This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
ppc64 unwinding problem
- From: Jakub Jelinek <jakub at redhat dot com>
- To: Richard Henderson <rth at redhat dot com>, David Edelsohn <dje at watson dot ibm dot com>
- Cc: gcc at gcc dot gnu dot org
- Date: Fri, 11 Jul 2003 22:57:37 +0200
- Subject: ppc64 unwinding problem
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
Hi!
Although ppc64-linux defines MD_FALLBACK_FRAME_STATE_FOR, it cannot unwind
through signal handlers.
The problem is rs6000_emit_eh_toc_restore, which during __builtin_eh_return
emits a loop to restore r2 register (which is never noted in FDEs,
as it is a register under linker's control, not compiler).
This loop has the AIX ABI assumptions, ie. that word at $r1 contains
saved $r1, 16($r1) is saved lr and 40($r1) is saved $r2.
Unfortunately this cannot work with MD_FALLBACK_FRAME_STATE_FOR, as
signal handler frame does not follow AIX calling convention and thus
the loop generated by __builtin_eh_return segfaults.
This is very bad, not only because some libgcj stuff does not work
(there are other bugs on ppc64 in gcj), but because NPTL relies on this.
I think adding code to __builtin_eh_return to recognize and handle
linux signal frames would be way too ugly (and would mean basically
duplicating MD_FALLBACK_FRAME_STATE_FOR functionality, though in RTL),
so as a different alternative I see adding some MD_CFA_PROGRAM macro
which would do an implicit CFA operation (I don't think
if (*($r1 + 16) == 0xE8410028) DW_CFA_offset (2, -40); else do nothing
is expressible in Dwarf2) either before or after executing CIE CFA program.
What do you think about that?
/* { dg-do run { target i?86-*-linux* x86_64-*-linux* ia64-*-linux* alpha*-*-linux* powerpc*-*-linux* s390*-*-linux* sparc*-*-linux* } } */
/* { dg-options "-fasynchronous-unwind-tables -fexceptions -O2" } */
/* Verify that cleanups work with exception handling through signal
frames. */
#include <unwind.h>
#include <stdlib.h>
#include <signal.h>
static _Unwind_Reason_Code
force_unwind_stop (int version, _Unwind_Action actions,
_Unwind_Exception_Class exc_class,
struct _Unwind_Exception *exc_obj,
struct _Unwind_Context *context,
void *stop_parameter)
{
if (actions & _UA_END_OF_STACK)
abort ();
return _URC_NO_REASON;
}
static void force_unwind ()
{
struct _Unwind_Exception *exc = malloc (sizeof (*exc));
exc->exception_class = 0;
exc->exception_cleanup = 0;
#ifndef __USING_SJLJ_EXCEPTIONS__
_Unwind_ForcedUnwind (exc, force_unwind_stop, 0);
#else
_Unwind_SjLj_ForcedUnwind (exc, force_unwind_stop, 0);
#endif
abort ();
}
int count;
char *null;
static void counter (void *p __attribute__((unused)))
{
++count;
}
static void handler (void *p __attribute__((unused)))
{
if (count != 2)
abort ();
exit (0);
}
static int __attribute__((noinline)) fn5 ()
{
char dummy __attribute__((cleanup (counter)));
force_unwind ();
return 0;
}
static void fn4 (int sig)
{
char dummy __attribute__((cleanup (counter)));
fn5 ();
null = NULL;
}
static void fn3 ()
{
abort ();
}
static int __attribute__((noinline)) fn2 ()
{
*null = 0;
fn3 ();
return 0;
}
static int __attribute__((noinline)) fn1 ()
{
signal (SIGSEGV, fn4);
fn2 ();
return 0;
}
static int __attribute__((noinline)) fn0 ()
{
char dummy __attribute__((cleanup (handler)));
fn1 ();
null = 0;
return 0;
}
int main()
{
fn0 ();
abort ();
}
Jakub