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
#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"
#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. */
};
/* 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.
inline _Unwind_Word
_Unwind_GetGR (struct _Unwind_Context *context, int index)
{
+ int size;
+ void *ptr;
+
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. */
- 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. */
inline void
_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val)
{
+ int size;
+ void *ptr;
+
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. */
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)
{
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;
- _Unwind_Word tmp_sp;
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
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 ()))
- {
- tmp_sp = (_Unwind_Ptr) context->cfa;
- _Unwind_SetGRPtr (&orig_context, __builtin_dwarf_sp_column (), &tmp_sp);
- }
+ _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:
- cfa = (void *) (_Unwind_Ptr) _Unwind_GetGR (&orig_context, fs->cfa_reg);
+ cfa = _Unwind_GetPtr (&orig_context, fs->cfa_reg);
cfa += fs->cfa_offset;
break;
}
break;
}
+
+ MD_FROB_UPDATE_CONTEXT (context, fs);
}
/* CONTEXT describes the unwind state for a frame, and FS describes the FDE
/* 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
} \
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;
+ _Unwind_SpTmp sp_slot;
memset (context, 0, sizeof (struct _Unwind_Context));
context->ra = ra;
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. */
- 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;
} \
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;
- void *target_cfa;
-
-#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)
{
memcpy (c, t, dwarf_reg_size_table[i]);
}
- /* 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;
+#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