/* DWARF2 exception handling and frame unwind runtime interface routines.
- Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003
+ Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
Free Software Foundation, Inc.
This file is part of GCC.
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
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"
#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"
-
+#include "unwind-dw2.h"
#ifndef __USING_SJLJ_EXCEPTIONS__
#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
#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. */
};
/* Byte size of every register managed by these routines. */
-static unsigned char dwarf_reg_size_table[DWARF_FRAME_REGISTERS];
+static unsigned char dwarf_reg_size_table[DWARF_FRAME_REGISTERS+1];
\f
-/* 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;
-\f
/* Read unaligned data from the instruction buffer. */
union unaligned
int size;
void *ptr;
+#ifdef DWARF_ZERO_REG
+ if (index == DWARF_ZERO_REG)
+ return 0;
+#endif
+
index = DWARF_REG_TO_UNWIND_COLUMN (index);
+ gcc_assert (index < (int) sizeof(dwarf_reg_size_table));
size = dwarf_reg_size_table[index];
ptr = context->reg[index];
/* 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 *
void *ptr;
index = DWARF_REG_TO_UNWIND_COLUMN (index);
+ gcc_assert (index < (int) sizeof(dwarf_reg_size_table));
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 ();
+ {
+ gcc_assert (size == sizeof(_Unwind_Word));
+ * (_Unwind_Word *) ptr = val;
+ }
}
/* Get the pointer to a register INDEX as saved in CONTEXT. */
_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
return (_Unwind_Ptr) context->bases.tbase;
}
#endif
+
+#ifdef MD_UNWIND_SUPPORT
+#include MD_UNWIND_SUPPORT
+#endif
\f
/* Extract any interesting information from the CIE for the translation
unit F belongs to. Return a pointer to the byte after the augmentation,
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;
- 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;
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
/* "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;
}
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;
{
_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];
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)
result = read_8u (ptr);
break;
default:
- abort ();
+ gcc_unreachable ();
}
}
break;
break;
default:
- abort ();
+ gcc_unreachable ();
}
break;
case DW_OP_mul:
case DW_OP_or:
case DW_OP_plus:
+ case DW_OP_shl:
+ case DW_OP_shr:
+ case DW_OP_shra:
+ case DW_OP_xor:
case DW_OP_le:
case DW_OP_ge:
case DW_OP_eq:
{
/* 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];
break;
default:
- abort ();
+ gcc_unreachable ();
}
}
break;
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)
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];
}
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:
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:
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;
break;
default:
- abort ();
+ gcc_unreachable ();
}
}
}
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));
context->args_size = 0;
context->lsda = 0;
+ if (context->ra == 0)
+ return _URC_END_OF_STACK;
+
fde = _Unwind_Find_FDE (context->ra - 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
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)
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);
}
}
default:
- abort ();
+ gcc_unreachable ();
}
context->cfa = cfa;
break;
}
+#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
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;
- 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
{
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)
{
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
#include "unwind.inc"
+#if defined (USE_GAS_SYMVER) && defined (SHARED) && defined (USE_LIBUNWIND_EXCEPTIONS)
+alias (_Unwind_Backtrace);
+alias (_Unwind_DeleteException);
+alias (_Unwind_FindEnclosingFunction);
+alias (_Unwind_ForcedUnwind);
+alias (_Unwind_GetDataRelBase);
+alias (_Unwind_GetTextRelBase);
+alias (_Unwind_GetCFA);
+alias (_Unwind_GetGR);
+alias (_Unwind_GetIP);
+alias (_Unwind_GetLanguageSpecificData);
+alias (_Unwind_GetRegionStart);
+alias (_Unwind_RaiseException);
+alias (_Unwind_Resume);
+alias (_Unwind_Resume_or_Rethrow);
+alias (_Unwind_SetGR);
+alias (_Unwind_SetIP);
+#endif
+
#endif /* !USING_SJLJ_EXCEPTIONS */