]> gcc.gnu.org Git - gcc.git/commitdiff
unwind-ia64.c (ia64_copy_rbs): New function.
authorJakub Jelinek <jakub@redhat.com>
Fri, 19 Dec 2003 14:00:53 +0000 (15:00 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Fri, 19 Dec 2003 14:00:53 +0000 (15:00 +0100)
* 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

gcc/ChangeLog
gcc/config/ia64/linux.h
gcc/config/ia64/unwind-ia64.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/cleanup-10.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/cleanup-11.c [new file with mode: 0644]

index dec8a807a4b7aa46465dfd7b836c3a74c124c428..ac10544a42db7ae0c19600b14e9a3b6041dc91a7 100644 (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
index d456ea5f52e30f9ed600649ec0450ef3ee68baff..fc7df808188211b947254b53af8c6be6b48c442c 100644 (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        \
index 4de326383675c99a509941ef7b198e3e43ae029d..29c63fa13a7d2e5e301d3206a4f7ad714bd5e738 100644 (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)
 }
 
 \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
@@ -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;
-
-  /* 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 ();
@@ -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"
index 3010412fce19b631322831608df82fe28a77658b..33e006ec38647ed239af0ce7faed012c17c478f9 100644 (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
diff --git a/gcc/testsuite/gcc.dg/cleanup-10.c b/gcc/testsuite/gcc.dg/cleanup-10.c
new file mode 100644 (file)
index 0000000..39923fd
--- /dev/null
@@ -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 ();
+}
diff --git a/gcc/testsuite/gcc.dg/cleanup-11.c b/gcc/testsuite/gcc.dg/cleanup-11.c
new file mode 100644 (file)
index 0000000..9c47f6c
--- /dev/null
@@ -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 ();
+}
This page took 0.089401 seconds and 5 git commands to generate.