X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Funwind-dw2.c;h=d3828e97ad4e3da4130fec68ec7a7144d7abff1a;hb=6b989ab5a9be38e7ff27bd109a651b14b45e4f0e;hp=20deb5721f9a15638f8f3042a9faa324526fcbf7;hpb=9b84bf7de848cc4e27b88354c441e4a2bc41abb6;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/unwind-dw2.c b/gcc/unwind-dw2.c index 20deb5721f9..d3828e97ad4 100644 --- a/gcc/unwind-dw2.c +++ b/gcc/unwind-dw2.c @@ -1,22 +1,23 @@ /* 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 + Free Software Foundation, Inc. - This file is part of GNU CC. + This file is part of GCC. - GNU CC is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. - GNU CC 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 License for more details. + 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 + License for more details. You should have received a copy of the GNU General Public License - along with GNU CC; see the file COPYING. If not, write to - the Free Software Foundation, 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ + 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. */ #include "tconfig.h" #include "tsystem.h" @@ -27,7 +28,7 @@ #include "gthr.h" -#if !USING_SJLJ_EXCEPTIONS +#ifndef __USING_SJLJ_EXCEPTIONS__ #ifndef STACK_GROWS_DOWNWARD #define STACK_GROWS_DOWNWARD 0 @@ -42,6 +43,11 @@ #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 +#endif + /* This is the register and unwind state for a particular frame. */ struct _Unwind_Context { @@ -68,7 +74,7 @@ typedef struct { struct { union { - unsigned int reg; + _Unwind_Word reg; _Unwind_Sword offset; const unsigned char *exp; } loc; @@ -100,12 +106,13 @@ typedef struct /* The information we care about from the CIE/FDE. */ _Unwind_Personality_Fn personality; - signed int data_align; - unsigned int code_align; + _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. */ @@ -125,10 +132,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; } @@ -218,15 +225,21 @@ extract_cie_info (struct dwarf_cie *cie, struct _Unwind_Context *context, const unsigned char *aug = cie->augmentation; const unsigned char *p = aug + strlen (aug) + 1; const unsigned char *ret = NULL; - _Unwind_Word code_align; - _Unwind_Sword data_align; + _Unwind_Word utmp; + + /* g++ v2 "eh" has pointer immediately following augmentation string, + so it must be handled first. */ + if (aug[0] == 'e' && aug[1] == 'h') + { + fs->eh_ptr = read_pointer (p); + p += sizeof (void *); + aug += 2; + } /* Immediately following the augmentation are the code and data alignment and return address column. */ - p = read_uleb128 (p, &code_align); - p = read_sleb128 (p, &data_align); - fs->code_align = code_align; - fs->data_align = data_align; + p = read_uleb128 (p, &fs->code_align); + p = read_sleb128 (p, &fs->data_align); fs->retaddr_column = *p++; fs->lsda_encoding = DW_EH_PE_omit; @@ -235,9 +248,8 @@ extract_cie_info (struct dwarf_cie *cie, struct _Unwind_Context *context, the size. */ if (*aug == 'z') { - _Unwind_Word i; - p = read_uleb128 (p, &i); - ret = p + i; + p = read_uleb128 (p, &utmp); + ret = p + utmp; fs->saw_z = 1; ++aug; @@ -246,15 +258,8 @@ extract_cie_info (struct dwarf_cie *cie, struct _Unwind_Context *context, /* Iterate over recognized augmentation subsequences. */ while (*aug != '\0') { - /* "eh" was used by g++ v2; recognize and skip. */ - if (aug[0] == 'e' && aug[1] == 'h') - { - p += sizeof (void *); - aug += 2; - } - /* "L" indicates a byte showing how the LSDA pointer is encoded. */ - else if (aug[0] == 'L') + if (aug[0] == 'L') { fs->lsda_encoding = *p++; aug += 1; @@ -292,7 +297,7 @@ static _Unwind_Word execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end, struct _Unwind_Context *context, _Unwind_Word initial) { - _Unwind_Word stack[64]; /* ??? Assume this is enough. */ + _Unwind_Word stack[64]; /* ??? Assume this is enough. */ int stack_elt; stack[0] = initial; @@ -301,8 +306,8 @@ execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end, while (op_ptr < op_end) { enum dwarf_location_atom op = *op_ptr++; - _Unwind_Word result, reg; - _Unwind_Sword offset; + _Unwind_Word result, reg, utmp; + _Unwind_Sword offset, stmp; switch (op) { @@ -382,8 +387,8 @@ execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end, op_ptr = read_uleb128 (op_ptr, &result); break; case DW_OP_consts: - op_ptr = read_sleb128 (op_ptr, &offset); - result = offset; + op_ptr = read_sleb128 (op_ptr, &stmp); + result = stmp; break; case DW_OP_reg0: @@ -520,14 +525,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: @@ -559,9 +564,12 @@ execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end, result = ~result; break; case DW_OP_plus_uconst: - op_ptr = read_uleb128 (op_ptr, ®); - result += reg; + op_ptr = read_uleb128 (op_ptr, &utmp); + result += utmp; break; + + default: + abort (); } break; @@ -592,13 +600,13 @@ execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end, result = second & first; break; case DW_OP_div: - result = (_Unwind_Sword)second / (_Unwind_Sword)first; + 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; + result = (_Unwind_Sword) second % (_Unwind_Sword) first; break; case DW_OP_mul: result = second * first; @@ -616,29 +624,32 @@ execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end, result = second >> first; break; case DW_OP_shra: - result = (_Unwind_Sword)second >> first; + 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; + result = (_Unwind_Sword) first <= (_Unwind_Sword) second; break; case DW_OP_ge: - result = (_Unwind_Sword)first >= (_Unwind_Sword)second; + result = (_Unwind_Sword) first >= (_Unwind_Sword) second; break; case DW_OP_eq: - result = (_Unwind_Sword)first == (_Unwind_Sword)second; + result = (_Unwind_Sword) first == (_Unwind_Sword) second; break; case DW_OP_lt: - result = (_Unwind_Sword)first < (_Unwind_Sword)second; + result = (_Unwind_Sword) first < (_Unwind_Sword) second; break; case DW_OP_gt: - result = (_Unwind_Sword)first > (_Unwind_Sword)second; + result = (_Unwind_Sword) first > (_Unwind_Sword) second; break; case DW_OP_ne: - result = (_Unwind_Sword)first != (_Unwind_Sword)second; + result = (_Unwind_Sword) first != (_Unwind_Sword) second; break; + + default: + abort (); } } break; @@ -695,23 +706,30 @@ execute_cfa_program (const unsigned char *insn_ptr, /* Don't allow remember/restore between CIE and FDE programs. */ fs->regs.prev = NULL; + /* 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, uoffset; - _Unwind_Sword offset; + _Unwind_Word reg, utmp; + _Unwind_Sword offset, stmp; - if (insn & DW_CFA_advance_loc) + if ((insn & 0xc0) == DW_CFA_advance_loc) fs->pc += (insn & 0x3f) * fs->code_align; - else if (insn & DW_CFA_offset) + else if ((insn & 0xc0) == DW_CFA_offset) { reg = insn & 0x3f; - insn_ptr = read_uleb128 (insn_ptr, &uoffset); - offset = (_Unwind_Sword)uoffset * fs->data_align; + 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; } - else if (insn & DW_CFA_restore) + else if ((insn & 0xc0) == DW_CFA_restore) { reg = insn & 0x3f; fs->regs.reg[reg].how = REG_UNSAVED; @@ -724,22 +742,22 @@ execute_cfa_program (const unsigned char *insn_ptr, break; case DW_CFA_advance_loc1: - fs->pc += read_1u (insn_ptr); + fs->pc += read_1u (insn_ptr) * fs->code_align; insn_ptr += 1; break; case DW_CFA_advance_loc2: - fs->pc += read_2u (insn_ptr); + fs->pc += read_2u (insn_ptr) * fs->code_align; insn_ptr += 2; break; case DW_CFA_advance_loc4: - fs->pc += read_4u (insn_ptr); + fs->pc += read_4u (insn_ptr) * fs->code_align; insn_ptr += 4; break; case DW_CFA_offset_extended: insn_ptr = read_uleb128 (insn_ptr, ®); - insn_ptr = read_uleb128 (insn_ptr, &uoffset); - offset = (_Unwind_Sword)uoffset * fs->data_align; + 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; break; @@ -773,7 +791,7 @@ execute_cfa_program (const unsigned char *insn_ptr, unused_rs = unused_rs->prev; } else - new_rs = alloca (sizeof (struct frame_state_reg_info)); + new_rs = __builtin_alloca (sizeof (struct frame_state_reg_info)); *new_rs = fs->regs; fs->regs.prev = new_rs; @@ -791,8 +809,8 @@ execute_cfa_program (const unsigned char *insn_ptr, case DW_CFA_def_cfa: insn_ptr = read_uleb128 (insn_ptr, &fs->cfa_reg); - insn_ptr = read_uleb128 (insn_ptr, &uoffset); - fs->cfa_offset = uoffset; + insn_ptr = read_uleb128 (insn_ptr, &utmp); + fs->cfa_offset = utmp; fs->cfa_how = CFA_REG_OFFSET; break; @@ -802,31 +820,31 @@ execute_cfa_program (const unsigned char *insn_ptr, break; case DW_CFA_def_cfa_offset: - insn_ptr = read_uleb128 (insn_ptr, &uoffset); - fs->cfa_offset = uoffset; + insn_ptr = read_uleb128 (insn_ptr, &utmp); + fs->cfa_offset = utmp; /* cfa_how deliberately not set. */ break; case DW_CFA_def_cfa_expression: - insn_ptr = read_uleb128 (insn_ptr, &uoffset); + insn_ptr = read_uleb128 (insn_ptr, &utmp); fs->cfa_exp = insn_ptr; fs->cfa_how = CFA_EXP; - insn_ptr += uoffset; + insn_ptr += utmp; break; case DW_CFA_expression: insn_ptr = read_uleb128 (insn_ptr, ®); - insn_ptr = read_uleb128 (insn_ptr, &uoffset); + 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 += uoffset; + insn_ptr += utmp; break; /* From the 2.1 draft. */ case DW_CFA_offset_extended_sf: insn_ptr = read_uleb128 (insn_ptr, ®); - insn_ptr = read_sleb128 (insn_ptr, &offset); - offset *= fs->data_align; + 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; break; @@ -838,7 +856,7 @@ execute_cfa_program (const unsigned char *insn_ptr, break; case DW_CFA_def_cfa_offset_sf: - insn_ptr = read_uleb128 (insn_ptr, &fs->cfa_offset); + insn_ptr = read_sleb128 (insn_ptr, &fs->cfa_offset); /* cfa_how deliberately not set. */ break; @@ -859,8 +877,8 @@ execute_cfa_program (const unsigned char *insn_ptr, /* Obsoleted by DW_CFA_offset_extended_sf, but used by older PowerPC code. */ insn_ptr = read_uleb128 (insn_ptr, ®); - insn_ptr = read_uleb128 (insn_ptr, &uoffset); - offset = (_Unwind_Sword)uoffset * fs->data_align; + 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; break; @@ -887,7 +905,7 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs) { /* Couldn't find frame unwind info for this function. Try a target-specific fallback mechanism. This will necessarily - not profide a personality routine or LSDA. */ + 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; @@ -911,7 +929,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) @@ -932,8 +950,69 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs) return _URC_NO_REASON; } + +typedef struct frame_state +{ + void *cfa; + void *eh_ptr; + long cfa_offset; + long args_size; + long reg_or_offset[PRE_GCC3_DWARF_FRAME_REGISTERS+1]; + unsigned short cfa_reg; + unsigned short retaddr_column; + char saved[PRE_GCC3_DWARF_FRAME_REGISTERS+1]; +} frame_state; + +struct frame_state * __frame_state_for (void *, struct frame_state *); + +/* Called from pre-G++ 3.0 __throw to find the registers to restore for + a given PC_TARGET. The caller should allocate a local variable of + `struct frame_state' and pass its address to STATE_IN. */ + +struct frame_state * +__frame_state_for (void *pc_target, struct frame_state *state_in) +{ + struct _Unwind_Context context; + _Unwind_FrameState fs; + int reg; + memset (&context, 0, sizeof (struct _Unwind_Context)); + context.ra = pc_target + 1; + if (uw_frame_state_for (&context, &fs) != _URC_NO_REASON) + return 0; + + /* 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) + return 0; + + for (reg = 0; reg < PRE_GCC3_DWARF_FRAME_REGISTERS + 1; reg++) + { + state_in->saved[reg] = fs.regs.reg[reg].how; + switch (state_in->saved[reg]) + { + case REG_SAVED_REG: + state_in->reg_or_offset[reg] = fs.regs.reg[reg].loc.reg; + break; + case REG_SAVED_OFFSET: + state_in->reg_or_offset[reg] = fs.regs.reg[reg].loc.offset; + break; + default: + state_in->reg_or_offset[reg] = 0; + break; + } + } + + state_in->cfa_offset = fs.cfa_offset; + state_in->cfa_reg = fs.cfa_reg; + state_in->retaddr_column = fs.retaddr_column; + state_in->args_size = context.args_size; + state_in->eh_ptr = fs.eh_ptr; + + return state_in; +} + static void uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs) { @@ -1018,14 +1097,16 @@ uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs) /* 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 void uw_init_context_1 (struct _Unwind_Context *context, @@ -1059,12 +1140,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) +#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)