aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog20
-rw-r--r--gcc/config/ia64/linux-unwind.h26
-rw-r--r--gcc/config/ia64/unwind-ia64.c40
3 files changed, 69 insertions, 17 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index f89660b..d2f328e 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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>
diff --git a/gcc/config/ia64/linux-unwind.h b/gcc/config/ia64/linux-unwind.h
index e2bad48..93f762d 100644
--- a/gcc/config/ia64/linux-unwind.h
+++ b/gcc/config/ia64/linux-unwind.h
@@ -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 */
diff --git a/gcc/config/ia64/unwind-ia64.c b/gcc/config/ia64/unwind-ia64.c
index d69b7fc..8e62f32 100644
--- a/gcc/config/ia64/unwind-ia64.c
+++ b/gcc/config/ia64/unwind-ia64.c
@@ -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;
}