OSDN Git Service

* gcc/config/pa/pa32-linux.h (MD_FALLBACK_FRAME_STATE_FOR): Define.
[pf3gnuchains/gcc-fork.git] / gcc / config / pa / pa32-linux.h
index 4943959..14cc2cf 100644 (file)
@@ -35,3 +35,97 @@ Boston, MA 02111-1307, USA.  */
     __attribute__ ((__unused__, section(".ctors"),                     \
                    aligned(sizeof(func_ptr))))                         \
     = { (func_ptr) (-1) }
+
+/* Do code reading to identify a signal frame, and set the frame
+   state data appropriately.  See unwind-dw2.c for the structs.  */
+
+#ifdef IN_LIBGCC2
+#include <signal.h>
+#include <sys/ucontext.h>
+
+/* Unfortunately, because of various bugs and changes to the kernel,
+   we have several cases to deal with.
+
+   In 2.4, the signal trampoline is 4 words, and (CONTEXT)->ra should
+   point directly at the beginning of the trampoline and struct rt_sigframe.
+
+   In <= 2.6.5-rc2-pa3, the signal trampoline is 9 words, and 
+   (CONTEXT)->ra points at the 4th word in the trampoline structure.  This 
+   is wrong, it should point at the 5th word.  This is fixed in 2.6.5-rc2-pa4.
+
+   To detect these cases, we first take (CONTEXT)->ra, align it to 64-bytes
+   to get the beginning of the signal frame, and then check offsets 0, 4
+   and 5 to see if we found the beginning of the trampoline.  This will
+   tell us how to locate the sigcontext structure.
+
+   Note that with a 2.4 64-bit kernel, the signal context is not properly
+   passed back to userspace so the unwind will not work correctly.  */
+#define MD_FALLBACK_FRAME_STATE_FOR(CONTEXT, FS, SUCCESS)              \
+  do {                                                                 \
+    unsigned long sp = (unsigned long)(CONTEXT)->ra & ~63;             \
+    unsigned int *pc = (unsigned int *)sp;                             \
+    unsigned long off;                                                 \
+    _Unwind_Ptr new_cfa;                                               \
+    int i;                                                             \
+    struct sigcontext *sc;                                             \
+    struct rt_sigframe {                                               \
+      struct siginfo info;                                             \
+      struct ucontext uc;                                              \
+    } *frame;                                                          \
+                                                                       \
+    /* rt_sigreturn trampoline:                                        \
+       3419000x ldi 0, %r25 or ldi 1, %r25   (x = 0 or 2)              \
+       3414015a ldi __NR_rt_sigreturn, %r20                            \
+       e4008200 be,l 0x100(%sr2, %r0), %sr0, %r31                      \
+       08000240 nop  */                                                        \
+                                                                       \
+    if (pc[0] == 0x34190000 || pc[0] == 0x34190002)                    \
+      off = 4*4;                                                       \
+    else if (pc[4] == 0x34190000 || pc[4] == 0x34190002)               \
+      {                                                                        \
+       pc += 4;                                                        \
+       off = 10 * 4;                                                   \
+      }                                                                        \
+    else if (pc[5] == 0x34190000 || pc[5] == 0x34190002)               \
+      {                                                                        \
+       pc += 5;                                                        \
+       off = 10 * 4;                                                   \
+      }                                                                        \
+    else                                                               \
+      break;                                                           \
+    if (pc[1] != 0x3414015a                                            \
+       || pc[2] != 0xe4008200                                          \
+       || pc[3] != 0x08000240)                                         \
+      break;                                                           \
+                                                                       \
+    frame = (struct rt_sigframe *)(sp + off);                          \
+    sc = &frame->uc.uc_mcontext;                                       \
+                                                                       \
+    new_cfa = sc->sc_gr[30];                                           \
+    (FS)->cfa_how = CFA_REG_OFFSET;                                    \
+    (FS)->cfa_reg = 30;                                                        \
+    (FS)->cfa_offset = new_cfa - (long) (CONTEXT)->cfa;                        \
+    for (i = 1; i <= 31; i++)                                          \
+      {                                                                        \
+       (FS)->regs.reg[i].how = REG_SAVED_OFFSET;                       \
+       (FS)->regs.reg[i].loc.offset = (long)&sc->sc_gr[i] - new_cfa;   \
+      }                                                                        \
+    for (i = 4; i <= 31; i++)                                          \
+      {                                                                        \
+       /* FP regs have left and right halves */                        \
+       (FS)->regs.reg[2*i+24].how = REG_SAVED_OFFSET;                  \
+       (FS)->regs.reg[2*i+24].loc.offset                               \
+         = (long)&sc->sc_fr[i] - new_cfa;                              \
+       (FS)->regs.reg[2*i+24+1].how = REG_SAVED_OFFSET;                \
+       (FS)->regs.reg[2*i+24+1].loc.offset                             \
+         = (long)&sc->sc_fr[i] + 4 - new_cfa;                          \
+      }                                                                        \
+    (FS)->regs.reg[88].how = REG_SAVED_OFFSET;                         \
+    (FS)->regs.reg[88].loc.offset = (long) &sc->sc_sar - new_cfa;      \
+    (FS)->regs.reg[2].how = REG_SAVED_OFFSET;                          \
+    (FS)->regs.reg[2].loc.offset = (long) &sc->sc_iaoq[0] - new_cfa;   \
+    (FS)->retaddr_column = 2;                                          \
+    goto SUCCESS;                                                      \
+  } while (0)
+
+#endif /* IN_LIBGCC2 */