diff options
author | jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4> | 2006-02-27 17:26:26 +0000 |
---|---|---|
committer | jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4> | 2006-02-27 17:26:26 +0000 |
commit | 15c73eb7f6ae9d0be39182f797df10d573be4199 (patch) | |
tree | 6984337363ffe60556818a17e48ceaa2283110bb /gcc | |
parent | 5f506404644a3986acc8986f3c980a488c2c27b7 (diff) | |
download | gcc-15c73eb7f6ae9d0be39182f797df10d573be4199.tar.gz |
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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@111488 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 30 | ||||
-rw-r--r-- | gcc/config/arm/unwind-arm.h | 5 | ||||
-rw-r--r-- | gcc/config/i386/linux-unwind.h | 4 | ||||
-rw-r--r-- | gcc/config/ia64/unwind-ia64.c | 7 | ||||
-rw-r--r-- | gcc/config/rs6000/linux-unwind.h | 66 | ||||
-rw-r--r-- | gcc/config/s390/linux-unwind.h | 28 | ||||
-rw-r--r-- | gcc/libgcc-std.ver | 1 | ||||
-rw-r--r-- | gcc/unwind-c.c | 5 | ||||
-rw-r--r-- | gcc/unwind-compat.c | 9 | ||||
-rw-r--r-- | gcc/unwind-dw2.c | 31 | ||||
-rw-r--r-- | gcc/unwind-dw2.h | 1 | ||||
-rw-r--r-- | gcc/unwind-generic.h | 3 | ||||
-rw-r--r-- | gcc/unwind-sjlj.c | 7 |
13 files changed, 145 insertions, 52 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ca154bdd1fe..baabf6a5f1a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,33 @@ +2006-02-27 Jakub Jelinek <jakub@redhat.com> + + 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. + 2006-02-27 Daniel Berlin <dberlin@dberlin.org> * tree-ssa-structalias.c (get_constraint_for): Move code to deal diff --git a/gcc/config/arm/unwind-arm.h b/gcc/config/arm/unwind-arm.h index dd8d2affe39..f7cfcab8890 100644 --- a/gcc/config/arm/unwind-arm.h +++ b/gcc/config/arm/unwind-arm.h @@ -1,5 +1,5 @@ /* Header file for the ARM EABI unwinder - Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. Contributed by Paul Brook This file is free software; you can redistribute it and/or modify it @@ -250,6 +250,9 @@ extern "C" { #define _Unwind_GetIP(context) \ (_Unwind_GetGR (context, 15) & ~(_Unwind_Word)1) +#define _Unwind_GetIP(context, ip_before_insn) \ + (*ip_before_insn = 0, _Unwind_GetGR (context, 15) & ~(_Unwind_Word)1) + static inline void _Unwind_SetGR (_Unwind_Context *context, int regno, _Unwind_Word val) { diff --git a/gcc/config/i386/linux-unwind.h b/gcc/config/i386/linux-unwind.h index 6ca1309c73c..07979d319b6 100644 --- a/gcc/config/i386/linux-unwind.h +++ b/gcc/config/i386/linux-unwind.h @@ -1,5 +1,5 @@ /* DWARF2 EH unwinding support for AMD x86-64 and x86. - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GCC. @@ -100,6 +100,7 @@ x86_64_fallback_frame_state (struct _Unwind_Context *context, fs->regs.reg[16].how = REG_SAVED_OFFSET; fs->regs.reg[16].loc.offset = (long)&sc->rip - new_cfa; fs->retaddr_column = 16; + fs->signal_frame = 1; return _URC_NO_REASON; } @@ -172,6 +173,7 @@ x86_fallback_frame_state (struct _Unwind_Context *context, fs->regs.reg[8].how = REG_SAVED_OFFSET; fs->regs.reg[8].loc.offset = (long)&sc->REG_NAME(eip) - new_cfa; fs->retaddr_column = 8; + fs->signal_frame = 1; return _URC_NO_REASON; } #endif /* not glibc 2.0 */ diff --git a/gcc/config/ia64/unwind-ia64.c b/gcc/config/ia64/unwind-ia64.c index 302f0d14927..fc7b20701cd 100644 --- a/gcc/config/ia64/unwind-ia64.c +++ b/gcc/config/ia64/unwind-ia64.c @@ -1704,6 +1704,13 @@ _Unwind_GetIP (struct _Unwind_Context *context) return context->rp; } +inline _Unwind_Ptr +_Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn) +{ + *ip_before_insn = 0; + return context->rp; +} + /* Overwrite the return address for CONTEXT with VAL. */ inline void diff --git a/gcc/config/rs6000/linux-unwind.h b/gcc/config/rs6000/linux-unwind.h index 6e822bde0e2..d01e6b1fb32 100644 --- a/gcc/config/rs6000/linux-unwind.h +++ b/gcc/config/rs6000/linux-unwind.h @@ -1,5 +1,5 @@ /* DWARF2 EH unwinding support for PowerPC and PowerPC64 Linux. - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GCC. @@ -89,26 +89,6 @@ struct gcc_ucontext enum { SIGNAL_FRAMESIZE = 128 }; -/* If the current unwind info (FS) does not contain explicit info - saving R2, then we have to do a minor amount of code reading to - figure out if it was saved. The big problem here is that the - code that does the save/restore is generated by the linker, so - we have no good way to determine at compile time what to do. */ - -#define MD_FROB_UPDATE_CONTEXT frob_update_context - -static void -frob_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs) -{ - if (fs->regs.reg[2].how == REG_UNSAVED) - { - unsigned int *insn - = (unsigned int *) _Unwind_GetGR (context, LINK_REGISTER_REGNUM); - if (*insn == 0xE8410028) - _Unwind_SetGRPtr (context, 2, context->cfa + 40); - } -} - /* If PC is at a sigreturn trampoline, return a pointer to the regs. Otherwise return NULL. */ @@ -272,6 +252,7 @@ ppc_fallback_frame_state (struct _Unwind_Context *context, fs->regs.reg[ARG_POINTER_REGNUM].how = REG_SAVED_OFFSET; fs->regs.reg[ARG_POINTER_REGNUM].loc.offset = (long) ®s->nip - new_cfa; fs->retaddr_column = ARG_POINTER_REGNUM; + fs->signal_frame = 1; if (hwcap == 0) { @@ -322,3 +303,46 @@ ppc_fallback_frame_state (struct _Unwind_Context *context, return _URC_NO_REASON; } + +#define MD_FROB_UPDATE_CONTEXT frob_update_context + +static void +frob_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs) +{ + const unsigned int *pc = (const unsigned int *) context->ra; + + /* Fix up for 2.6.12 - 2.6.16 Linux kernels that have vDSO, but don't + have S flag in it. */ +#ifdef __powerpc64__ + /* addi r1, r1, 128; li r0, 0x0077; sc (sigreturn) */ + /* addi r1, r1, 128; li r0, 0x00AC; sc (rt_sigreturn) */ + if (pc[0] == 0x38210000 + SIGNAL_FRAMESIZE + && (pc[1] == 0x38000077 || pc[1] == 0x380000AC) + && pc[2] == 0x44000002) + context->signal_frame = 1; +#else + /* li r0, 0x7777; sc (sigreturn old) */ + /* li r0, 0x0077; sc (sigreturn new) */ + /* li r0, 0x6666; sc (rt_sigreturn old) */ + /* li r0, 0x00AC; sc (rt_sigreturn new) */ + if ((pc[0] == 0x38007777 || pc[0] == 0x38000077 + || pc[0] == 0x38006666 || pc[0] == 0x380000AC) + && pc[1] == 0x44000002) + context->signal_frame = 1; +#endif + +#ifdef __powerpc64__ + if (fs->regs.reg[2].how == REG_UNSAVED) + { + /* If the current unwind info (FS) does not contain explicit info + saving R2, then we have to do a minor amount of code reading to + figure out if it was saved. The big problem here is that the + code that does the save/restore is generated by the linker, so + we have no good way to determine at compile time what to do. */ + unsigned int *insn + = (unsigned int *) _Unwind_GetGR (context, LINK_REGISTER_REGNUM); + if (*insn == 0xE8410028) + _Unwind_SetGRPtr (context, 2, context->cfa + 40); + } +#endif +} diff --git a/gcc/config/s390/linux-unwind.h b/gcc/config/s390/linux-unwind.h index 5f22dfc1bff..d1e9b735edb 100644 --- a/gcc/config/s390/linux-unwind.h +++ b/gcc/config/s390/linux-unwind.h @@ -1,5 +1,5 @@ /* DWARF2 EH unwinding support for S/390 Linux. - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GCC. @@ -113,27 +113,11 @@ s390_fallback_frame_state (struct _Unwind_Context *context, fs->regs.reg[32].how = REG_SAVED_OFFSET; fs->regs.reg[32].loc.offset = (long)®s->psw_addr - new_cfa; fs->retaddr_column = 32; - - /* If we got a SIGSEGV or a SIGBUS, the PSW address points *to* - the faulting instruction, not after it. This causes the logic - in unwind-dw2.c that decrements the RA to determine the correct - CFI region to get confused. To fix that, we *increment* the RA - here in that case. Note that we cannot modify the RA in place, - and the frame state wants a *pointer*, not a value; thus we put - the modified RA value into the unused register 33 slot of FS and - have the register 32 save address point to that slot. - - Unfortunately, for regular signals on old kernels, we don't know - the signal number. We default to not fiddling with the RA; - that can fail in rare cases. Upgrade your kernel. */ - - if (signo && (*signo == 11 || *signo == 7)) - { - fs->regs.reg[33].loc.exp = - (unsigned char *)regs->psw_addr + 1; - fs->regs.reg[32].loc.offset = - (long)&fs->regs.reg[33].loc.exp - new_cfa; - } + /* SIGILL, SIGFPE and SIGTRAP are delivered with psw_addr + after the faulting instruction rather than before it. + Don't set FS->signal_frame in that case. */ + if (!signo || (*signo != 4 && *signo != 5 && *signo != 8)) + fs->signal_frame = 1; return _URC_NO_REASON; } diff --git a/gcc/libgcc-std.ver b/gcc/libgcc-std.ver index cb2e7fe40d8..f8e9e52d082 100644 --- a/gcc/libgcc-std.ver +++ b/gcc/libgcc-std.ver @@ -272,4 +272,5 @@ GCC_4.2.0 { __floatuntisf __floatuntixf __floatuntitf + _Unwind_GetIPInfo } diff --git a/gcc/unwind-c.c b/gcc/unwind-c.c index e3e2eca1804..cf17b6174d2 100644 --- a/gcc/unwind-c.c +++ b/gcc/unwind-c.c @@ -127,6 +127,7 @@ PERSONALITY_FUNCTION (int version, lsda_header_info info; const unsigned char *language_specific_data, *p, *action_record; _Unwind_Ptr landing_pad, ip; + int ip_before_insn = 0; #ifdef __ARM_EABI_UNWINDER__ if ((state & _US_ACTION_MASK) != _US_UNWIND_FRAME_STARTING) @@ -156,7 +157,9 @@ PERSONALITY_FUNCTION (int version, /* Parse the LSDA header. */ p = parse_lsda_header (context, language_specific_data, &info); - ip = _Unwind_GetIP (context) - 1; + ip = _Unwind_GetIPInfo (context, &ip_before_insn); + if (! ip_before_insn) + --ip; landing_pad = 0; #ifdef __USING_SJLJ_EXCEPTIONS__ diff --git a/gcc/unwind-compat.c b/gcc/unwind-compat.c index f5316f0b6cb..fa40ab27cba 100644 --- a/gcc/unwind-compat.c +++ b/gcc/unwind-compat.c @@ -1,5 +1,5 @@ /* Backward compatibility unwind routines. - Copyright (C) 2004, 2005 + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GCC. @@ -136,6 +136,13 @@ _Unwind_GetIP (struct _Unwind_Context *context) } symver (_Unwind_GetIP, GCC_3.0); +_Unwind_Ptr +_Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn) +{ + *ip_before_insn = 0; + return __libunwind_Unwind_GetIP (context); +} + extern void *__libunwind_Unwind_GetLanguageSpecificData (struct _Unwind_Context *); 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 diff --git a/gcc/unwind-dw2.h b/gcc/unwind-dw2.h index e894dd913dc..4851067fdfb 100644 --- a/gcc/unwind-dw2.h +++ b/gcc/unwind-dw2.h @@ -83,6 +83,7 @@ typedef struct unsigned char fde_encoding; unsigned char lsda_encoding; unsigned char saw_z; + unsigned char signal_frame; void *eh_ptr; } _Unwind_FrameState; diff --git a/gcc/unwind-generic.h b/gcc/unwind-generic.h index 9c0c7da07ad..3f4c06530ce 100644 --- a/gcc/unwind-generic.h +++ b/gcc/unwind-generic.h @@ -1,5 +1,5 @@ /* Exception handling and frame unwind runtime interface routines. - Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 2001, 2003, 2004, 2006 Free Software Foundation, Inc. This file is part of GCC. @@ -155,6 +155,7 @@ extern _Unwind_Word _Unwind_GetGR (struct _Unwind_Context *, int); extern void _Unwind_SetGR (struct _Unwind_Context *, int, _Unwind_Word); extern _Unwind_Ptr _Unwind_GetIP (struct _Unwind_Context *); +extern _Unwind_Ptr _Unwind_GetIPInfo (struct _Unwind_Context *, int *); extern void _Unwind_SetIP (struct _Unwind_Context *, _Unwind_Ptr); /* @@@ Retrieve the CFA of the given context. */ diff --git a/gcc/unwind-sjlj.c b/gcc/unwind-sjlj.c index 4c06aa1f894..72c363c7af1 100644 --- a/gcc/unwind-sjlj.c +++ b/gcc/unwind-sjlj.c @@ -214,6 +214,13 @@ _Unwind_GetIP (struct _Unwind_Context *context) return context->fc->call_site + 1; } +_Unwind_Ptr +_Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn) +{ + *ip_before_insn = 0; + return context->fc->call_site + 1; +} + /* Set the return landing pad index in CONTEXT. */ void |