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:
Jakub Jelinek 2003-12-19 15:00:53 +01:00 committed by Jakub Jelinek
parent effed65516
commit e8c89d2970
6 changed files with 385 additions and 15 deletions

View File

@ -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

View File

@ -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 \

View File

@ -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"

View File

@ -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

View File

@ -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 ();
}

View File

@ -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 ();
}