* 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
+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
(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]; \
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 \
(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 \
{
/* 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
}
\f
+/* 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
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;
}
{
/* 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);
}
}
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;
/* Set psp to the caller's stack pointer. */
void *psp = __builtin_dwarf_cfa () - 16;
_Unwind_FrameState fs;
-
- /* Flush the register stack to memory so that we can access it. */
- __builtin_ia64_flushrs ();
+ unsigned long rnat, tmp1, tmp2;
+
+ /* 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 ();
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)));
"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
";; \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"
+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
--- /dev/null
+/* { 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 ();
+}
--- /dev/null
+/* { 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 ();
+}