unwind-ia64.c (ia64_copy_rbs): New function.
* config/ia64/unwind-ia64.c (ia64_copy_rbs): New function. (unw_access_gr): Only call ia64_rse_rnat_addr if addr is above regstk_top. (uw_frame_state_for): Handle locations inside bundles. (uw_init_context_1): Initialize context->rnat. Set context->regstk_top to lowest rbs address which has nat collection in context->rnat. (uw_install_context): Fix rnat restoring. Restore ar.rsc to previous state. * config/ia64/linux.h (MD_FALLBACK_FRAME_STATE_FOR, MD_HANDLE_UNWABI): Handle unwinding through SA_ONSTACK frames. * gcc.dg/cleanup-10.c: New test. * gcc.dg/cleanup-11.c: New test. From-SVN: r74835
This commit is contained in:
parent
effed65516
commit
e8c89d2970
|
@ -1,3 +1,17 @@
|
|||
2003-12-19 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* config/ia64/unwind-ia64.c (ia64_copy_rbs): New function.
|
||||
(unw_access_gr): Only call ia64_rse_rnat_addr if addr is above
|
||||
regstk_top.
|
||||
(uw_frame_state_for): Handle locations inside bundles.
|
||||
(uw_init_context_1): Initialize context->rnat.
|
||||
Set context->regstk_top to lowest rbs address which has nat collection
|
||||
in context->rnat.
|
||||
(uw_install_context): Fix rnat restoring.
|
||||
Restore ar.rsc to previous state.
|
||||
* config/ia64/linux.h (MD_FALLBACK_FRAME_STATE_FOR,
|
||||
MD_HANDLE_UNWABI): Handle unwinding through SA_ONSTACK frames.
|
||||
|
||||
2003-12-19 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR c++/13239
|
||||
|
|
|
@ -97,7 +97,6 @@ do { \
|
|||
(CONTEXT)->br_loc[0] = &(sc_->sc_br[0]); \
|
||||
(CONTEXT)->br_loc[6] = &(sc_->sc_br[6]); \
|
||||
(CONTEXT)->br_loc[7] = &(sc_->sc_br[7]); \
|
||||
(CONTEXT)->bsp = sc_->sc_ar_bsp; \
|
||||
(CONTEXT)->pr = sc_->sc_pr; \
|
||||
(CONTEXT)->psp = sc_->sc_gr[12]; \
|
||||
(CONTEXT)->gp = sc_->sc_gr[1]; \
|
||||
|
@ -105,6 +104,22 @@ do { \
|
|||
other than what we adjust for below. */ \
|
||||
(FS) -> no_reg_stack_frame = 1; \
|
||||
\
|
||||
if (sc_->sc_rbs_base) \
|
||||
{ \
|
||||
/* Need to switch from alternate register backing store. */ \
|
||||
long ndirty, loadrs = sc_->sc_loadrs >> 16; \
|
||||
unsigned long alt_bspstore = (CONTEXT)->bsp - loadrs; \
|
||||
unsigned long bspstore; \
|
||||
unsigned long *ar_bsp = (unsigned long *)(sc_->sc_ar_bsp); \
|
||||
\
|
||||
ndirty = ia64_rse_num_regs ((unsigned long *) alt_bspstore, \
|
||||
(unsigned long *) (CONTEXT)->bsp);\
|
||||
bspstore = (unsigned long) \
|
||||
ia64_rse_skip_regs (ar_bsp, -ndirty); \
|
||||
ia64_copy_rbs ((CONTEXT), bspstore, alt_bspstore, loadrs, \
|
||||
sc_->sc_ar_rnat); \
|
||||
} \
|
||||
\
|
||||
/* Don't touch the branch registers o.t. b0, b6 and b7. \
|
||||
The kernel doesn't pass the preserved branch registers \
|
||||
in the sigcontext but leaves them intact, so there's no \
|
||||
|
@ -154,13 +169,28 @@ do { \
|
|||
(CONTEXT)->br_loc[0] = &(sc_->sc_br[0]); \
|
||||
(CONTEXT)->br_loc[6] = &(sc_->sc_br[6]); \
|
||||
(CONTEXT)->br_loc[7] = &(sc_->sc_br[7]); \
|
||||
(CONTEXT)->bsp = sc_->sc_ar_bsp; \
|
||||
(CONTEXT)->pr = sc_->sc_pr; \
|
||||
(CONTEXT)->gp = sc_->sc_gr[1]; \
|
||||
/* Signal frame doesn't have an associated reg. stack frame \
|
||||
other than what we adjust for below. */ \
|
||||
(FS) -> no_reg_stack_frame = 1; \
|
||||
\
|
||||
if (sc_->sc_rbs_base) \
|
||||
{ \
|
||||
/* Need to switch from alternate register backing store. */ \
|
||||
long ndirty, loadrs = sc_->sc_loadrs >> 16; \
|
||||
unsigned long alt_bspstore = (CONTEXT)->bsp - loadrs; \
|
||||
unsigned long bspstore; \
|
||||
unsigned long *ar_bsp = (unsigned long *)(sc_->sc_ar_bsp); \
|
||||
\
|
||||
ndirty = ia64_rse_num_regs ((unsigned long *) alt_bspstore, \
|
||||
(unsigned long *) (CONTEXT)->bsp);\
|
||||
bspstore = (unsigned long) \
|
||||
ia64_rse_skip_regs (ar_bsp, -ndirty); \
|
||||
ia64_copy_rbs ((CONTEXT), bspstore, alt_bspstore, loadrs, \
|
||||
sc_->sc_ar_rnat); \
|
||||
} \
|
||||
\
|
||||
/* Don't touch the branch registers o.t. b0, b6 and b7. \
|
||||
The kernel doesn't pass the preserved branch registers \
|
||||
in the sigcontext but leaves them intact, so there's no \
|
||||
|
|
|
@ -184,7 +184,8 @@ struct _Unwind_Context
|
|||
{
|
||||
/* Initial frame info. */
|
||||
unsigned long rnat; /* rse nat collection */
|
||||
unsigned long regstk_top; /* bsp for first frame */
|
||||
unsigned long regstk_top; /* lowest address of rbs stored register
|
||||
which uses context->rnat collection */
|
||||
|
||||
/* Current frame info. */
|
||||
unsigned long bsp; /* backing store pointer value
|
||||
|
@ -1492,6 +1493,80 @@ ia64_rse_skip_regs (unsigned long *addr, long num_regs)
|
|||
}
|
||||
|
||||
|
||||
/* Copy register backing store from SRC to DST, LEN words
|
||||
(which include both saved registers and nat collections).
|
||||
DST_RNAT is a partial nat collection for DST. SRC and DST
|
||||
don't have to be equal modulo 64 slots, so it cannot be
|
||||
done with a simple memcpy as the nat collections will be
|
||||
at different relative offsets and need to be combined together. */
|
||||
static void
|
||||
ia64_copy_rbs (struct _Unwind_Context *info, unsigned long dst,
|
||||
unsigned long src, long len, unsigned long dst_rnat)
|
||||
{
|
||||
long count;
|
||||
unsigned long src_rnat;
|
||||
unsigned long shift1, shift2;
|
||||
|
||||
len <<= 3;
|
||||
dst_rnat &= (1UL << ((dst >> 3) & 0x3f)) - 1;
|
||||
src_rnat = src >= info->regstk_top
|
||||
? info->rnat : *(unsigned long *) (src | 0x1f8);
|
||||
src_rnat &= ~((1UL << ((src >> 3) & 0x3f)) - 1);
|
||||
/* Just to make sure. */
|
||||
src_rnat &= ~(1UL << 63);
|
||||
shift1 = ((dst - src) >> 3) & 0x3f;
|
||||
if ((dst & 0x1f8) < (src & 0x1f8))
|
||||
shift1--;
|
||||
shift2 = 0x3f - shift1;
|
||||
if ((dst & 0x1f8) >= (src & 0x1f8))
|
||||
{
|
||||
count = ~dst & 0x1f8;
|
||||
goto first;
|
||||
}
|
||||
count = ~src & 0x1f8;
|
||||
goto second;
|
||||
while (len > 0)
|
||||
{
|
||||
src_rnat = src >= info->regstk_top
|
||||
? info->rnat : *(unsigned long *) (src | 0x1f8);
|
||||
/* Just to make sure. */
|
||||
src_rnat &= ~(1UL << 63);
|
||||
count = shift2 << 3;
|
||||
first:
|
||||
if (count > len)
|
||||
count = len;
|
||||
memcpy ((char *) dst, (char *) src, count);
|
||||
dst += count;
|
||||
src += count;
|
||||
len -= count;
|
||||
dst_rnat |= (src_rnat << shift1) & ~(1UL << 63);
|
||||
if (len <= 0)
|
||||
break;
|
||||
*(long *) dst = dst_rnat;
|
||||
dst += 8;
|
||||
dst_rnat = 0;
|
||||
count = shift1 << 3;
|
||||
second:
|
||||
if (count > len)
|
||||
count = len;
|
||||
memcpy ((char *) dst, (char *) src, count);
|
||||
dst += count;
|
||||
src += count + 8;
|
||||
len -= count + 8;
|
||||
dst_rnat |= (src_rnat >> shift2);
|
||||
}
|
||||
if ((dst & 0x1f8) == 0x1f8)
|
||||
{
|
||||
*(long *) dst = dst_rnat;
|
||||
dst += 8;
|
||||
dst_rnat = 0;
|
||||
}
|
||||
/* Set info->regstk_top to lowest rbs address which will use
|
||||
info->rnat collection. */
|
||||
info->regstk_top = dst & ~0x1ffUL;
|
||||
info->rnat = dst_rnat;
|
||||
}
|
||||
|
||||
/* Unwind accessors. */
|
||||
|
||||
static void
|
||||
|
@ -1551,9 +1626,10 @@ unw_access_gr (struct _Unwind_Context *info, int regnum,
|
|||
break;
|
||||
|
||||
case UNW_NAT_REGSTK:
|
||||
nat_addr = ia64_rse_rnat_addr (addr);
|
||||
if ((unsigned long) nat_addr >= info->regstk_top)
|
||||
if ((unsigned long) addr >= info->regstk_top)
|
||||
nat_addr = &info->rnat;
|
||||
else
|
||||
nat_addr = ia64_rse_rnat_addr (addr);
|
||||
nat_mask = 1UL << ia64_rse_slot_num (addr);
|
||||
break;
|
||||
}
|
||||
|
@ -1563,9 +1639,10 @@ unw_access_gr (struct _Unwind_Context *info, int regnum,
|
|||
{
|
||||
/* Access a stacked register. */
|
||||
addr = ia64_rse_skip_regs ((unsigned long *) info->bsp, regnum - 32);
|
||||
nat_addr = ia64_rse_rnat_addr (addr);
|
||||
if ((unsigned long) nat_addr >= info->regstk_top)
|
||||
if ((unsigned long) addr >= info->regstk_top)
|
||||
nat_addr = &info->rnat;
|
||||
else
|
||||
nat_addr = ia64_rse_rnat_addr (addr);
|
||||
nat_mask = 1UL << ia64_rse_slot_num (addr);
|
||||
}
|
||||
|
||||
|
@ -1724,7 +1801,8 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
|
|||
}
|
||||
|
||||
context->region_start = ent->start_offset + segment_base;
|
||||
fs->when_target = (context->rp - context->region_start) / 16 * 3;
|
||||
fs->when_target = ((context->rp & -16) - context->region_start) / 16 * 3
|
||||
+ (context->rp & 15);
|
||||
|
||||
unw = (unsigned long *) (ent->info_offset + segment_base);
|
||||
header = *unw;
|
||||
|
@ -1998,18 +2076,31 @@ uw_init_context_1 (struct _Unwind_Context *context, void *bsp)
|
|||
/* Set psp to the caller's stack pointer. */
|
||||
void *psp = __builtin_dwarf_cfa () - 16;
|
||||
_Unwind_FrameState fs;
|
||||
unsigned long rnat, tmp1, tmp2;
|
||||
|
||||
/* Flush the register stack to memory so that we can access it. */
|
||||
__builtin_ia64_flushrs ();
|
||||
/* Flush the register stack to memory so that we can access it.
|
||||
Get rse nat collection for the last incomplete rbs chunk of
|
||||
registers at the same time. For this RSE needs to be turned
|
||||
into the mandatory only mode. */
|
||||
asm ("mov.m %1 = ar.rsc;;\n\t"
|
||||
"and %2 = 0x1c, %1;;\n\t"
|
||||
"mov.m ar.rsc = %2;;\n\t"
|
||||
"flushrs;;\n\t"
|
||||
"mov.m %0 = ar.rnat;;\n\t"
|
||||
"mov.m ar.rsc = %1\n\t"
|
||||
: "=r" (rnat), "=r" (tmp1), "=r" (tmp2));
|
||||
|
||||
memset (context, 0, sizeof (struct _Unwind_Context));
|
||||
context->bsp = context->regstk_top = (unsigned long) bsp;
|
||||
context->bsp = (unsigned long) bsp;
|
||||
/* Set context->regstk_top to lowest rbs address which will use
|
||||
context->rnat collection. */
|
||||
context->regstk_top = context->bsp & ~0x1ffULL;
|
||||
context->rnat = rnat;
|
||||
context->psp = (unsigned long) psp;
|
||||
context->rp = (unsigned long) rp;
|
||||
asm ("mov %0 = sp" : "=r" (context->sp));
|
||||
asm ("mov %0 = pr" : "=r" (context->pr));
|
||||
context->pri_unat_loc = &context->initial_unat; /* ??? */
|
||||
/* ??? Get rnat. Don't we have to turn off the rse for that? */
|
||||
|
||||
if (uw_frame_state_for (context, &fs) != _URC_NO_REASON)
|
||||
abort ();
|
||||
|
@ -2050,6 +2141,9 @@ uw_install_context (struct _Unwind_Context *current __attribute__((unused)),
|
|||
ia64_rse_skip_regs ((unsigned long *)target->bsp,
|
||||
(*target->pfs_loc >> 7) & 0x7f);
|
||||
|
||||
if (target->bsp < target->regstk_top)
|
||||
target->rnat = *ia64_rse_rnat_addr ((unsigned long *) target->bsp);
|
||||
|
||||
/* Provide assembly with the offsets into the _Unwind_Context. */
|
||||
asm volatile ("uc_rnat = %0"
|
||||
: : "i"(offsetof (struct _Unwind_Context, rnat)));
|
||||
|
@ -2251,10 +2345,10 @@ uw_install_context (struct _Unwind_Context *current __attribute__((unused)),
|
|||
"mov.m r25 = ar.rsc \n\t"
|
||||
"(p6) mov.m ar.fpsr = r30 \n\t"
|
||||
";; \n\t"
|
||||
"and r25 = 0x1c, r25 \n\t"
|
||||
"and r29 = 0x1c, r25 \n\t"
|
||||
"mov b0 = r26 \n\t"
|
||||
";; \n\t"
|
||||
"mov.m ar.rsc = r25 \n\t"
|
||||
"mov.m ar.rsc = r29 \n\t"
|
||||
";; \n\t"
|
||||
/* This must be done before setting AR.BSPSTORE, otherwise
|
||||
AR.BSP will be initialized with a random displacement
|
||||
|
@ -2265,7 +2359,6 @@ uw_install_context (struct _Unwind_Context *current __attribute__((unused)),
|
|||
";; \n\t"
|
||||
"mov.m ar.bspstore = r23 \n\t"
|
||||
";; \n\t"
|
||||
"or r25 = 0x3, r25 \n\t"
|
||||
"mov.m ar.rnat = r22 \n\t"
|
||||
";; \n\t"
|
||||
"mov.m ar.rsc = r25 \n\t"
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
2003-12-19 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* gcc.dg/cleanup-10.c: New test.
|
||||
* gcc.dg/cleanup-11.c: New test.
|
||||
|
||||
2003-12-19 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR c++/13239
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
/* { dg-do run { target i?86-*-linux* x86_64-*-linux* ia64-*-linux* alpha*-*-linux* powerpc*-*-linux* s390*-*-linux* sparc*-*-linux* mips*-*-linux* } } */
|
||||
/* { dg-options "-fasynchronous-unwind-tables -fexceptions -O2" } */
|
||||
/* Verify that cleanups work with exception handling through signal frames
|
||||
on alternate stack. */
|
||||
|
||||
#include <unwind.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.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, siginfo_t *info, void *ctx)
|
||||
{
|
||||
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 ()
|
||||
{
|
||||
stack_t ss;
|
||||
struct sigaction s;
|
||||
|
||||
ss.ss_size = 4 * sysconf (_SC_PAGESIZE);
|
||||
if (ss.ss_size < SIGSTKSZ)
|
||||
ss.ss_size = SIGSTKSZ;
|
||||
ss.ss_sp = malloc (ss.ss_size);
|
||||
if (ss.ss_sp == NULL)
|
||||
exit (1);
|
||||
ss.ss_flags = 0;
|
||||
if (sigaltstack (&ss, NULL) < 0)
|
||||
exit (1);
|
||||
|
||||
sigemptyset (&s.sa_mask);
|
||||
s.sa_sigaction = fn4;
|
||||
s.sa_flags = SA_ONESHOT | SA_ONSTACK;
|
||||
sigaction (SIGSEGV, &s, NULL);
|
||||
fn2 ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __attribute__((noinline)) fn0 ()
|
||||
{
|
||||
char dummy __attribute__((cleanup (handler)));
|
||||
fn1 ();
|
||||
null = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
fn0 ();
|
||||
abort ();
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
/* { dg-do run { target i?86-*-linux* x86_64-*-linux* ia64-*-linux* alpha*-*-linux* powerpc*-*-linux* s390*-*-linux* sparc*-*-linux* mips*-*-linux* } } */
|
||||
/* { dg-options "-fasynchronous-unwind-tables -fexceptions -O2" } */
|
||||
/* Verify that cleanups work with exception handling through realtime signal
|
||||
frames on alternate stack. */
|
||||
|
||||
#include <unwind.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.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, siginfo_t *info, void *ctx)
|
||||
{
|
||||
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 ()
|
||||
{
|
||||
stack_t ss;
|
||||
struct sigaction s;
|
||||
|
||||
ss.ss_size = 4 * sysconf (_SC_PAGESIZE);
|
||||
if (ss.ss_size < SIGSTKSZ)
|
||||
ss.ss_size = SIGSTKSZ;
|
||||
ss.ss_sp = malloc (ss.ss_size);
|
||||
if (ss.ss_sp == NULL)
|
||||
exit (1);
|
||||
ss.ss_flags = 0;
|
||||
if (sigaltstack (&ss, NULL) < 0)
|
||||
exit (1);
|
||||
|
||||
sigemptyset (&s.sa_mask);
|
||||
s.sa_sigaction = fn4;
|
||||
s.sa_flags = SA_ONESHOT | SA_ONSTACK | SA_SIGINFO;
|
||||
sigaction (SIGSEGV, &s, NULL);
|
||||
fn2 ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __attribute__((noinline)) fn0 ()
|
||||
{
|
||||
char dummy __attribute__((cleanup (handler)));
|
||||
fn1 ();
|
||||
null = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
fn0 ();
|
||||
abort ();
|
||||
}
|
Loading…
Reference in New Issue