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] == 0xef000000; + } + /* 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)