OSDN Git Service

2003-06-10 Andrew Haley <aph@redhat.com>
[pf3gnuchains/gcc-fork.git] / gcc / unwind-dw2.c
index 3c5feea..e61664b 100644 (file)
@@ -1,5 +1,5 @@
 /* DWARF2 exception handling and frame unwind runtime interface routines.
-   Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002
+   Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003
    Free Software Foundation, Inc.
 
    This file is part of GCC.
@@ -21,6 +21,8 @@
 
 #include "tconfig.h"
 #include "tsystem.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "dwarf2.h"
 #include "unwind.h"
 #include "unwind-pe.h"
 #define PRE_GCC3_DWARF_FRAME_REGISTERS DWARF_FRAME_REGISTERS
 #endif
 
+#ifndef DWARF_REG_TO_UNWIND_COLUMN
+#define DWARF_REG_TO_UNWIND_COLUMN(REGNO) (REGNO)
+#endif
+
 /* This is the register and unwind state for a particular frame.  This
    provides the information necessary to unwind up past a frame and return
    to its caller.  */
@@ -162,18 +168,46 @@ read_8s (const void *p) { const union unaligned *up = p; return up->s8; }
 inline _Unwind_Word
 _Unwind_GetGR (struct _Unwind_Context *context, int index)
 {
+  index = DWARF_REG_TO_UNWIND_COLUMN (index);
   /* This will segfault if the register hasn't been saved.  */
   return * (_Unwind_Word *) context->reg[index];
 }
 
+/* Get the value of the CFA as saved in CONTEXT.  */
+
+_Unwind_Word
+_Unwind_GetCFA (struct _Unwind_Context *context)
+{
+  return (_Unwind_Ptr) context->cfa;
+}
+
 /* Overwrite the saved value for register REG in CONTEXT with VAL.  */
 
 inline void
 _Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val)
 {
+  index = DWARF_REG_TO_UNWIND_COLUMN (index);
   * (_Unwind_Word *) context->reg[index] = val;
 }
 
+/* Get the pointer to a register INDEX as saved in CONTEXT.  */
+
+static inline void *
+_Unwind_GetGRPtr (struct _Unwind_Context *context, int index)
+{
+  index = DWARF_REG_TO_UNWIND_COLUMN (index);
+  return context->reg[index];
+}
+
+/* Set the pointer to a register INDEX as saved in CONTEXT.  */
+
+static inline void
+_Unwind_SetGRPtr (struct _Unwind_Context *context, int index, void *p)
+{
+  index = DWARF_REG_TO_UNWIND_COLUMN (index);
+  context->reg[index] = p;
+}
+
 /* Retrieve the return address for CONTEXT.  */
 
 inline _Unwind_Ptr
@@ -692,7 +726,7 @@ execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end,
       /* Most things push a result value.  */
       if ((size_t) stack_elt >= sizeof(stack)/sizeof(*stack))
        abort ();
-      stack[++stack_elt] = result;
+      stack[stack_elt++] = result;
     no_push:;
     }
 
@@ -739,13 +773,14 @@ execute_cfa_program (const unsigned char *insn_ptr,
          reg = insn & 0x3f;
          insn_ptr = read_uleb128 (insn_ptr, &utmp);
          offset = (_Unwind_Sword) utmp * fs->data_align;
-         fs->regs.reg[reg].how = REG_SAVED_OFFSET;
-         fs->regs.reg[reg].loc.offset = offset;
+         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
+           = REG_SAVED_OFFSET;
+         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset;
        }
       else if ((insn & 0xc0) == DW_CFA_restore)
        {
          reg = insn & 0x3f;
-         fs->regs.reg[reg].how = REG_UNSAVED;
+         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how = REG_UNSAVED;
        }
       else switch (insn)
        {
@@ -771,17 +806,21 @@ execute_cfa_program (const unsigned char *insn_ptr,
          insn_ptr = read_uleb128 (insn_ptr, &reg);
          insn_ptr = read_uleb128 (insn_ptr, &utmp);
          offset = (_Unwind_Sword) utmp * fs->data_align;
-         fs->regs.reg[reg].how = REG_SAVED_OFFSET;
-         fs->regs.reg[reg].loc.offset = offset;
+         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
+           = REG_SAVED_OFFSET;
+         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset;
          break;
 
        case DW_CFA_restore_extended:
          insn_ptr = read_uleb128 (insn_ptr, &reg);
-         fs->regs.reg[reg].how = REG_UNSAVED;
+         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN(reg)].how = REG_UNSAVED;
          break;
 
        case DW_CFA_undefined:
        case DW_CFA_same_value:
+         insn_ptr = read_uleb128 (insn_ptr, &reg);
+         break;
+
        case DW_CFA_nop:
          break;
 
@@ -790,8 +829,8 @@ execute_cfa_program (const unsigned char *insn_ptr,
            _Unwind_Word reg2;
            insn_ptr = read_uleb128 (insn_ptr, &reg);
            insn_ptr = read_uleb128 (insn_ptr, &reg2);
-           fs->regs.reg[reg].how = REG_SAVED_REG;
-           fs->regs.reg[reg].loc.reg = reg2;
+           fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how = REG_SAVED_REG;
+           fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.reg = reg2;
          }
          break;
 
@@ -839,17 +878,17 @@ execute_cfa_program (const unsigned char *insn_ptr,
          break;
 
        case DW_CFA_def_cfa_expression:
-         insn_ptr = read_uleb128 (insn_ptr, &utmp);
          fs->cfa_exp = insn_ptr;
          fs->cfa_how = CFA_EXP;
+         insn_ptr = read_uleb128 (insn_ptr, &utmp);
          insn_ptr += utmp;
          break;
 
        case DW_CFA_expression:
          insn_ptr = read_uleb128 (insn_ptr, &reg);
+         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how = REG_SAVED_EXP;
+         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.exp = insn_ptr;
          insn_ptr = read_uleb128 (insn_ptr, &utmp);
-         fs->regs.reg[reg].how = REG_SAVED_EXP;
-         fs->regs.reg[reg].loc.exp = insn_ptr;
          insn_ptr += utmp;
          break;
 
@@ -858,8 +897,9 @@ execute_cfa_program (const unsigned char *insn_ptr,
          insn_ptr = read_uleb128 (insn_ptr, &reg);
          insn_ptr = read_sleb128 (insn_ptr, &stmp);
          offset = stmp * fs->data_align;
-         fs->regs.reg[reg].how = REG_SAVED_OFFSET;
-         fs->regs.reg[reg].loc.offset = offset;
+         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
+           = REG_SAVED_OFFSET;
+         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset;
          break;
 
        case DW_CFA_def_cfa_sf:
@@ -892,8 +932,9 @@ execute_cfa_program (const unsigned char *insn_ptr,
          insn_ptr = read_uleb128 (insn_ptr, &reg);
          insn_ptr = read_uleb128 (insn_ptr, &utmp);
          offset = (_Unwind_Word) utmp * fs->data_align;
-         fs->regs.reg[reg].how = REG_SAVED_OFFSET;
-         fs->regs.reg[reg].loc.offset = -offset;
+         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
+           = REG_SAVED_OFFSET;
+         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = -offset;
          break;
 
        default:
@@ -1038,34 +1079,48 @@ uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
   void *cfa;
   long i;
 
+#ifdef EH_RETURN_STACKADJ_RTX
+  /* Special handling here: Many machines do not use a frame pointer,
+     and track the CFA only through offsets from the stack pointer from
+     one frame to the next.  In this case, the stack pointer is never
+     stored, so it has no saved address in the context.  What we do
+     have is the CFA from the previous stack frame.
+
+     In very special situations (such as unwind info for signal return),
+     there may be location expressions that use the stack pointer as well.
+
+     Do this conditionally for one frame.  This allows the unwind info
+     for one frame to save a copy of the stack pointer from the previous
+     frame, and be able to use much easier CFA mechanisms to do it.
+     Always zap the saved stack pointer value for the next frame; carrying
+     the value over from one frame to another doesn't make sense.  */
+
+  _Unwind_Word tmp_sp;
+
+  if (!_Unwind_GetGRPtr (&orig_context, __builtin_dwarf_sp_column ()))
+    {
+      tmp_sp = (_Unwind_Ptr) context->cfa;
+      _Unwind_SetGRPtr (&orig_context, __builtin_dwarf_sp_column (), &tmp_sp);
+    }
+  _Unwind_SetGRPtr (context, __builtin_dwarf_sp_column (), NULL);
+#endif
+
   /* Compute this frame's CFA.  */
   switch (fs->cfa_how)
     {
     case CFA_REG_OFFSET:
-      /* Special handling here: Many machines do not use a frame pointer,
-        and track the CFA only through offsets from the stack pointer from
-        one frame to the next.  In this case, the stack pointer is never
-        stored, so it has no saved address in the context.  What we do
-        have is the CFA from the previous stack frame.  */
-      if (context->reg[fs->cfa_reg] == NULL)
-       cfa = context->cfa;
-      else
-       cfa = (void *) (_Unwind_Ptr) _Unwind_GetGR (context, fs->cfa_reg);
+      cfa = (void *) (_Unwind_Ptr) _Unwind_GetGR (&orig_context, fs->cfa_reg);
       cfa += fs->cfa_offset;
       break;
 
     case CFA_EXP:
-      /* ??? No way of knowing what register number is the stack pointer
-        to do the same sort of handling as above.  Assume that if the
-        CFA calculation is so complicated as to require a stack program
-        that this will not be a problem.  */
       {
        const unsigned char *exp = fs->cfa_exp;
        _Unwind_Word len;
 
        exp = read_uleb128 (exp, &len);
        cfa = (void *) (_Unwind_Ptr)
-         execute_stack_op (exp, exp + len, context, 0);
+         execute_stack_op (exp, exp + len, &orig_context, 0);
        break;
       }
 
@@ -1080,12 +1135,18 @@ uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
       {
       case REG_UNSAVED:
        break;
+
       case REG_SAVED_OFFSET:
-       context->reg[i] = cfa + fs->regs.reg[i].loc.offset;
+       _Unwind_SetGRPtr (context, i,
+                         (void *) (cfa + fs->regs.reg[i].loc.offset));
        break;
+
       case REG_SAVED_REG:
-       context->reg[i] = orig_context.reg[fs->regs.reg[i].loc.reg];
+       _Unwind_SetGRPtr
+         (context, i,
+          _Unwind_GetGRPtr (&orig_context, fs->regs.reg[i].loc.reg));
        break;
+
       case REG_SAVED_EXP:
        {
          const unsigned char *exp = fs->regs.reg[i].loc.exp;
@@ -1095,7 +1156,7 @@ uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
          exp = read_uleb128 (exp, &len);
          val = execute_stack_op (exp, exp + len, &orig_context,
                                  (_Unwind_Ptr) cfa);
-         context->reg[i] = (void *) val;
+         _Unwind_SetGRPtr (context, i, (void *) val);
        }
        break;
       }
@@ -1137,6 +1198,7 @@ uw_init_context_1 (struct _Unwind_Context *context,
 {
   void *ra = __builtin_extract_return_addr (__builtin_return_address (0));
   _Unwind_FrameState fs;
+  _Unwind_Word sp_slot;
 
   memset (context, 0, sizeof (struct _Unwind_Context));
   context->ra = ra;
@@ -1145,9 +1207,10 @@ uw_init_context_1 (struct _Unwind_Context *context,
     abort ();
 
   /* Force the frame state to use the known cfa value.  */
-  context->cfa = outer_cfa;
+  sp_slot = (_Unwind_Ptr) outer_cfa;
+  _Unwind_SetGRPtr (context, __builtin_dwarf_sp_column (), &sp_slot);
   fs.cfa_how = CFA_REG_OFFSET;
-  fs.cfa_reg = 0;
+  fs.cfa_reg = __builtin_dwarf_sp_column ();
   fs.cfa_offset = 0;
 
   uw_update_context_1 (context, &fs);
@@ -1200,15 +1263,31 @@ uw_install_context_1 (struct _Unwind_Context *current,
     {
       void *c = current->reg[i];
       void *t = target->reg[i];
+
       if (t && c && t != c)
        memcpy (c, t, dwarf_reg_size_table[i]);
     }
 
-  /* We adjust SP by the difference between CURRENT and TARGET's CFA.  */
-  if (STACK_GROWS_DOWNWARD)
-    return target->cfa - current->cfa + target->args_size;
-  else
-    return current->cfa - target->cfa - target->args_size;
+#ifdef EH_RETURN_STACKADJ_RTX
+  {
+    void *target_cfa;
+
+    /* If the last frame records a saved stack pointer, use it.  */
+    if (_Unwind_GetGRPtr (target, __builtin_dwarf_sp_column ()))
+      target_cfa = (void *)(_Unwind_Ptr)
+        _Unwind_GetGR (target, __builtin_dwarf_sp_column ());
+    else
+      target_cfa = target->cfa;
+
+    /* We adjust SP by the difference between CURRENT and TARGET's CFA.  */
+    if (STACK_GROWS_DOWNWARD)
+      return target_cfa - current->cfa + target->args_size;
+    else
+      return current->cfa - target_cfa - target->args_size;
+  }
+#else
+  return 0;
+#endif
 }
 
 static inline _Unwind_Ptr