/* DWARF2 exception handling and frame unwind runtime interface routines.
- Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
This file is part of GCC.
void *ra;
void *lsda;
struct dwarf_eh_bases bases;
+ /* Signal frame context. */
+#define SIGNAL_FRAME_BIT ((~(_Unwind_Word) 0 >> 1) + 1)
+ /* Context which has version/args_size/by_value fields. */
+#define EXTENDED_CONTEXT_BIT ((~(_Unwind_Word) 0 >> 2) + 1)
+ _Unwind_Word flags;
+ /* 0 for now, can be increased when further fields are added to
+ struct _Unwind_Context. */
+ _Unwind_Word version;
_Unwind_Word args_size;
+ char by_value[DWARF_FRAME_REGISTERS+1];
};
/* Byte size of every register managed by these routines. */
signed s8 __attribute__ ((mode (DI)));
} __attribute__ ((packed));
+static void uw_update_context (struct _Unwind_Context *, _Unwind_FrameState *);
+static _Unwind_Reason_Code uw_frame_state_for (struct _Unwind_Context *,
+ _Unwind_FrameState *);
+
static inline void *
read_pointer (const void *p) { const union unaligned *up = p; return up->p; }
static inline unsigned long
read_8s (const void *p) { const union unaligned *up = p; return up->s8; }
\f
-/* Get the value of register REG as saved in CONTEXT. */
+static inline _Unwind_Word
+_Unwind_IsSignalFrame (struct _Unwind_Context *context)
+{
+ return (context->flags & SIGNAL_FRAME_BIT) ? 1 : 0;
+}
+
+static inline void
+_Unwind_SetSignalFrame (struct _Unwind_Context *context, int val)
+{
+ if (val)
+ context->flags |= SIGNAL_FRAME_BIT;
+ else
+ context->flags &= ~SIGNAL_FRAME_BIT;
+}
+
+static inline _Unwind_Word
+_Unwind_IsExtendedContext (struct _Unwind_Context *context)
+{
+ return context->flags & EXTENDED_CONTEXT_BIT;
+}
+\f
+/* Get the value of register INDEX as saved in CONTEXT. */
inline _Unwind_Word
_Unwind_GetGR (struct _Unwind_Context *context, int index)
size = dwarf_reg_size_table[index];
ptr = context->reg[index];
+ if (_Unwind_IsExtendedContext (context) && context->by_value[index])
+ return (_Unwind_Word) (_Unwind_Internal_Ptr) ptr;
+
/* This will segfault if the register hasn't been saved. */
if (size == sizeof(_Unwind_Ptr))
return * (_Unwind_Ptr *) ptr;
return (_Unwind_Ptr) context->cfa;
}
-/* Overwrite the saved value for register REG in CONTEXT with VAL. */
+/* Overwrite the saved value for register INDEX in CONTEXT with VAL. */
inline void
_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val)
index = DWARF_REG_TO_UNWIND_COLUMN (index);
gcc_assert (index < (int) sizeof(dwarf_reg_size_table));
size = dwarf_reg_size_table[index];
+
+ if (_Unwind_IsExtendedContext (context) && context->by_value[index])
+ {
+ context->reg[index] = (void *) (_Unwind_Internal_Ptr) val;
+ return;
+ }
+
ptr = context->reg[index];
if (size == sizeof(_Unwind_Ptr))
_Unwind_GetGRPtr (struct _Unwind_Context *context, int index)
{
index = DWARF_REG_TO_UNWIND_COLUMN (index);
+ if (_Unwind_IsExtendedContext (context) && context->by_value[index])
+ return &context->reg[index];
return context->reg[index];
}
_Unwind_SetGRPtr (struct _Unwind_Context *context, int index, void *p)
{
index = DWARF_REG_TO_UNWIND_COLUMN (index);
+ if (_Unwind_IsExtendedContext (context))
+ context->by_value[index] = 0;
context->reg[index] = p;
}
+/* Overwrite the saved value for register INDEX in CONTEXT with VAL. */
+
+static inline void
+_Unwind_SetGRValue (struct _Unwind_Context *context, int index,
+ _Unwind_Word val)
+{
+ index = DWARF_REG_TO_UNWIND_COLUMN (index);
+ gcc_assert (index < (int) sizeof(dwarf_reg_size_table));
+ gcc_assert (dwarf_reg_size_table[index] == sizeof (_Unwind_Ptr));
+
+ context->by_value[index] = 1;
+ context->reg[index] = (void *) (_Unwind_Internal_Ptr) val;
+}
+
+/* Return nonzero if register INDEX is stored by value rather than
+ by reference. */
+
+static inline int
+_Unwind_GRByValue (struct _Unwind_Context *context, int index)
+{
+ index = DWARF_REG_TO_UNWIND_COLUMN (index);
+ return context->by_value[index];
+}
+
/* Retrieve the return address for CONTEXT. */
inline _Unwind_Ptr
return (_Unwind_Ptr) context->ra;
}
+/* Retrieve the return address and flag whether that IP is before
+ or after first not yet fully executed instruction. */
+
+inline _Unwind_Ptr
+_Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn)
+{
+ *ip_before_insn = _Unwind_IsSignalFrame (context);
+ return (_Unwind_Ptr) context->ra;
+}
+
/* Overwrite the return address for CONTEXT with VAL. */
inline void
aug += 1;
}
+ /* "S" indicates a signal frame. */
+ else if (aug[0] == 'S')
+ {
+ fs->signal_frame = 1;
+ aug += 1;
+ }
+
/* Otherwise we have an unknown augmentation string.
Bail unless we saw a 'z' prefix. */
else
a different stack configuration that we are not interested in. We
assume that the call itself is unwind info-neutral; if not, or if
there are delay instructions that adjust the stack, these must be
- reflected at the point immediately before the call insn. */
- while (insn_ptr < insn_end && fs->pc < context->ra)
+ reflected at the point immediately before the call insn.
+ In signal frames, return address is after last completed instruction,
+ so we add 1 to return address to make the comparison <=. */
+ while (insn_ptr < insn_end
+ && fs->pc < context->ra + _Unwind_IsSignalFrame (context))
{
unsigned char insn = *insn_ptr++;
_Unwind_Word reg, utmp;
break;
case DW_CFA_def_cfa:
- insn_ptr = read_uleb128 (insn_ptr, &fs->cfa_reg);
+ insn_ptr = read_uleb128 (insn_ptr, &fs->regs.cfa_reg);
insn_ptr = read_uleb128 (insn_ptr, &utmp);
- fs->cfa_offset = utmp;
- fs->cfa_how = CFA_REG_OFFSET;
+ fs->regs.cfa_offset = utmp;
+ fs->regs.cfa_how = CFA_REG_OFFSET;
break;
case DW_CFA_def_cfa_register:
- insn_ptr = read_uleb128 (insn_ptr, &fs->cfa_reg);
- fs->cfa_how = CFA_REG_OFFSET;
+ insn_ptr = read_uleb128 (insn_ptr, &fs->regs.cfa_reg);
+ fs->regs.cfa_how = CFA_REG_OFFSET;
break;
case DW_CFA_def_cfa_offset:
insn_ptr = read_uleb128 (insn_ptr, &utmp);
- fs->cfa_offset = utmp;
+ fs->regs.cfa_offset = utmp;
/* cfa_how deliberately not set. */
break;
case DW_CFA_def_cfa_expression:
- fs->cfa_exp = insn_ptr;
- fs->cfa_how = CFA_EXP;
+ fs->regs.cfa_exp = insn_ptr;
+ fs->regs.cfa_how = CFA_EXP;
insn_ptr = read_uleb128 (insn_ptr, &utmp);
insn_ptr += utmp;
break;
insn_ptr += utmp;
break;
- /* From the 2.1 draft. */
+ /* Dwarf3. */
case DW_CFA_offset_extended_sf:
insn_ptr = read_uleb128 (insn_ptr, ®);
insn_ptr = read_sleb128 (insn_ptr, &stmp);
break;
case DW_CFA_def_cfa_sf:
- insn_ptr = read_uleb128 (insn_ptr, &fs->cfa_reg);
- insn_ptr = read_sleb128 (insn_ptr, &fs->cfa_offset);
- fs->cfa_how = CFA_REG_OFFSET;
+ insn_ptr = read_uleb128 (insn_ptr, &fs->regs.cfa_reg);
+ insn_ptr = read_sleb128 (insn_ptr, &fs->regs.cfa_offset);
+ fs->regs.cfa_how = CFA_REG_OFFSET;
+ fs->regs.cfa_offset *= fs->data_align;
break;
case DW_CFA_def_cfa_offset_sf:
- insn_ptr = read_sleb128 (insn_ptr, &fs->cfa_offset);
+ insn_ptr = read_sleb128 (insn_ptr, &fs->regs.cfa_offset);
+ fs->regs.cfa_offset *= fs->data_align;
/* cfa_how deliberately not set. */
break;
+ case DW_CFA_val_offset:
+ insn_ptr = read_uleb128 (insn_ptr, ®);
+ insn_ptr = read_uleb128 (insn_ptr, &utmp);
+ offset = (_Unwind_Sword) utmp * fs->data_align;
+ fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
+ = REG_SAVED_VAL_OFFSET;
+ fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset;
+ break;
+
+ case DW_CFA_val_offset_sf:
+ insn_ptr = read_uleb128 (insn_ptr, ®);
+ insn_ptr = read_sleb128 (insn_ptr, &stmp);
+ offset = stmp * fs->data_align;
+ fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
+ = REG_SAVED_VAL_OFFSET;
+ fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset;
+ break;
+
+ case DW_CFA_val_expression:
+ insn_ptr = read_uleb128 (insn_ptr, ®);
+ fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
+ = REG_SAVED_VAL_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;
+
case DW_CFA_GNU_window_save:
/* ??? Hardcoded for SPARC register window configuration. */
for (reg = 16; reg < 32; ++reg)
if (context->ra == 0)
return _URC_END_OF_STACK;
- fde = _Unwind_Find_FDE (context->ra - 1, &context->bases);
+ fde = _Unwind_Find_FDE (context->ra + _Unwind_IsSignalFrame (context) - 1,
+ &context->bases);
if (fde == NULL)
{
#ifdef MD_FALLBACK_FRAME_STATE_FOR
int reg;
memset (&context, 0, sizeof (struct _Unwind_Context));
+ context.flags = EXTENDED_CONTEXT_BIT;
context.ra = pc_target + 1;
if (uw_frame_state_for (&context, &fs) != _URC_NO_REASON)
/* We have no way to pass a location expression for the CFA to our
caller. It wouldn't understand it anyway. */
- if (fs.cfa_how == CFA_EXP)
+ if (fs.regs.cfa_how == CFA_EXP)
return 0;
for (reg = 0; reg < PRE_GCC3_DWARF_FRAME_REGISTERS + 1; reg++)
}
}
- state_in->cfa_offset = fs.cfa_offset;
- state_in->cfa_reg = fs.cfa_reg;
+ state_in->cfa_offset = fs.regs.cfa_offset;
+ state_in->cfa_reg = fs.regs.cfa_reg;
state_in->retaddr_column = fs.retaddr_column;
state_in->args_size = context.args_size;
state_in->eh_ptr = fs.eh_ptr;
static inline void
_Unwind_SetSpColumn (struct _Unwind_Context *context, void *cfa,
- _Unwind_SpTmp *tmp_sp)
+ _Unwind_SpTmp *tmp_sp)
{
int size = dwarf_reg_size_table[__builtin_dwarf_sp_column ()];
#endif
/* Compute this frame's CFA. */
- switch (fs->cfa_how)
+ switch (fs->regs.cfa_how)
{
case CFA_REG_OFFSET:
- cfa = _Unwind_GetPtr (&orig_context, fs->cfa_reg);
- cfa += fs->cfa_offset;
+ cfa = _Unwind_GetPtr (&orig_context, fs->regs.cfa_reg);
+ cfa += fs->regs.cfa_offset;
break;
case CFA_EXP:
{
- const unsigned char *exp = fs->cfa_exp;
+ const unsigned char *exp = fs->regs.cfa_exp;
_Unwind_Word len;
exp = read_uleb128 (exp, &len);
break;
case REG_SAVED_REG:
- _Unwind_SetGRPtr
- (context, i,
- _Unwind_GetGRPtr (&orig_context, fs->regs.reg[i].loc.reg));
+ if (_Unwind_GRByValue (&orig_context, fs->regs.reg[i].loc.reg))
+ _Unwind_SetGRValue (context, i,
+ _Unwind_GetGR (&orig_context,
+ fs->regs.reg[i].loc.reg));
+ else
+ _Unwind_SetGRPtr (context, i,
+ _Unwind_GetGRPtr (&orig_context,
+ fs->regs.reg[i].loc.reg));
break;
case REG_SAVED_EXP:
_Unwind_SetGRPtr (context, i, (void *) val);
}
break;
+
+ case REG_SAVED_VAL_OFFSET:
+ _Unwind_SetGRValue (context, i,
+ (_Unwind_Internal_Ptr)
+ (cfa + fs->regs.reg[i].loc.offset));
+ break;
+
+ case REG_SAVED_VAL_EXP:
+ {
+ const unsigned char *exp = fs->regs.reg[i].loc.exp;
+ _Unwind_Word len;
+ _Unwind_Ptr val;
+
+ exp = read_uleb128 (exp, &len);
+ val = execute_stack_op (exp, exp + len, &orig_context,
+ (_Unwind_Ptr) cfa);
+ _Unwind_SetGRValue (context, i, val);
+ }
+ break;
}
+ _Unwind_SetSignalFrame (context, fs->signal_frame);
+
#ifdef MD_FROB_UPDATE_CONTEXT
MD_FROB_UPDATE_CONTEXT (context, fs);
#endif
memset (context, 0, sizeof (struct _Unwind_Context));
context->ra = ra;
+ context->flags = EXTENDED_CONTEXT_BIT;
code = uw_frame_state_for (context, &fs);
gcc_assert (code == _URC_NO_REASON);
{
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)
+ && dwarf_reg_size_table[0] == 0)
init_dwarf_reg_size_table ();
}
#else
/* Force the frame state to use the known cfa value. */
_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.regs.cfa_how = CFA_REG_OFFSET;
+ fs.regs.cfa_reg = __builtin_dwarf_sp_column ();
+ fs.regs.cfa_offset = 0;
uw_update_context_1 (context, &fs);
/* If the target frame does not have a saved stack pointer,
then set up the target's CFA. */
if (!_Unwind_GetGRPtr (target, __builtin_dwarf_sp_column ()))
- _Unwind_SetSpColumn (target, target->cfa, &sp_slot);
+ _Unwind_SetSpColumn (target, target->cfa, &sp_slot);
for (i = 0; i < DWARF_FRAME_REGISTERS; ++i)
{
void *c = current->reg[i];
void *t = target->reg[i];
- if (t && c && t != c)
+ gcc_assert (current->by_value[i] == 0);
+ if (target->by_value[i] && c)
+ {
+ _Unwind_Word w;
+ _Unwind_Ptr p;
+ if (dwarf_reg_size_table[i] == sizeof (_Unwind_Word))
+ {
+ w = (_Unwind_Internal_Ptr) t;
+ memcpy (c, &w, sizeof (_Unwind_Word));
+ }
+ else
+ {
+ gcc_assert (dwarf_reg_size_table[i] == sizeof (_Unwind_Ptr));
+ p = (_Unwind_Internal_Ptr) t;
+ memcpy (c, &p, sizeof (_Unwind_Ptr));
+ }
+ }
+ else if (t && c && t != c)
memcpy (c, t, dwarf_reg_size_table[i]);
}