ARM Linux EABI: unwinding through a segfault handler
Andrew Haley
aph@redhat.com
Thu Aug 25 12:26:00 GMT 2011
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 <aph@redhat.com>
* 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)
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: segv.cc
URL: <https://gcc.gnu.org/pipermail/gcc/attachments/20110825/8525ba08/attachment.cc>
More information about the Gcc
mailing list