OSDN Git Service

* config/rs6000/spe.md (SPE_ACC_REGNO): Delete definition.
[pf3gnuchains/gcc-fork.git] / gcc / config / rs6000 / linux-unwind.h
index 71bebd2..18b0faa 100644 (file)
@@ -1,5 +1,5 @@
 /* DWARF2 EH unwinding support for PowerPC and PowerPC64 Linux.
-   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
    these structs elsewhere;  Many fields are missing, particularly
    from the end of the structures.  */
 
+#define R_LR           65
+#define R_CR2          70
+#define R_VR0          77
+#define R_VRSAVE       109
+#define R_VSCR         110
+
 struct gcc_vregs
 {
   __attribute__ ((vector_size (16))) int vr[32];
@@ -89,26 +95,6 @@ struct gcc_ucontext
 
 enum { SIGNAL_FRAMESIZE = 128 };
 
-/* If the current unwind info (FS) does not contain explicit info
-   saving R2, then we have to do a minor amount of code reading to
-   figure out if it was saved.  The big problem here is that the
-   code that does the save/restore is generated by the linker, so
-   we have no good way to determine at compile time what to do.  */
-
-#define MD_FROB_UPDATE_CONTEXT frob_update_context
-
-static void
-frob_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
-{
-  if (fs->regs.reg[2].how == REG_UNSAVED)
-    {
-      unsigned int *insn
-       = (unsigned int *) _Unwind_GetGR (context, LINK_REGISTER_REGNUM);
-      if (*insn == 0xE8410028)
-       _Unwind_SetGRPtr (context, 2, context->cfa + 40);
-    }
-}
-
 /* If PC is at a sigreturn trampoline, return a pointer to the
    regs.  Otherwise return NULL.  */
 
@@ -252,9 +238,9 @@ ppc_fallback_frame_state (struct _Unwind_Context *context,
     return _URC_END_OF_STACK;
 
   new_cfa = regs->gpr[STACK_POINTER_REGNUM];
-  fs->cfa_how = CFA_REG_OFFSET;
-  fs->cfa_reg = STACK_POINTER_REGNUM;
-  fs->cfa_offset = new_cfa - (long) context->cfa;
+  fs->regs.cfa_how = CFA_REG_OFFSET;
+  fs->regs.cfa_reg = STACK_POINTER_REGNUM;
+  fs->regs.cfa_offset = new_cfa - (long) context->cfa;
 
   for (i = 0; i < 32; i++)
     if (i != STACK_POINTER_REGNUM)
@@ -263,20 +249,21 @@ ppc_fallback_frame_state (struct _Unwind_Context *context,
        fs->regs.reg[i].loc.offset = (long) &regs->gpr[i] - new_cfa;
       }
 
-  fs->regs.reg[CR2_REGNO].how = REG_SAVED_OFFSET;
-  fs->regs.reg[CR2_REGNO].loc.offset = (long) &regs->ccr - new_cfa;
+  fs->regs.reg[R_CR2].how = REG_SAVED_OFFSET;
+  fs->regs.reg[R_CR2].loc.offset = (long) &regs->ccr - new_cfa;
 
-  fs->regs.reg[LINK_REGISTER_REGNUM].how = REG_SAVED_OFFSET;
-  fs->regs.reg[LINK_REGISTER_REGNUM].loc.offset = (long) &regs->link - new_cfa;
+  fs->regs.reg[R_LR].how = REG_SAVED_OFFSET;
+  fs->regs.reg[R_LR].loc.offset = (long) &regs->link - new_cfa;
 
   fs->regs.reg[ARG_POINTER_REGNUM].how = REG_SAVED_OFFSET;
   fs->regs.reg[ARG_POINTER_REGNUM].loc.offset = (long) &regs->nip - new_cfa;
   fs->retaddr_column = ARG_POINTER_REGNUM;
+  fs->signal_frame = 1;
 
   if (hwcap == 0)
     {
       hwcap = ppc_linux_aux_vector (16);
-      /* These will already be set if we found AT_HWCAP.  A non-zero
+      /* These will already be set if we found AT_HWCAP.  A nonzero
         value stops us looking again if for some reason we couldn't
         find AT_HWCAP.  */
 #ifdef __powerpc64__
@@ -307,18 +294,72 @@ ppc_fallback_frame_state (struct _Unwind_Context *context,
        {
          for (i = 0; i < 32; i++)
            {
-             fs->regs.reg[i + FIRST_ALTIVEC_REGNO].how = REG_SAVED_OFFSET;
-             fs->regs.reg[i + FIRST_ALTIVEC_REGNO].loc.offset
+             fs->regs.reg[i + R_VR0].how = REG_SAVED_OFFSET;
+             fs->regs.reg[i + R_VR0].loc.offset
                = (long) &vregs[i] - new_cfa;
            }
 
-         fs->regs.reg[VSCR_REGNO].how = REG_SAVED_OFFSET;
-         fs->regs.reg[VSCR_REGNO].loc.offset = (long) &vregs->vscr - new_cfa;
+         fs->regs.reg[R_VSCR].how = REG_SAVED_OFFSET;
+         fs->regs.reg[R_VSCR].loc.offset = (long) &vregs->vscr - new_cfa;
        }
 
-      fs->regs.reg[VRSAVE_REGNO].how = REG_SAVED_OFFSET;
-      fs->regs.reg[VRSAVE_REGNO].loc.offset = (long) &vregs->vsave - new_cfa;
+      fs->regs.reg[R_VRSAVE].how = REG_SAVED_OFFSET;
+      fs->regs.reg[R_VRSAVE].loc.offset = (long) &vregs->vsave - new_cfa;
     }
 
+  /* If we have SPE register high-parts... we check at compile-time to
+     avoid expanding the code for all other PowerPC.  */
+#ifdef __SPE__
+  for (i = 0; i < 32; i++)
+    {
+      fs->regs.reg[i + FIRST_PSEUDO_REGISTER - 1].how = REG_SAVED_OFFSET;
+      fs->regs.reg[i + FIRST_PSEUDO_REGISTER - 1].loc.offset
+       = (long) &regs->vregs - new_cfa + 4 * i;
+    }
+#endif
+
   return _URC_NO_REASON;
 }
+
+#define MD_FROB_UPDATE_CONTEXT frob_update_context
+
+static void
+frob_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs ATTRIBUTE_UNUSED)
+{
+  const unsigned int *pc = (const unsigned int *) context->ra;
+
+  /* Fix up for 2.6.12 - 2.6.16 Linux kernels that have vDSO, but don't
+     have S flag in it.  */
+#ifdef __powerpc64__
+  /* addi r1, r1, 128; li r0, 0x0077; sc  (sigreturn) */
+  /* addi r1, r1, 128; li r0, 0x00AC; sc  (rt_sigreturn) */
+  if (pc[0] == 0x38210000 + SIGNAL_FRAMESIZE
+      && (pc[1] == 0x38000077 || pc[1] == 0x380000AC)
+      && pc[2] == 0x44000002)
+    _Unwind_SetSignalFrame (context, 1);
+#else
+  /* li r0, 0x7777; sc  (sigreturn old)  */
+  /* li r0, 0x0077; sc  (sigreturn new)  */
+  /* li r0, 0x6666; sc  (rt_sigreturn old)  */
+  /* li r0, 0x00AC; sc  (rt_sigreturn new)  */
+  if ((pc[0] == 0x38007777 || pc[0] == 0x38000077
+       || pc[0] == 0x38006666 || pc[0] == 0x380000AC)
+      && pc[1] == 0x44000002)
+    _Unwind_SetSignalFrame (context, 1);
+#endif
+
+#ifdef __powerpc64__
+  if (fs->regs.reg[2].how == REG_UNSAVED)
+    {
+      /* If the current unwind info (FS) does not contain explicit info
+        saving R2, then we have to do a minor amount of code reading to
+        figure out if it was saved.  The big problem here is that the
+        code that does the save/restore is generated by the linker, so
+        we have no good way to determine at compile time what to do.  */
+      unsigned int *insn
+       = (unsigned int *) _Unwind_GetGR (context, R_LR);
+      if (*insn == 0xE8410028)
+       _Unwind_SetGRPtr (context, 2, context->cfa + 40);
+    }
+#endif
+}