summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/unwind-dw2.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/gcc/unwind-dw2.c')
-rw-r--r--contrib/gcc/unwind-dw2.c216
1 files changed, 157 insertions, 59 deletions
diff --git a/contrib/gcc/unwind-dw2.c b/contrib/gcc/unwind-dw2.c
index 0e59c7b..70d3221 100644
--- a/contrib/gcc/unwind-dw2.c
+++ b/contrib/gcc/unwind-dw2.c
@@ -9,6 +9,15 @@
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
@@ -21,8 +30,13 @@
#include "tconfig.h"
#include "tsystem.h"
+#include "coretypes.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"
@@ -48,6 +62,15 @@
#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
+
+/* 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. */
@@ -84,7 +107,7 @@ typedef struct
REG_UNSAVED,
REG_SAVED_OFFSET,
REG_SAVED_REG,
- REG_SAVED_EXP,
+ REG_SAVED_EXP
} how;
} reg[DWARF_FRAME_REGISTERS+1];
@@ -100,7 +123,7 @@ typedef struct
enum {
CFA_UNSET,
CFA_REG_OFFSET,
- CFA_EXP,
+ CFA_EXP
} cfa_how;
/* The PC described by the current frame state. */
@@ -162,8 +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)
{
+ 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. */
@@ -171,7 +215,7 @@ _Unwind_GetGR (struct _Unwind_Context *context, int index)
_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. */
@@ -179,7 +223,39 @@ _Unwind_GetCFA (struct _Unwind_Context *context)
inline void
_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val)
{
- * (_Unwind_Word *) context->reg[index] = val;
+ 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];
+
+ 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. */
+
+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. */
@@ -214,7 +290,7 @@ void *
_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
@@ -240,7 +316,7 @@ _Unwind_GetTextRelBase (struct _Unwind_Context *context)
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;
@@ -747,13 +823,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)
{
@@ -779,13 +856,14 @@ 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:
@@ -801,8 +879,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;
@@ -858,8 +936,8 @@ execute_cfa_program (const unsigned char *insn_ptr,
case DW_CFA_expression:
insn_ptr = read_uleb128 (insn_ptr, &reg);
- fs->regs.reg[reg].how = REG_SAVED_EXP;
- fs->regs.reg[reg].loc.exp = insn_ptr;
+ 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);
insn_ptr += utmp;
break;
@@ -869,8 +947,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:
@@ -903,8 +982,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:
@@ -921,8 +1001,8 @@ execute_cfa_program (const unsigned char *insn_ptr,
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));
@@ -1045,6 +1125,23 @@ __frame_state_for (void *pc_target, struct frame_state *state_in)
return state_in;
}
+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)
{
@@ -1068,21 +1165,18 @@ uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
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;
+ _Unwind_SpTmp tmp_sp;
- if (!orig_context.reg[__builtin_dwarf_sp_column ()])
- {
- tmp_sp = (_Unwind_Ptr) context->cfa;
- orig_context.reg[__builtin_dwarf_sp_column ()] = &tmp_sp;
- }
- context->reg[__builtin_dwarf_sp_column ()] = NULL;
+ 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;
@@ -1110,11 +1204,14 @@ uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
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:
@@ -1126,10 +1223,12 @@ 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;
}
+
+ MD_FROB_UPDATE_CONTEXT (context, fs);
}
/* CONTEXT describes the unwind state for a frame, and FS describes the FDE
@@ -1145,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
- ((void *) (_Unwind_Ptr) _Unwind_GetGR (context, fs->retaddr_column));
+ (_Unwind_GetPtr (context, fs->retaddr_column));
}
/* Fill in CONTEXT for top-of-stack. The only valid registers at this
@@ -1162,13 +1261,19 @@ uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
} \
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_Word sp_slot;
+ _Unwind_SpTmp sp_slot;
memset (context, 0, sizeof (struct _Unwind_Context));
context->ra = ra;
@@ -1176,9 +1281,20 @@ uw_init_context_1 (struct _Unwind_Context *context,
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. */
- sp_slot = (_Unwind_Ptr) outer_cfa;
- context->reg[__builtin_dwarf_sp_column ()] = &sp_slot;
+ _Unwind_SetSpColumn (context, outer_cfa, &sp_slot);
fs.cfa_how = CFA_REG_OFFSET;
fs.cfa_reg = __builtin_dwarf_sp_column ();
fs.cfa_offset = 0;
@@ -1205,34 +1321,17 @@ uw_init_context_1 (struct _Unwind_Context *context,
} \
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];
void *t = target->reg[i];
+
if (t && c && t != c)
memcpy (c, t, dwarf_reg_size_table[i]);
}
@@ -1242,9 +1341,8 @@ uw_install_context_1 (struct _Unwind_Context *current,
void *target_cfa;
/* If the last frame records a saved stack pointer, use it. */
- if (target->reg[__builtin_dwarf_sp_column ()])
- target_cfa = (void *)(_Unwind_Ptr)
- _Unwind_GetGR (target, __builtin_dwarf_sp_column ());
+ if (_Unwind_GetGRPtr (target, __builtin_dwarf_sp_column ()))
+ target_cfa = _Unwind_GetPtr (target, __builtin_dwarf_sp_column ());
else
target_cfa = target->cfa;
OpenPOWER on IntegriCloud