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.
REG_UNSAVED,
REG_SAVED_OFFSET,
REG_SAVED_REG,
- REG_SAVED_EXP,
+ REG_SAVED_EXP
} how;
} reg[DWARF_FRAME_REGISTERS+1];
enum {
CFA_UNSET,
CFA_REG_OFFSET,
- CFA_EXP,
+ CFA_EXP
} cfa_how;
/* The PC described by the current frame state. */
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. */
_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. */
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. */
_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
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;
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;
+ 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
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:
- 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;
-#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];
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