unwind-ia64.c (struct _Unwind_Context): Add new field 'signal_pfs_loc'.
authorEric Botcazou <ebotcazou@adacore.com>
Fri, 14 Aug 2009 20:49:40 +0000 (20:49 +0000)
committerDouglas Rupp <rupp@gcc.gnu.org>
Fri, 14 Aug 2009 20:49:40 +0000 (20:49 +0000)
* config/ia64/unwind-ia64.c (struct _Unwind_Context): Add new
field 'signal_pfs_loc'.
(uw_frame_state_for): Remove duplicate code dealing with leaf
procedures without unwind info.
If in the frame after unwinding through a signal handler, restore
the AR.PFS register instead of the CFM if AR.PFS has not been saved.
* config/ia64/linux-unwind.h (ia64_fallback_frame_state): Do not set
'pfs_loc' to the AR.PFS location in the signal context; instead
set 'signal_pfs_loc'.
Manually generate the unwind info for the AR.PFS register.
(ABI_MARKER_OLD_LINUX_SIGTRAMP, ABI_MARKER_OLD_LINUX_INTERRUPT,
ABI_MARKER_LINUX_SIGTRAMP, ABI_MARKER_LINUX_INTERRUPT): Define.
(ia64_handle_unwabi): Test 'fs->unwabi' against them.
Do not set 'pfs_loc' to the AR.PFS location in the signal context;
instead set 'signal_pfs_loc'.
Remove code preventing the AR.PFS register from being restored
from the signal context.

From-SVN: r150777

gcc/ChangeLog
gcc/config/ia64/linux-unwind.h
gcc/config/ia64/unwind-ia64.c

index f89660b..d2f328e 100644 (file)
@@ -1,3 +1,23 @@
+2009-08-14  Eric Botcazou  <ebotcazou@adacore.com>
+
+       * config/ia64/unwind-ia64.c (struct _Unwind_Context): Add new
+       field 'signal_pfs_loc'.
+       (uw_frame_state_for): Remove duplicate code dealing with leaf
+       procedures without unwind info.
+       If in the frame after unwinding through a signal handler, restore
+       the AR.PFS register instead of the CFM if AR.PFS has not been saved.
+       * config/ia64/linux-unwind.h (ia64_fallback_frame_state): Do not set
+       'pfs_loc' to the AR.PFS location in the signal context; instead
+       set 'signal_pfs_loc'.
+       Manually generate the unwind info for the AR.PFS register.
+       (ABI_MARKER_OLD_LINUX_SIGTRAMP, ABI_MARKER_OLD_LINUX_INTERRUPT,
+       ABI_MARKER_LINUX_SIGTRAMP, ABI_MARKER_LINUX_INTERRUPT): Define.
+       (ia64_handle_unwabi): Test 'fs->unwabi' against them.
+       Do not set 'pfs_loc' to the AR.PFS location in the signal context;
+       instead set 'signal_pfs_loc'.
+       Remove code preventing the AR.PFS register from being restored
+       from the signal context.
+
 2009-08-14  Douglas B Rupp  <rupp@gnat.com>
            Tristan Gingold  <gingold@adacore.com>
 
index e2bad48..93f762d 100644 (file)
@@ -23,7 +23,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 /* Do code reading to identify a signal frame, and set the frame
-   state data appropriately.  See unwind-dw2.c for the structs.  */
+   state data appropriately.  See unwind-ia64.c for the structs.  */
 
 /* This works only for glibc-2.3 and later, because sigcontext is different
    in glibc-2.2.4.  */
@@ -66,7 +66,7 @@ ia64_fallback_frame_state (struct _Unwind_Context *context,
       }
 
       context->fpsr_loc = &(sc->sc_ar_fpsr);
-      context->pfs_loc = &(sc->sc_ar_pfs);
+      context->signal_pfs_loc = &(sc->sc_ar_pfs);
       context->lc_loc = &(sc->sc_ar_lc);
       context->unat_loc = &(sc->sc_ar_unat);
       context->br_loc[0] = &(sc->sc_br[0]);
@@ -105,11 +105,17 @@ ia64_fallback_frame_state (struct _Unwind_Context *context,
          ia64_rse_skip_regs ((unsigned long *)(sc->sc_ar_bsp), -sof);
       }
 
+      /* Account for use of br.ret to resume execution of user code.  */
       fs->curr.reg[UNW_REG_RP].where = UNW_WHERE_SPREL;
       fs->curr.reg[UNW_REG_RP].val
        = (unsigned long)&(sc->sc_ip) - context->psp;
       fs->curr.reg[UNW_REG_RP].when = -1;
 
+      fs->curr.reg[UNW_REG_PFS].where = UNW_WHERE_SPREL;
+      fs->curr.reg[UNW_REG_PFS].val
+       = (unsigned long)&(sc->sc_cfm) - context->psp;
+      fs ->curr.reg[UNW_REG_PFS].when = -1;
+
       return _URC_NO_REASON;
     }
   return _URC_END_OF_STACK;
@@ -117,11 +123,16 @@ ia64_fallback_frame_state (struct _Unwind_Context *context,
 
 #define MD_HANDLE_UNWABI ia64_handle_unwabi
 
+#define ABI_MARKER_OLD_LINUX_SIGTRAMP  ((0 << 8) | 's')
+#define ABI_MARKER_OLD_LINUX_INTERRUPT ((0 << 8) | 'i')
+#define ABI_MARKER_LINUX_SIGTRAMP      ((3 << 8) | 's')
+#define ABI_MARKER_LINUX_INTERRUPT     ((3 << 8) | 'i')
+
 static void
 ia64_handle_unwabi (struct _Unwind_Context *context, _Unwind_FrameState *fs)
 {
-  if (fs->unwabi == ((3 << 8) | 's')
-      || fs->unwabi == ((0 << 8) | 's'))
+  if (fs->unwabi == ABI_MARKER_LINUX_SIGTRAMP
+      || fs->unwabi == ABI_MARKER_OLD_LINUX_SIGTRAMP)
     {
       struct sigframe {
        char scratch[16];
@@ -144,7 +155,7 @@ ia64_handle_unwabi (struct _Unwind_Context *context, _Unwind_FrameState *fs)
          context->ireg[i - 2].loc = &sc->sc_gr[i];
       }
 
-      context->pfs_loc = &(sc->sc_ar_pfs);
+      context->signal_pfs_loc = &(sc->sc_ar_pfs);
       context->lc_loc = &(sc->sc_ar_lc);
       context->unat_loc = &(sc->sc_ar_unat);
       context->br_loc[0] = &(sc->sc_br[0]);
@@ -181,9 +192,8 @@ ia64_handle_unwabi (struct _Unwind_Context *context, _Unwind_FrameState *fs)
          ia64_rse_skip_regs ((unsigned long *)(sc->sc_ar_bsp), -sof);
       }
 
-      /* pfs_loc already set above.  Without this pfs_loc would point
-        incorrectly to sc_cfm instead of sc_ar_pfs.  */
-      fs->curr.reg[UNW_REG_PFS].where = UNW_WHERE_NONE;
+      /* The use of br.ret to resume execution of user code is already
+        accounted for in the unwind ABI.  */
     }
 }
 #endif /* glibc-2.3 or better */
index d69b7fc..8e62f32 100644 (file)
@@ -204,6 +204,9 @@ struct _Unwind_Context
   unsigned long *pfs_loc;      /* Save location for pfs in current
                                   (corr. to sp) frame.  Target
                                   contains cfm for caller.     */
+  unsigned long *signal_pfs_loc;/* Save location for pfs in current
+                                  signal frame.  Target contains
+                                  pfs for caller.  */
   unsigned long *pri_unat_loc;
   unsigned long *unat_loc;
   unsigned long *lc_loc;
@@ -1786,6 +1789,7 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
 #ifdef MD_FALLBACK_FRAME_STATE_FOR
       if (MD_FALLBACK_FRAME_STATE_FOR (context, fs) == _URC_NO_REASON)
        return _URC_NO_REASON;
+#endif
 
       /* [SCRA 11.4.1] A leaf function with no memory stack, no exception
         handlers, and which keeps the return value in B0 does not need
@@ -1794,15 +1798,11 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
         This can only happen in the frame after unwinding through a signal
         handler.  Avoid infinite looping by requiring that B0 != RP.
         RP == 0 terminates the chain.  */
-      if (context->br_loc[0] && *context->br_loc[0] != context->rp
+      if (context->br_loc[0]
+         && *context->br_loc[0] != context->rp
          && context->rp != 0)
-       {
-         fs->curr.reg[UNW_REG_RP].where = UNW_WHERE_BR;
-         fs->curr.reg[UNW_REG_RP].when = -1;
-         fs->curr.reg[UNW_REG_RP].val = 0;
-         return _URC_NO_REASON;
-       }
-#endif
+       goto skip_unwind_info;
+
       return _URC_END_OF_STACK;
     }
 
@@ -1850,7 +1850,8 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
          r->where = UNW_WHERE_NONE;
     }
 
-  /* If RP did't get saved, generate entry for the return link register.  */
+skip_unwind_info:
+  /* If RP didn't get saved, generate entry for the return link register.  */
   if (fs->curr.reg[UNW_REG_RP].when >= fs->when_target)
     {
       fs->curr.reg[UNW_REG_RP].where = UNW_WHERE_BR;
@@ -1858,6 +1859,27 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
       fs->curr.reg[UNW_REG_RP].val = fs->return_link_reg;
     }
 
+  /* There is a subtlety for the frame after unwinding through a signal
+     handler: should we restore the cfm as usual or the pfs?  We can't
+     restore both because we use br.ret to resume execution of user code.
+     For other frames the procedure is by definition non-leaf so the pfs
+     is saved and restored and thus effectively dead in the body; only
+     the cfm need therefore be restored.
+     
+     Here we have 2 cases:
+       - either the pfs is saved and restored and thus effectively dead
+        like in regular frames; then we do nothing special and restore
+        the cfm.
+       - or the pfs is not saved and thus live; but in that case the
+        procedure is necessarily leaf so the cfm is effectively dead
+        and we restore the pfs.  */
+  if (context->signal_pfs_loc)
+    {
+      if (fs->curr.reg[UNW_REG_PFS].when >= fs->when_target)
+       context->pfs_loc = context->signal_pfs_loc;
+      context->signal_pfs_loc = NULL;
+    }
+
   return _URC_NO_REASON;
 }