/* 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.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
- Software Foundation, 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA. */
+ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
#include "tconfig.h"
#include "tsystem.h"
void *lsda;
struct dwarf_eh_bases bases;
_Unwind_Word args_size;
+ char signal_frame;
+ char by_value[DWARF_FRAME_REGISTERS+1];
};
/* Byte size of every register managed by these routines. */
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. */
+/* 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 (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 (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 (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);
+ 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 = context->signal_frame != 0;
+ 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 + context->signal_frame)
{
unsigned char insn = *insn_ptr++;
_Unwind_Word reg, utmp;
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);
insn_ptr = read_uleb128 (insn_ptr, &fs->cfa_reg);
insn_ptr = read_sleb128 (insn_ptr, &fs->cfa_offset);
fs->cfa_how = CFA_REG_OFFSET;
+ fs->cfa_offset *= fs->data_align;
break;
case DW_CFA_def_cfa_offset_sf:
insn_ptr = read_sleb128 (insn_ptr, &fs->cfa_offset);
+ fs->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 + context->signal_frame - 1,
+ &context->bases);
if (fde == NULL)
{
#ifdef MD_FALLBACK_FRAME_STATE_FOR
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 ()];
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;
}
+ context->signal_frame = fs->signal_frame;
+
#ifdef MD_FROB_UPDATE_CONTEXT
MD_FROB_UPDATE_CONTEXT (context, fs);
#endif
context->ra = __builtin_extract_return_addr
(_Unwind_GetPtr (context, fs->retaddr_column));
}
+
+static void
+uw_advance_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
+{
+ uw_update_context (context, fs);
+}
\f
/* Fill in CONTEXT for top-of-stack. The only valid registers at this
level will be the return address and the CFA. */
/* 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]);
}