OSDN Git Service

* include/ext/pool_allocator.h: Include c++config.h.
[pf3gnuchains/gcc-fork.git] / gcc / unwind-dw2.c
index 7596ef0..70d3221 100644 (file)
@@ -9,6 +9,15 @@
    the Free Software Foundation; either version 2, or (at your option)
    any later version.
 
    the Free Software Foundation; either version 2, or (at your option)
    any later version.
 
+   In addition to the permissions in the GNU General Public License, the
+   Free Software Foundation gives you unlimited permission to link the
+   compiled version of this file into combinations with other programs,
+   and to distribute those combinations without any restriction coming
+   from the use of this file.  (The General Public License restrictions
+   do apply in other respects; for example, they cover modification of
+   the file, and distribution when not linked into a combined
+   executable.)
+
    GCC is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
    GCC is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
@@ -25,6 +34,9 @@
 #include "tm.h"
 #include "dwarf2.h"
 #include "unwind.h"
 #include "tm.h"
 #include "dwarf2.h"
 #include "unwind.h"
+#ifdef __USING_SJLJ_EXCEPTIONS__
+# define NO_SIZE_OF_ENCODED_VALUE
+#endif
 #include "unwind-pe.h"
 #include "unwind-dw2-fde.h"
 #include "gthr.h"
 #include "unwind-pe.h"
 #include "unwind-dw2-fde.h"
 #include "gthr.h"
 #define DWARF_REG_TO_UNWIND_COLUMN(REGNO) (REGNO)
 #endif
 
 #define DWARF_REG_TO_UNWIND_COLUMN(REGNO) (REGNO)
 #endif
 
+/* A target can do some update context frobbing.  */
+#ifndef MD_FROB_UPDATE_CONTEXT
+#define MD_FROB_UPDATE_CONTEXT(CTX, FS) do { } while (0)
+#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.  */
 /* 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.  */
@@ -68,7 +85,7 @@ struct _Unwind_Context
 };
 
 /* Byte size of every register managed by these routines.  */
 };
 
 /* Byte size of every register managed by these routines.  */
-static unsigned char dwarf_reg_size_table[DWARF_FRAME_REGISTERS];
+static unsigned char dwarf_reg_size_table[DWARF_FRAME_REGISTERS+1];
 
 \f
 /* The result of interpreting the frame unwind info for a frame.
 
 \f
 /* The result of interpreting the frame unwind info for a frame.
@@ -90,7 +107,7 @@ typedef struct
        REG_UNSAVED,
        REG_SAVED_OFFSET,
        REG_SAVED_REG,
        REG_UNSAVED,
        REG_SAVED_OFFSET,
        REG_SAVED_REG,
-       REG_SAVED_EXP,
+       REG_SAVED_EXP
       } how;
     } reg[DWARF_FRAME_REGISTERS+1];
 
       } how;
     } reg[DWARF_FRAME_REGISTERS+1];
 
@@ -106,7 +123,7 @@ typedef struct
   enum {
     CFA_UNSET,
     CFA_REG_OFFSET,
   enum {
     CFA_UNSET,
     CFA_REG_OFFSET,
-    CFA_EXP,
+    CFA_EXP
   } cfa_how;
 
   /* The PC described by the current frame state.  */
   } cfa_how;
 
   /* The PC described by the current frame state.  */
@@ -168,9 +185,29 @@ read_8s (const void *p) { const union unaligned *up = p; return up->s8; }
 inline _Unwind_Word
 _Unwind_GetGR (struct _Unwind_Context *context, int index)
 {
 inline _Unwind_Word
 _Unwind_GetGR (struct _Unwind_Context *context, int index)
 {
+  int size;
+  void *ptr;
+
   index = DWARF_REG_TO_UNWIND_COLUMN (index);
   index = DWARF_REG_TO_UNWIND_COLUMN (index);
+  if (index >= (int) sizeof(dwarf_reg_size_table))
+    abort ();
+  size = dwarf_reg_size_table[index];
+  ptr = context->reg[index];
+
   /* This will segfault if the register hasn't been saved.  */
   /* This will segfault if the register hasn't been saved.  */
-  return * (_Unwind_Word *) context->reg[index];
+  if (size == sizeof(_Unwind_Ptr))
+    return * (_Unwind_Ptr *) ptr;
+
+  if (size == sizeof(_Unwind_Word))
+    return * (_Unwind_Word *) ptr;
+
+  abort ();
+}
+
+static inline void *
+_Unwind_GetPtr (struct _Unwind_Context *context, int index)
+{
+  return (void *)(_Unwind_Ptr) _Unwind_GetGR (context, index);
 }
 
 /* Get the value of the CFA as saved in CONTEXT.  */
 }
 
 /* Get the value of the CFA as saved in CONTEXT.  */
@@ -178,7 +215,7 @@ _Unwind_GetGR (struct _Unwind_Context *context, int index)
 _Unwind_Word
 _Unwind_GetCFA (struct _Unwind_Context *context)
 {
 _Unwind_Word
 _Unwind_GetCFA (struct _Unwind_Context *context)
 {
-  return (_Unwind_Word)context->cfa;
+  return (_Unwind_Ptr) context->cfa;
 }
 
 /* Overwrite the saved value for register REG in CONTEXT with VAL.  */
 }
 
 /* Overwrite the saved value for register REG in CONTEXT with VAL.  */
@@ -186,8 +223,21 @@ _Unwind_GetCFA (struct _Unwind_Context *context)
 inline void
 _Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val)
 {
 inline void
 _Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val)
 {
+  int size;
+  void *ptr;
+
   index = DWARF_REG_TO_UNWIND_COLUMN (index);
   index = DWARF_REG_TO_UNWIND_COLUMN (index);
-  * (_Unwind_Word *) context->reg[index] = val;
+  if (index >= (int) sizeof(dwarf_reg_size_table))
+    abort ();
+  size = dwarf_reg_size_table[index];
+  ptr = context->reg[index];
+
+  if (size == sizeof(_Unwind_Ptr))
+    * (_Unwind_Ptr *) ptr = val;
+  else if (size == sizeof(_Unwind_Word))
+    * (_Unwind_Word *) ptr = val;
+  else
+    abort ();
 }
 
 /* Get the pointer to a register INDEX as saved in CONTEXT.  */
 }
 
 /* Get the pointer to a register INDEX as saved in CONTEXT.  */
@@ -240,7 +290,7 @@ void *
 _Unwind_FindEnclosingFunction (void *pc)
 {
   struct dwarf_eh_bases bases;
 _Unwind_FindEnclosingFunction (void *pc)
 {
   struct dwarf_eh_bases bases;
-  struct dwarf_fde *fde = _Unwind_Find_FDE (pc-1, &bases);
+  const struct dwarf_fde *fde = _Unwind_Find_FDE (pc-1, &bases);
   if (fde)
     return bases.func;
   else
   if (fde)
     return bases.func;
   else
@@ -266,7 +316,7 @@ _Unwind_GetTextRelBase (struct _Unwind_Context *context)
    or NULL if we encountered an undecipherable augmentation.  */
 
 static const unsigned char *
    or NULL if we encountered an undecipherable augmentation.  */
 
 static const unsigned char *
-extract_cie_info (struct dwarf_cie *cie, struct _Unwind_Context *context,
+extract_cie_info (const struct dwarf_cie *cie, struct _Unwind_Context *context,
                  _Unwind_FrameState *fs)
 {
   const unsigned char *aug = cie->augmentation;
                  _Unwind_FrameState *fs)
 {
   const unsigned char *aug = cie->augmentation;
@@ -951,14 +1001,17 @@ execute_cfa_program (const unsigned char *insn_ptr,
 static _Unwind_Reason_Code
 uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
 {
 static _Unwind_Reason_Code
 uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
 {
-  struct dwarf_fde *fde;
-  struct dwarf_cie *cie;
+  const struct dwarf_fde *fde;
+  const struct dwarf_cie *cie;
   const unsigned char *aug, *insn, *end;
 
   memset (fs, 0, sizeof (*fs));
   context->args_size = 0;
   context->lsda = 0;
 
   const unsigned char *aug, *insn, *end;
 
   memset (fs, 0, sizeof (*fs));
   context->args_size = 0;
   context->lsda = 0;
 
+  if (context->ra == 0)
+    return _URC_END_OF_STACK;
+
   fde = _Unwind_Find_FDE (context->ra - 1, &context->bases);
   if (fde == NULL)
     {
   fde = _Unwind_Find_FDE (context->ra - 1, &context->bases);
   if (fde == NULL)
     {
@@ -1072,14 +1125,31 @@ __frame_state_for (void *pc_target, struct frame_state *state_in)
   return state_in;
 }
 \f
   return state_in;
 }
 \f
+typedef union { _Unwind_Ptr ptr; _Unwind_Word word; } _Unwind_SpTmp;
+
+static inline void
+_Unwind_SetSpColumn (struct _Unwind_Context *context, void *cfa,
+                     _Unwind_SpTmp *tmp_sp)
+{
+  int size = dwarf_reg_size_table[__builtin_dwarf_sp_column ()];
+  
+  if (size == sizeof(_Unwind_Ptr))
+    tmp_sp->ptr = (_Unwind_Ptr) cfa;
+  else if (size == sizeof(_Unwind_Word))
+    tmp_sp->word = (_Unwind_Ptr) cfa;
+  else
+    abort ();
+  _Unwind_SetGRPtr (context, __builtin_dwarf_sp_column (), tmp_sp);
+}
+
 static void
 uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
 {
   struct _Unwind_Context orig_context = *context;
 static void
 uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
 {
   struct _Unwind_Context orig_context = *context;
-  _Unwind_Word tmp_sp;
   void *cfa;
   long i;
 
   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
   /* 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
@@ -1089,17 +1159,24 @@ uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
      In very special situations (such as unwind info for signal return),
      there may be location expressions that use the stack pointer as well.
 
      In very special situations (such as unwind info for signal return),
      there may be location expressions that use the stack pointer as well.
 
-     Given that other unwind mechanisms generally won't work if you try
-     to represent stack pointer saves and restores directly, we don't
-     bother conditionalizing this at all.  */
-  tmp_sp = (_Unwind_Ptr) context->cfa;
-  _Unwind_SetGRPtr (&orig_context, __builtin_dwarf_sp_column (), &tmp_sp);
+     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_SpTmp tmp_sp;
+
+  if (!_Unwind_GetGRPtr (&orig_context, __builtin_dwarf_sp_column ()))
+    _Unwind_SetSpColumn (&orig_context, context->cfa, &tmp_sp);
+  _Unwind_SetGRPtr (context, __builtin_dwarf_sp_column (), NULL);
+#endif
 
   /* Compute this frame's CFA.  */
   switch (fs->cfa_how)
     {
     case CFA_REG_OFFSET:
 
   /* Compute this frame's CFA.  */
   switch (fs->cfa_how)
     {
     case CFA_REG_OFFSET:
-      cfa = (void *) (_Unwind_Ptr) _Unwind_GetGR (&orig_context, fs->cfa_reg);
+      cfa = _Unwind_GetPtr (&orig_context, fs->cfa_reg);
       cfa += fs->cfa_offset;
       break;
 
       cfa += fs->cfa_offset;
       break;
 
@@ -1150,6 +1227,8 @@ uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
        }
        break;
       }
        }
        break;
       }
+
+  MD_FROB_UPDATE_CONTEXT (context, fs);
 }
 
 /* CONTEXT describes the unwind state for a frame, and FS describes the FDE
 }
 
 /* CONTEXT describes the unwind state for a frame, and FS describes the FDE
@@ -1165,7 +1244,7 @@ uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
   /* Compute the return address now, since the return address column
      can change from frame to frame.  */
   context->ra = __builtin_extract_return_addr
   /* Compute the return address now, since the return address column
      can change from frame to frame.  */
   context->ra = __builtin_extract_return_addr
-    ((void *) (_Unwind_Ptr) _Unwind_GetGR (context, fs->retaddr_column));
+    (_Unwind_GetPtr (context, fs->retaddr_column));
 }
 \f
 /* Fill in CONTEXT for top-of-stack.  The only valid registers at this
 }
 \f
 /* Fill in CONTEXT for top-of-stack.  The only valid registers at this
@@ -1182,12 +1261,19 @@ uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
     }                                                                     \
   while (0)
 
     }                                                                     \
   while (0)
 
+static inline void
+init_dwarf_reg_size_table (void)
+{
+  __builtin_init_dwarf_reg_size_table (dwarf_reg_size_table);
+}
+
 static void
 uw_init_context_1 (struct _Unwind_Context *context,
                   void *outer_cfa, void *outer_ra)
 {
   void *ra = __builtin_extract_return_addr (__builtin_return_address (0));
   _Unwind_FrameState fs;
 static void
 uw_init_context_1 (struct _Unwind_Context *context,
                   void *outer_cfa, void *outer_ra)
 {
   void *ra = __builtin_extract_return_addr (__builtin_return_address (0));
   _Unwind_FrameState fs;
+  _Unwind_SpTmp sp_slot;
 
   memset (context, 0, sizeof (struct _Unwind_Context));
   context->ra = ra;
 
   memset (context, 0, sizeof (struct _Unwind_Context));
   context->ra = ra;
@@ -1195,8 +1281,20 @@ uw_init_context_1 (struct _Unwind_Context *context,
   if (uw_frame_state_for (context, &fs) != _URC_NO_REASON)
     abort ();
 
   if (uw_frame_state_for (context, &fs) != _URC_NO_REASON)
     abort ();
 
+#if __GTHREADS
+  {
+    static __gthread_once_t once_regsizes = __GTHREAD_ONCE_INIT;
+    if (__gthread_once (&once_regsizes, init_dwarf_reg_size_table) != 0
+       || dwarf_reg_size_table[0] == 0)
+      init_dwarf_reg_size_table ();
+  }
+#else
+  if (dwarf_reg_size_table[0] == 0)
+    init_dwarf_reg_size_table ();
+#endif
+
   /* Force the frame state to use the known cfa value.  */
   /* Force the frame state to use the known cfa value.  */
-  context->cfa = outer_cfa;
+  _Unwind_SetSpColumn (context, outer_cfa, &sp_slot);
   fs.cfa_how = CFA_REG_OFFSET;
   fs.cfa_reg = __builtin_dwarf_sp_column ();
   fs.cfa_offset = 0;
   fs.cfa_how = CFA_REG_OFFSET;
   fs.cfa_reg = __builtin_dwarf_sp_column ();
   fs.cfa_offset = 0;
@@ -1223,30 +1321,12 @@ uw_init_context_1 (struct _Unwind_Context *context,
     }                                                                   \
   while (0)
 
     }                                                                   \
   while (0)
 
-static inline void
-init_dwarf_reg_size_table (void)
-{
-  __builtin_init_dwarf_reg_size_table (dwarf_reg_size_table);
-}
-
 static long
 uw_install_context_1 (struct _Unwind_Context *current,
                      struct _Unwind_Context *target)
 {
   long i;
 
 static long
 uw_install_context_1 (struct _Unwind_Context *current,
                      struct _Unwind_Context *target)
 {
   long i;
 
-#if __GTHREADS
-  {
-    static __gthread_once_t once_regsizes = __GTHREAD_ONCE_INIT;
-    if (__gthread_once (&once_regsizes, init_dwarf_reg_size_table) != 0
-       || dwarf_reg_size_table[0] == 0)
-      init_dwarf_reg_size_table ();
-  }
-#else
-  if (dwarf_reg_size_table[0] == 0)
-    init_dwarf_reg_size_table ();
-#endif
-
   for (i = 0; i < DWARF_FRAME_REGISTERS; ++i)
     {
       void *c = current->reg[i];
   for (i = 0; i < DWARF_FRAME_REGISTERS; ++i)
     {
       void *c = current->reg[i];
@@ -1256,11 +1336,25 @@ uw_install_context_1 (struct _Unwind_Context *current,
        memcpy (c, t, dwarf_reg_size_table[i]);
     }
 
        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 = _Unwind_GetPtr (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
 }
 
 static inline _Unwind_Ptr