diff options
Diffstat (limited to 'contrib/gcc/unwind-dw2.c')
-rw-r--r-- | contrib/gcc/unwind-dw2.c | 216 |
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, ®); 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, ®); - 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, ®); insn_ptr = read_uleb128 (insn_ptr, ®2); - 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, ®); - 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, ®); 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, ®); 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; |