diff options
author | Jakub Jelinek <jakub@redhat.com> | 2006-02-27 18:26:26 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2006-02-27 18:26:26 +0100 |
commit | 754e45a8679ad25d2f622919749497c16dc2ea4c (patch) | |
tree | 6984337363ffe60556818a17e48ceaa2283110bb /gcc/unwind-dw2.c | |
parent | 6df11ca1befd286661b26a6a2a6774f4d4aa483c (diff) | |
download | gcc-754e45a8679ad25d2f622919749497c16dc2ea4c.tar.gz |
re PR other/26208 (Serious problem with unwinding through signal frames)
PR other/26208
* unwind-dw2.c (struct _Unwind_Context): Add signal_frame field.
(extract_cie_info): Handle S flag in augmentation string.
(execute_cfa_program): If context->signal_frame, execute also
fs->pc == context->ra instructions.
(uw_frame_state_for): If context->signal_frame, don't subtract one
from context->ra to find FDE.
(uw_update_context_1): Set context->signal_frame to
fs->signal_frame.
(_Unwind_GetIPInfo): New function.
* unwind-dw2.h (_Unwind_FrameState): Add signal_frame field.
* unwind-c.c (PERSONALITY_FUNCTION): Use _Unwind_GetIPInfo instead
of _Unwind_GetIP.
* unwind-sjlj.c (_Unwind_GetIPInfo): New function.
* unwind-generic.h (_Unwind_GetIPInfo): New prototype.
* unwind-compat.c (_Unwind_GetIPInfo): New function.
* libgcc-std.ver (_Unwind_GetIPInfo): Export @@GCC_4.2.0.
* config/ia64/unwind-ia64.c (_Unwind_GetIPInfo): New function.
* config/arm/unwind-arm.h (_Unwind_GetIPInfo): Define.
* config/i386/linux-unwind.h (x86_fallback_frame_state,
x86_64_fallback_frame_state): Set fs->signal_frame.
* config/rs6000/linux-unwind.h (ppc_fallback_frame_state): Likewise.
(MD_FROB_UPDATE_CONTEXT): Define unconditionally.
(frob_update_context): Likewise. Workaround missing S flag in
Linux 2.6.12 - 2.6.16 kernel vDSOs.
* config/s390/linux-unwind.h (s390_fallback_frame_state): Likewise.
Remove the psw_addr + 1 hack.
libjava/
* exception.cc (PERSONALITY_FUNCTION): Use _Unwind_GetIPInfo instead
of _Unwind_GetIP.
* include/i386-signal.h (MAKE_THROW_FRAME): Change into empty macro.
(HANDLE_DIVIDE_OVERFLOW): Don't adjust _res->eip if falling through
to throw.
* include/x86_64-signal.h (MAKE_THROW_FRAME): Change into empty
macro.
* include/powerpc-signal.h (MAKE_THROW_FRAME): Change into empty
macro.
libstdc++-v3/
* libsupc++/eh_personality.cc (PERSONALITY_FUNCTION): Use
_Unwind_GetIPInfo instead of _Unwind_GetIP.
From-SVN: r111488
Diffstat (limited to 'gcc/unwind-dw2.c')
-rw-r--r-- | gcc/unwind-dw2.c | 31 |
1 files changed, 27 insertions, 4 deletions
diff --git a/gcc/unwind-dw2.c b/gcc/unwind-dw2.c index 930f02f3799..8707391a86b 100644 --- a/gcc/unwind-dw2.c +++ b/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. @@ -71,6 +71,7 @@ struct _Unwind_Context void *lsda; struct dwarf_eh_bases bases; _Unwind_Word args_size; + char signal_frame; }; /* Byte size of every register managed by these routines. */ @@ -207,6 +208,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 = context->signal_frame != 0; + return (_Unwind_Ptr) context->ra; +} + /* Overwrite the return address for CONTEXT with VAL. */ inline void @@ -327,6 +338,13 @@ extract_cie_info (const struct dwarf_cie *cie, struct _Unwind_Context *context, aug += 1; } + /* "S" indicates a signal frame. */ + else if (aug[0] == 'S') + { + fs->signal_frame = 1; + aug += 1; + } + /* Otherwise we have an unknown augmentation string. Bail unless we saw a 'z' prefix. */ else @@ -761,8 +779,10 @@ 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 + context->signal_frame) { unsigned char insn = *insn_ptr++; _Unwind_Word reg, utmp; @@ -974,7 +994,8 @@ 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 + context->signal_frame - 1, + &context->bases); if (fde == NULL) { #ifdef MD_FALLBACK_FRAME_STATE_FOR @@ -1192,6 +1213,8 @@ uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs) break; } + context->signal_frame = fs->signal_frame; + #ifdef MD_FROB_UPDATE_CONTEXT MD_FROB_UPDATE_CONTEXT (context, fs); #endif |