diff options
author | kan <kan@FreeBSD.org> | 2007-05-19 01:19:51 +0000 |
---|---|---|
committer | kan <kan@FreeBSD.org> | 2007-05-19 01:19:51 +0000 |
commit | 1f9ea4d0a40cca64d60cf4dab152349da7b9dddf (patch) | |
tree | 0cb530c9c38af219e6dda2994c078b6b2b9ad853 /contrib/gcc/unwind-dw2.c | |
parent | 4895159b2b4f648051c1f139faa7b6dc50c2bfcb (diff) | |
download | FreeBSD-src-1f9ea4d0a40cca64d60cf4dab152349da7b9dddf.zip FreeBSD-src-1f9ea4d0a40cca64d60cf4dab152349da7b9dddf.tar.gz |
GCC 4.2.0 release.
Diffstat (limited to 'contrib/gcc/unwind-dw2.c')
-rw-r--r-- | contrib/gcc/unwind-dw2.c | 444 |
1 files changed, 293 insertions, 151 deletions
diff --git a/contrib/gcc/unwind-dw2.c b/contrib/gcc/unwind-dw2.c index 69cfd4f..62c9d09 100644 --- a/contrib/gcc/unwind-dw2.c +++ b/contrib/gcc/unwind-dw2.c @@ -1,5 +1,5 @@ /* 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. @@ -25,8 +25,8 @@ 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" @@ -40,7 +40,7 @@ #include "unwind-pe.h" #include "unwind-dw2-fde.h" #include "gthr.h" - +#include "unwind-dw2.h" #ifndef __USING_SJLJ_EXCEPTIONS__ @@ -51,12 +51,6 @@ #define STACK_GROWS_DOWNWARD 1 #endif -/* A target can override (perhaps for backward compatibility) how - many dwarf2 columns are unwound. */ -#ifndef DWARF_FRAME_REGISTERS -#define DWARF_FRAME_REGISTERS FIRST_PSEUDO_REGISTER -#endif - /* Dwarf frame registers used for pre gcc 3.0 compiled glibc. */ #ifndef PRE_GCC3_DWARF_FRAME_REGISTERS #define PRE_GCC3_DWARF_FRAME_REGISTERS DWARF_FRAME_REGISTERS @@ -66,11 +60,6 @@ #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. */ @@ -81,65 +70,22 @@ struct _Unwind_Context 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. */ static unsigned char dwarf_reg_size_table[DWARF_FRAME_REGISTERS+1]; -/* The result of interpreting the frame unwind info for a frame. - This is all symbolic at this point, as none of the values can - be resolved until the target pc is located. */ -typedef struct -{ - /* Each register save state can be described in terms of a CFA slot, - another register, or a location expression. */ - struct frame_state_reg_info - { - struct { - union { - _Unwind_Word reg; - _Unwind_Sword offset; - const unsigned char *exp; - } loc; - enum { - REG_UNSAVED, - REG_SAVED_OFFSET, - REG_SAVED_REG, - REG_SAVED_EXP - } how; - } reg[DWARF_FRAME_REGISTERS+1]; - - /* Used to implement DW_CFA_remember_state. */ - struct frame_state_reg_info *prev; - } regs; - - /* The CFA can be described in terms of a reg+offset or a - location expression. */ - _Unwind_Sword cfa_offset; - _Unwind_Word cfa_reg; - const unsigned char *cfa_exp; - enum { - CFA_UNSET, - CFA_REG_OFFSET, - CFA_EXP - } cfa_how; - - /* The PC described by the current frame state. */ - void *pc; - - /* The information we care about from the CIE/FDE. */ - _Unwind_Personality_Fn personality; - _Unwind_Sword data_align; - _Unwind_Word code_align; - unsigned char retaddr_column; - unsigned char fde_encoding; - unsigned char lsda_encoding; - unsigned char saw_z; - void *eh_ptr; -} _Unwind_FrameState; - /* Read unaligned data from the instruction buffer. */ union unaligned @@ -153,6 +99,10 @@ union unaligned 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; } @@ -180,7 +130,28 @@ read_8u (const void *p) { const union unaligned *up = p; return up->u8; } static inline unsigned long read_8s (const void *p) { const union unaligned *up = p; return up->s8; } -/* 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; +} + +/* Get the value of register INDEX as saved in CONTEXT. */ inline _Unwind_Word _Unwind_GetGR (struct _Unwind_Context *context, int index) @@ -194,19 +165,21 @@ _Unwind_GetGR (struct _Unwind_Context *context, int index) #endif index = DWARF_REG_TO_UNWIND_COLUMN (index); - if (index >= (int) sizeof(dwarf_reg_size_table)) - abort (); + gcc_assert (index < (int) sizeof(dwarf_reg_size_table)); 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; - - if (size == sizeof(_Unwind_Word)) - return * (_Unwind_Word *) ptr; - - abort (); + else + { + gcc_assert (size == sizeof(_Unwind_Word)); + return * (_Unwind_Word *) ptr; + } } static inline void * @@ -223,7 +196,7 @@ _Unwind_GetCFA (struct _Unwind_Context *context) 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) @@ -232,17 +205,24 @@ _Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val) void *ptr; index = DWARF_REG_TO_UNWIND_COLUMN (index); - if (index >= (int) sizeof(dwarf_reg_size_table)) - abort (); + 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_Ptr *) ptr = val; - else if (size == sizeof(_Unwind_Word)) - * (_Unwind_Word *) ptr = val; else - abort (); + { + gcc_assert (size == sizeof(_Unwind_Word)); + * (_Unwind_Word *) ptr = val; + } } /* Get the pointer to a register INDEX as saved in CONTEXT. */ @@ -251,6 +231,8 @@ static inline void * _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]; } @@ -260,9 +242,35 @@ static inline void _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 @@ -271,6 +279,16 @@ _Unwind_GetIP (struct _Unwind_Context *context) 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 @@ -315,6 +333,10 @@ _Unwind_GetTextRelBase (struct _Unwind_Context *context) return (_Unwind_Ptr) context->bases.tbase; } #endif + +#ifdef MD_UNWIND_SUPPORT +#include MD_UNWIND_SUPPORT +#endif /* Extract any interesting information from the CIE for the translation unit F belongs to. Return a pointer to the byte after the augmentation, @@ -325,7 +347,7 @@ extract_cie_info (const struct dwarf_cie *cie, struct _Unwind_Context *context, _Unwind_FrameState *fs) { const unsigned char *aug = cie->augmentation; - const unsigned char *p = aug + strlen (aug) + 1; + const unsigned char *p = aug + strlen ((const char *)aug) + 1; const unsigned char *ret = NULL; _Unwind_Word utmp; @@ -342,7 +364,10 @@ extract_cie_info (const struct dwarf_cie *cie, struct _Unwind_Context *context, data alignment and return address column. */ p = read_uleb128 (p, &fs->code_align); p = read_sleb128 (p, &fs->data_align); - fs->retaddr_column = *p++; + if (cie->version == 1) + fs->retaddr_column = *p++; + else + p = read_uleb128 (p, &fs->retaddr_column); fs->lsda_encoding = DW_EH_PE_omit; /* If the augmentation starts with 'z', then a uleb128 immediately @@ -377,8 +402,17 @@ extract_cie_info (const struct dwarf_cie *cie, struct _Unwind_Context *context, /* "P" indicates a personality routine in the CIE augmentation. */ else if (aug[0] == 'P') { - p = read_encoded_value (context, *p, p + 1, - (_Unwind_Ptr *) &fs->personality); + _Unwind_Ptr personality; + + p = read_encoded_value (context, *p, p + 1, &personality); + fs->personality = (_Unwind_Personality_Fn) personality; + aug += 1; + } + + /* "S" indicates a signal frame. */ + else if (aug[0] == 'S') + { + fs->signal_frame = 1; aug += 1; } @@ -574,35 +608,41 @@ execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end, break; case DW_OP_dup: - if (stack_elt < 1) - abort (); + gcc_assert (stack_elt); result = stack[stack_elt - 1]; break; case DW_OP_drop: - if (--stack_elt < 0) - abort (); + gcc_assert (stack_elt); + stack_elt -= 1; goto no_push; case DW_OP_pick: offset = *op_ptr++; - if (offset >= stack_elt - 1) - abort (); + gcc_assert (offset < stack_elt - 1); result = stack[stack_elt - 1 - offset]; break; case DW_OP_over: - if (stack_elt < 2) - abort (); + gcc_assert (stack_elt >= 2); result = stack[stack_elt - 2]; break; + case DW_OP_swap: + { + _Unwind_Word t; + gcc_assert (stack_elt >= 2); + t = stack[stack_elt - 1]; + stack[stack_elt - 1] = stack[stack_elt - 2]; + stack[stack_elt - 2] = t; + goto no_push; + } + case DW_OP_rot: { _Unwind_Word t1, t2, t3; - if (stack_elt < 3) - abort (); + gcc_assert (stack_elt >= 3); t1 = stack[stack_elt - 1]; t2 = stack[stack_elt - 2]; t3 = stack[stack_elt - 3]; @@ -619,8 +659,9 @@ execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end, case DW_OP_not: case DW_OP_plus_uconst: /* Unary operations. */ - if (--stack_elt < 0) - abort (); + gcc_assert (stack_elt); + stack_elt -= 1; + result = stack[stack_elt]; switch (op) @@ -650,7 +691,7 @@ execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end, result = read_8u (ptr); break; default: - abort (); + gcc_unreachable (); } } break; @@ -671,7 +712,7 @@ execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end, break; default: - abort (); + gcc_unreachable (); } break; @@ -695,8 +736,9 @@ execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end, { /* Binary operations. */ _Unwind_Word first, second; - if ((stack_elt -= 2) < 0) - abort (); + gcc_assert (stack_elt >= 2); + stack_elt -= 2; + second = stack[stack_elt]; first = stack[stack_elt + 1]; @@ -755,7 +797,7 @@ execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end, break; default: - abort (); + gcc_unreachable (); } } break; @@ -767,8 +809,9 @@ execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end, goto no_push; case DW_OP_bra: - if (--stack_elt < 0) - abort (); + gcc_assert (stack_elt); + stack_elt -= 1; + offset = read_2s (op_ptr); op_ptr += 2; if (stack[stack_elt] != 0) @@ -779,20 +822,19 @@ execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end, goto no_push; default: - abort (); + gcc_unreachable (); } /* Most things push a result value. */ - if ((size_t) stack_elt >= sizeof(stack)/sizeof(*stack)) - abort (); + gcc_assert ((size_t) stack_elt < sizeof(stack)/sizeof(*stack)); stack[stack_elt++] = result; no_push:; } /* We were executing this program to get a value. It should be at top of stack. */ - if (--stack_elt < 0) - abort (); + gcc_assert (stack_elt); + stack_elt -= 1; return stack[stack_elt]; } @@ -818,8 +860,11 @@ execute_cfa_program (const unsigned char *insn_ptr, 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; @@ -844,8 +889,13 @@ execute_cfa_program (const unsigned char *insn_ptr, else switch (insn) { case DW_CFA_set_loc: - insn_ptr = read_encoded_value (context, fs->fde_encoding, - insn_ptr, (_Unwind_Ptr *) &fs->pc); + { + _Unwind_Ptr pc; + + insn_ptr = read_encoded_value (context, fs->fde_encoding, + insn_ptr, &pc); + fs->pc = (void *) pc; + } break; case DW_CFA_advance_loc1: @@ -872,12 +922,15 @@ execute_cfa_program (const unsigned char *insn_ptr, case DW_CFA_restore_extended: insn_ptr = read_uleb128 (insn_ptr, ®); + /* FIXME, this is wrong; the CIE might have said that the + register was saved somewhere. */ fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN(reg)].how = REG_UNSAVED; break; case DW_CFA_undefined: case DW_CFA_same_value: insn_ptr = read_uleb128 (insn_ptr, ®); + fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN(reg)].how = REG_UNSAVED; break; case DW_CFA_nop: @@ -902,7 +955,7 @@ execute_cfa_program (const unsigned char *insn_ptr, unused_rs = unused_rs->prev; } else - new_rs = __builtin_alloca (sizeof (struct frame_state_reg_info)); + new_rs = alloca (sizeof (struct frame_state_reg_info)); *new_rs = fs->regs; fs->regs.prev = new_rs; @@ -951,7 +1004,7 @@ execute_cfa_program (const unsigned char *insn_ptr, 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); @@ -965,13 +1018,42 @@ execute_cfa_program (const unsigned char *insn_ptr, 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) @@ -997,7 +1079,7 @@ execute_cfa_program (const unsigned char *insn_ptr, break; default: - abort (); + gcc_unreachable (); } } } @@ -1021,17 +1103,15 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs) 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 /* Couldn't find frame unwind info for this function. Try a target-specific fallback mechanism. This will necessarily not provide a personality routine or LSDA. */ -#ifdef MD_FALLBACK_FRAME_STATE_FOR - MD_FALLBACK_FRAME_STATE_FOR (context, fs, success); - return _URC_END_OF_STACK; - success: - return _URC_NO_REASON; + return MD_FALLBACK_FRAME_STATE_FOR (context, fs); #else return _URC_END_OF_STACK; #endif @@ -1060,8 +1140,12 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs) insn = aug + i; } if (fs->lsda_encoding != DW_EH_PE_omit) - aug = read_encoded_value (context, fs->lsda_encoding, aug, - (_Unwind_Ptr *) &context->lsda); + { + _Unwind_Ptr lsda; + + aug = read_encoded_value (context, fs->lsda_encoding, aug, &lsda); + context->lsda = (void *) lsda; + } /* Then the insns in the FDE up to our target PC. */ if (insn == NULL) @@ -1098,6 +1182,7 @@ __frame_state_for (void *pc_target, struct frame_state *state_in) 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) @@ -1138,16 +1223,17 @@ 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) + _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 (); + { + gcc_assert (size == sizeof(_Unwind_Word)); + tmp_sp->word = (_Unwind_Ptr) cfa; + } _Unwind_SetGRPtr (context, __builtin_dwarf_sp_column (), tmp_sp); } @@ -1201,7 +1287,7 @@ uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs) } default: - abort (); + gcc_unreachable (); } context->cfa = cfa; @@ -1218,9 +1304,14 @@ uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs) 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: @@ -1235,9 +1326,32 @@ uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs) _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 } /* CONTEXT describes the unwind state for a frame, and FS describes the FDE @@ -1255,6 +1369,12 @@ uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs) 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); +} /* Fill in CONTEXT for top-of-stack. The only valid registers at this level will be the return address and the CFA. */ @@ -1283,12 +1403,14 @@ uw_init_context_1 (struct _Unwind_Context *context, void *ra = __builtin_extract_return_addr (__builtin_return_address (0)); _Unwind_FrameState fs; _Unwind_SpTmp sp_slot; + _Unwind_Reason_Code code; memset (context, 0, sizeof (struct _Unwind_Context)); context->ra = ra; + context->flags = EXTENDED_CONTEXT_BIT; - if (uw_frame_state_for (context, &fs) != _URC_NO_REASON) - abort (); + code = uw_frame_state_for (context, &fs); + gcc_assert (code == _URC_NO_REASON); #if __GTHREADS { @@ -1335,35 +1457,55 @@ uw_install_context_1 (struct _Unwind_Context *current, struct _Unwind_Context *target) { long i; + _Unwind_SpTmp sp_slot; + + /* 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); 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]); } -#ifdef EH_RETURN_STACKADJ_RTX - { - void *target_cfa; + /* If the current frame doesn't have a saved stack pointer, then we + need to rely on EH_RETURN_STACKADJ_RTX to get our target stack + pointer value reloaded. */ + if (!_Unwind_GetGRPtr (current, __builtin_dwarf_sp_column ())) + { + 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 + + /* 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; + } return 0; -#endif } static inline _Unwind_Ptr |