X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Funwind-dw2.c;h=f94eaf99da9ca9d3f5dca948dbe3ba0de4cd8a15;hb=658fc6b4e6c918222cc8ec22e1f396e0cda0fe28;hp=c2619bd88985d6c5b6deeb1e4a877ffdf1741c60;hpb=fc8b707bfb4d1204c1c5e68b309bdb04dabf71b8;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/unwind-dw2.c b/gcc/unwind-dw2.c index c2619bd8898..f94eaf99da9 100644 --- a/gcc/unwind-dw2.c +++ b/gcc/unwind-dw2.c @@ -1,5 +1,6 @@ /* DWARF2 exception handling and frame unwind runtime interface routines. - Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003 + Free Software Foundation, Inc. This file is part of GCC. @@ -8,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 @@ -20,6 +30,8 @@ #include "tconfig.h" #include "tsystem.h" +#include "coretypes.h" +#include "tm.h" #include "dwarf2.h" #include "unwind.h" #include "unwind-pe.h" @@ -27,7 +39,7 @@ #include "gthr.h" -#if !USING_SJLJ_EXCEPTIONS +#ifndef __USING_SJLJ_EXCEPTIONS__ #ifndef STACK_GROWS_DOWNWARD #define STACK_GROWS_DOWNWARD 0 @@ -47,7 +59,18 @@ #define PRE_GCC3_DWARF_FRAME_REGISTERS DWARF_FRAME_REGISTERS #endif -/* This is the register and unwind state for a particular frame. */ +#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. */ struct _Unwind_Context { void *reg[DWARF_FRAME_REGISTERS+1]; @@ -131,10 +154,10 @@ static inline void * read_pointer (const void *p) { const union unaligned *up = p; return up->p; } static inline int -read_1u (const void *p) { return *(const unsigned char *)p; } +read_1u (const void *p) { return *(const unsigned char *) p; } static inline int -read_1s (const void *p) { return *(const signed char *)p; } +read_1s (const void *p) { return *(const signed char *) p; } static inline int read_2u (const void *p) { const union unaligned *up = p; return up->u2; } @@ -159,8 +182,35 @@ 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); + 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. */ + +_Unwind_Word +_Unwind_GetCFA (struct _Unwind_Context *context) +{ + return (_Unwind_Ptr) context->cfa; } /* Overwrite the saved value for register REG in CONTEXT with VAL. */ @@ -168,7 +218,37 @@ _Unwind_GetGR (struct _Unwind_Context *context, int index) 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); + 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. */ @@ -199,6 +279,17 @@ _Unwind_GetRegionStart (struct _Unwind_Context *context) return (_Unwind_Ptr) context->bases.func; } +void * +_Unwind_FindEnclosingFunction (void *pc) +{ + struct dwarf_eh_bases bases; + struct dwarf_fde *fde = _Unwind_Find_FDE (pc-1, &bases); + if (fde) + return bases.func; + else + return NULL; +} + #ifndef __ia64__ _Unwind_Ptr _Unwind_GetDataRelBase (struct _Unwind_Context *context) @@ -524,14 +615,14 @@ execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end, { case DW_OP_deref: { - void *ptr = (void *)(_Unwind_Ptr) result; + void *ptr = (void *) (_Unwind_Ptr) result; result = (_Unwind_Ptr) read_pointer (ptr); } break; case DW_OP_deref_size: { - void *ptr = (void *)(_Unwind_Ptr) result; + void *ptr = (void *) (_Unwind_Ptr) result; switch (*op_ptr++) { case 1: @@ -588,68 +679,68 @@ 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 (); - second = stack[stack_elt]; - first = stack[stack_elt + 1]; - - switch (op) - { - case DW_OP_and: - result = second & first; - break; - case DW_OP_div: - result = (_Unwind_Sword)second / (_Unwind_Sword)first; - break; - case DW_OP_minus: - result = second - first; - break; - case DW_OP_mod: - result = (_Unwind_Sword)second % (_Unwind_Sword)first; - break; - case DW_OP_mul: - result = second * first; - break; - case DW_OP_or: - result = second | first; - break; - case DW_OP_plus: - result = second + first; - break; - case DW_OP_shl: - result = second << first; - break; - case DW_OP_shr: - result = second >> first; - break; - case DW_OP_shra: - result = (_Unwind_Sword)second >> first; - break; - case DW_OP_xor: - result = second ^ first; - break; - case DW_OP_le: - result = (_Unwind_Sword)first <= (_Unwind_Sword)second; - break; - case DW_OP_ge: - result = (_Unwind_Sword)first >= (_Unwind_Sword)second; - break; - case DW_OP_eq: - result = (_Unwind_Sword)first == (_Unwind_Sword)second; - break; - case DW_OP_lt: - result = (_Unwind_Sword)first < (_Unwind_Sword)second; - break; - case DW_OP_gt: - result = (_Unwind_Sword)first > (_Unwind_Sword)second; - break; - case DW_OP_ne: - result = (_Unwind_Sword)first != (_Unwind_Sword)second; - break; - - default: + if ((stack_elt -= 2) < 0) abort (); - } + second = stack[stack_elt]; + first = stack[stack_elt + 1]; + + switch (op) + { + case DW_OP_and: + result = second & first; + break; + case DW_OP_div: + result = (_Unwind_Sword) second / (_Unwind_Sword) first; + break; + case DW_OP_minus: + result = second - first; + break; + case DW_OP_mod: + result = (_Unwind_Sword) second % (_Unwind_Sword) first; + break; + case DW_OP_mul: + result = second * first; + break; + case DW_OP_or: + result = second | first; + break; + case DW_OP_plus: + result = second + first; + break; + case DW_OP_shl: + result = second << first; + break; + case DW_OP_shr: + result = second >> first; + break; + case DW_OP_shra: + result = (_Unwind_Sword) second >> first; + break; + case DW_OP_xor: + result = second ^ first; + break; + case DW_OP_le: + result = (_Unwind_Sword) first <= (_Unwind_Sword) second; + break; + case DW_OP_ge: + result = (_Unwind_Sword) first >= (_Unwind_Sword) second; + break; + case DW_OP_eq: + result = (_Unwind_Sword) first == (_Unwind_Sword) second; + break; + case DW_OP_lt: + result = (_Unwind_Sword) first < (_Unwind_Sword) second; + break; + case DW_OP_gt: + result = (_Unwind_Sword) first > (_Unwind_Sword) second; + break; + case DW_OP_ne: + result = (_Unwind_Sword) first != (_Unwind_Sword) second; + break; + + default: + abort (); + } } break; @@ -678,7 +769,7 @@ execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end, /* Most things push a result value. */ if ((size_t) stack_elt >= sizeof(stack)/sizeof(*stack)) abort (); - stack[++stack_elt] = result; + stack[stack_elt++] = result; no_push:; } @@ -705,7 +796,14 @@ execute_cfa_program (const unsigned char *insn_ptr, /* Don't allow remember/restore between CIE and FDE programs. */ fs->regs.prev = NULL; - while (insn_ptr < insn_end && fs->pc <= context->ra) + /* The comparison with the return address uses < rather than <= because + we are only interested in the effects of code before the call; for a + noreturn function, the return address may point to unrelated code with + 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) { unsigned char insn = *insn_ptr++; _Unwind_Word reg, utmp; @@ -717,14 +815,15 @@ 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; + offset = (_Unwind_Sword) utmp * fs->data_align; + 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) { @@ -749,18 +848,22 @@ execute_cfa_program (const unsigned char *insn_ptr, case DW_CFA_offset_extended: 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; + offset = (_Unwind_Sword) utmp * fs->data_align; + 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: case DW_CFA_same_value: + insn_ptr = read_uleb128 (insn_ptr, ®); + break; + case DW_CFA_nop: break; @@ -769,11 +872,11 @@ 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; - + case DW_CFA_remember_state: { struct frame_state_reg_info *new_rs; @@ -818,17 +921,17 @@ execute_cfa_program (const unsigned char *insn_ptr, break; case DW_CFA_def_cfa_expression: - insn_ptr = read_uleb128 (insn_ptr, &utmp); fs->cfa_exp = insn_ptr; fs->cfa_how = CFA_EXP; + insn_ptr = read_uleb128 (insn_ptr, &utmp); insn_ptr += utmp; break; case DW_CFA_expression: insn_ptr = read_uleb128 (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); - fs->regs.reg[reg].how = REG_SAVED_EXP; - fs->regs.reg[reg].loc.exp = insn_ptr; insn_ptr += utmp; break; @@ -837,10 +940,11 @@ 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: insn_ptr = read_uleb128 (insn_ptr, &fs->cfa_reg); insn_ptr = read_sleb128 (insn_ptr, &fs->cfa_offset); @@ -870,9 +974,10 @@ execute_cfa_program (const unsigned char *insn_ptr, older PowerPC code. */ 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; + offset = (_Unwind_Word) utmp * fs->data_align; + 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: @@ -881,6 +986,11 @@ execute_cfa_program (const unsigned char *insn_ptr, } } +/* Given the _Unwind_Context CONTEXT for a stack frame, look up the FDE for + its caller and decode it into FS. This function also sets the + args_size and lsda members of CONTEXT, as they are really information + about the caller's frame. */ + static _Unwind_Reason_Code uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs) { @@ -921,7 +1031,7 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs) execute_cfa_program (insn, end, context, fs); /* Locate augmentation for the fde. */ - aug = (unsigned char *)fde + sizeof (*fde); + aug = (unsigned char *) fde + sizeof (*fde); aug += 2 * size_of_encoded_value (fs->fde_encoding); insn = NULL; if (fs->saw_z) @@ -1005,6 +1115,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) { @@ -1012,34 +1139,45 @@ uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs) void *cfa; long i; +#ifdef EH_RETURN_STACKADJ_RTX + /* Special handling here: Many machines do not use a frame pointer, + and track the CFA only through offsets from the stack pointer from + one frame to the next. In this case, the stack pointer is never + stored, so it has no saved address in the context. What we do + have is the CFA from the previous stack frame. + + In very special situations (such as unwind info for signal return), + there may be location expressions that use the stack pointer as well. + + Do this conditionally for one frame. This allows the unwind info + for one frame to save a copy of the stack pointer from the previous + frame, and be able to use much easier CFA mechanisms to do it. + 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_SpTmp tmp_sp; + + 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: - /* Special handling here: Many machines do not use a frame pointer, - and track the CFA only through offsets from the stack pointer from - one frame to the next. In this case, the stack pointer is never - stored, so it has no saved address in the context. What we do - have is the CFA from the previous stack frame. */ - if (context->reg[fs->cfa_reg] == NULL) - cfa = context->cfa; - else - cfa = (void *) (_Unwind_Ptr) _Unwind_GetGR (context, fs->cfa_reg); + cfa = _Unwind_GetPtr (&orig_context, fs->cfa_reg); cfa += fs->cfa_offset; break; case CFA_EXP: - /* ??? No way of knowing what register number is the stack pointer - to do the same sort of handling as above. Assume that if the - CFA calculation is so complicated as to require a stack program - that this will not be a problem. */ { const unsigned char *exp = fs->cfa_exp; _Unwind_Word len; exp = read_uleb128 (exp, &len); cfa = (void *) (_Unwind_Ptr) - execute_stack_op (exp, exp + len, context, 0); + execute_stack_op (exp, exp + len, &orig_context, 0); break; } @@ -1054,12 +1192,18 @@ uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs) { case REG_UNSAVED: 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: { const unsigned char *exp = fs->regs.reg[i].loc.exp; @@ -1069,12 +1213,19 @@ 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 + of its caller. Update CONTEXT to refer to the caller as well. Note + that the args_size and lsda members are not updated here, but later in + uw_frame_state_for. */ + static void uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs) { @@ -1083,20 +1234,28 @@ 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 level will be the return address and the CFA. */ - -#define uw_init_context(CONTEXT) \ -do { \ - /* Do any necessary initialization to access arbitrary stack frames. \ - On the SPARC, this means flushing the register windows. */ \ - __builtin_unwind_init (); \ - uw_init_context_1 (CONTEXT, __builtin_dwarf_cfa (), \ - __builtin_return_address (0)); \ -} while (0) + +#define uw_init_context(CONTEXT) \ + do \ + { \ + /* Do any necessary initialization to access arbitrary stack frames. \ + On the SPARC, this means flushing the register windows. */ \ + __builtin_unwind_init (); \ + uw_init_context_1 (CONTEXT, __builtin_dwarf_cfa (), \ + __builtin_return_address (0)); \ + } \ + 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, @@ -1104,6 +1263,7 @@ 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; memset (context, 0, sizeof (struct _Unwind_Context)); context->ra = ra; @@ -1111,10 +1271,22 @@ 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. */ - context->cfa = outer_cfa; + _Unwind_SetSpColumn (context, outer_cfa, &sp_slot); fs.cfa_how = CFA_REG_OFFSET; - fs.cfa_reg = 0; + fs.cfa_reg = __builtin_dwarf_sp_column (); fs.cfa_offset = 0; uw_update_context_1 (context, &fs); @@ -1130,18 +1302,14 @@ uw_init_context_1 (struct _Unwind_Context *context, macro because __builtin_eh_return must be invoked in the context of our caller. */ -#define uw_install_context(CURRENT, TARGET) \ -do { \ - long offset = uw_install_context_1 ((CURRENT), (TARGET)); \ - void *handler = __builtin_frob_return_addr ((TARGET)->ra); \ - __builtin_eh_return (offset, handler); \ -} while (0) - -static inline void -init_dwarf_reg_size_table (void) -{ - __builtin_init_dwarf_reg_size_table (dwarf_reg_size_table); -} +#define uw_install_context(CURRENT, TARGET) \ + do \ + { \ + long offset = uw_install_context_1 ((CURRENT), (TARGET)); \ + void *handler = __builtin_frob_return_addr ((TARGET)->ra); \ + __builtin_eh_return (offset, handler); \ + } \ + while (0) static long uw_install_context_1 (struct _Unwind_Context *current, @@ -1149,31 +1317,34 @@ uw_install_context_1 (struct _Unwind_Context *current, { 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]); } - /* 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; +#ifdef EH_RETURN_STACKADJ_RTX + { + 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 + return 0; +#endif } static inline _Unwind_Ptr