ARM Linux EABI: unwinding through a segfault handler
Throwing an exception through a segfault handler doesn't always work on ARM: the attached example fails on current gcc trunk. panda-9:~ $ g++ segv.cc -fnon-call-exceptions -g panda-9:~ $ ./a.out terminate called after throwing an instance of 'FoobarException*' Aborted The bug is that _Unwind_GetIPInfo doesn't correctly set ip_before_insn. Instead, it always sets it to zero; it should be set to 1 if this is a frame created by a signal handler: #define _Unwind_GetIPInfo(context, ip_before_insn) \ (*ip_before_insn = 0, _Unwind_GetGR (context, 15) & ~(_Unwind_Word)1) Fixing this on ARM is hard because signal frames aren't specially marked as they are on systems that use DWARF unwinder data. I have a patch that works on systems where the signal restorer is exactly mov r7, $SYS_rt_sigreturn swi 0x0 It works as a proof of concept, but it's fugly. So, suggestions welcome. Is there a nice way to detect a signal frame? Andrew. 2011-08-25 Andrew Haley * config/arm/unwind-arm.h (_Unwind_IsSignalFrame): New. (_Unwind_GetIPInfo): Use _Unwind_IsSignalFrame. * config/arm/unwind-arm.c (UCB_SIGNAL_FRAME): New def. (get_eit_entry): Update UCB_SIGNAL_FRAME. (_Unwind_IsSignalFrame): New function. Index: config/arm/unwind-arm.c === --- config/arm/unwind-arm.c (revision 178028) +++ config/arm/unwind-arm.c (working copy) @@ -61,6 +61,7 @@ #define UCB_PR_ADDR(ucbp) ((ucbp)->unwinder_cache.reserved2) #define UCB_SAVED_CALLSITE_ADDR(ucbp) ((ucbp)->unwinder_cache.reserved3) #define UCB_FORCED_STOP_ARG(ucbp) ((ucbp)->unwinder_cache.reserved4) +#define UCB_SIGNAL_FRAME(ucbp) ((ucbp)->unwinder_cache.reserved5) struct core_regs { @@ -595,7 +596,14 @@ { const __EIT_entry * eitp; int nrec; - + + { +_uw *pc = (_uw *)(return_address & ~3); + UCB_SIGNAL_FRAME(ucbp) <<= 1; + UCB_SIGNAL_FRAME(ucbp) + |= pc[0] == 0xe3a070ad && pc[1] == 0xef00; + } + /* The return address is the address of the instruction following the call instruction (plus one in thumb mode). If this was the last instruction in the function the address will lie in the following @@ -941,6 +949,15 @@ } +_Unwind_Word +_Unwind_IsSignalFrame (_Unwind_Context *context) +{ + _Unwind_Control_Block *ucbp += (_Unwind_Control_Block *)_Unwind_GetGR (context, 12); + return (UCB_SIGNAL_FRAME (ucbp) & 2) != 0; +} + + /* Free an exception. */ void Index: config/arm/unwind-arm.h === --- config/arm/unwind-arm.h (revision 178028) +++ config/arm/unwind-arm.h (working copy) @@ -217,6 +217,8 @@ _Unwind_Reason_Code __gnu_unwind_execute (_Unwind_Context *, __gnu_unwind_state *); + _Unwind_Word _Unwind_IsSignalFrame (_Unwind_Context *context); + /* Decode an R_ARM_TARGET2 relocation. */ static inline _Unwind_Word _Unwind_decode_target2 (_Unwind_Word ptr) @@ -254,7 +256,8 @@ (_Unwind_GetGR (context, 15) & ~(_Unwind_Word)1) #define _Unwind_GetIPInfo(context, ip_before_insn) \ - (*ip_before_insn = 0, _Unwind_GetGR (context, 15) & ~(_Unwind_Word)1) +(*ip_before_insn = _Unwind_IsSignalFrame (context), \ + _Unwind_GetGR (context, 15) & ~(_Unwind_Word)1) static inline void _Unwind_SetGR (_Unwind_Context *context, int regno, _Unwind_Word val) #define _POSIX_SOURCE #include #include int *a; class FoobarException { int thingy; }; void signal_handler(int signum, siginfo_t *info, void *) { FoobarException *f = new FoobarException; throw f; } int main() { struct sigaction act; act.sa_sigaction = signal_handler; sigemptyset (&act.sa_mask); act.sa_flags = SA_SIGINFO; sigaction (11, &act, NULL); try { printf("%d\n", *a); } catch (FoobarException *f) { printf("Hello!\n"); } }
Re: ARM Linux EABI: unwinding through a segfault handler
On 08/25/2011 05:26 AM, Andrew Haley wrote: Throwing an exception through a segfault handler doesn't always work on ARM: the attached example fails on current gcc trunk. panda-9:~ $ g++ segv.cc -fnon-call-exceptions -g panda-9:~ $ ./a.out terminate called after throwing an instance of 'FoobarException*' Aborted The bug is that _Unwind_GetIPInfo doesn't correctly set ip_before_insn. Instead, it always sets it to zero; it should be set to 1 if this is a frame created by a signal handler: #define _Unwind_GetIPInfo(context, ip_before_insn) \ (*ip_before_insn = 0, _Unwind_GetGR (context, 15)& ~(_Unwind_Word)1) Fixing this on ARM is hard because signal frames aren't specially marked as they are on systems that use DWARF unwinder data. I have a patch that works on systems where the signal restorer is exactly mov r7, $SYS_rt_sigreturn swi 0x0 It works as a proof of concept, but it's fugly. For what it's worth, I did the equivalent on MIPS. Once you do this, it is a de facto ABI. Probably the ARM linux maintainers should be consulted to see if they are willing to consider the possibility of never changing it. I think all Linux ABIs should support unwinding through signal handlers, so adding this makes sense to me. David Daney So, suggestions welcome. Is there a nice way to detect a signal frame?
Re: ARM Linux EABI: unwinding through a segfault handler
On 08/25/2011 05:57 PM, David Daney wrote: > On 08/25/2011 05:26 AM, Andrew Haley wrote: >> Throwing an exception through a segfault handler doesn't always work >> on ARM: the attached example fails on current gcc trunk. >> >> panda-9:~ $ g++ segv.cc -fnon-call-exceptions -g >> panda-9:~ $ ./a.out >> terminate called after throwing an instance of 'FoobarException*' >> Aborted >> >> The bug is that _Unwind_GetIPInfo doesn't correctly set ip_before_insn. >> Instead, it always sets it to zero; it should be set to 1 if this >> is a frame created by a signal handler: >> >> >> #define _Unwind_GetIPInfo(context, ip_before_insn) \ >>(*ip_before_insn = 0, _Unwind_GetGR (context, 15)& ~(_Unwind_Word)1) >> >> >> Fixing this on ARM is hard because signal frames aren't specially >> marked as they are on systems that use DWARF unwinder data. I have >> a patch that works on systems where the signal restorer is exactly >> >> mov r7, $SYS_rt_sigreturn >> swi 0x0 >> >> It works as a proof of concept, but it's fugly. > > For what it's worth, I did the equivalent on MIPS. > > Once you do this, it is a de facto ABI. Probably the ARM linux > maintainers should be consulted to see if they are willing to consider > the possibility of never changing it. I think Joseph Meyers is the author of both ends of this, and I think he reads this list. Andrew.
gcc-4.5-20110825 is now available
Snapshot gcc-4.5-20110825 is now available on ftp://gcc.gnu.org/pub/gcc/snapshots/4.5-20110825/ and on various mirrors, see http://gcc.gnu.org/mirrors.html for details. This snapshot has been generated from the GCC 4.5 SVN branch with the following options: svn://gcc.gnu.org/svn/gcc/branches/gcc-4_5-branch revision 178088 You'll find: gcc-4.5-20110825.tar.bz2 Complete GCC MD5=23b2bfbc5e78c3a89aa9922a6630cbf0 SHA1=38948ecf5287ad03c0a459b1f89fac137c63c5b0 Diffs from 4.5-20110818 are available in the diffs/ subdirectory. When a particular snapshot is ready for public consumption the LATEST-4.5 link is updated and a message is sent to the gcc list. Please do not use a snapshot before it has been announced that way.