+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>
<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. */
}
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]);
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;
#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];
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]);
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 */
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;
#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
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;
}
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;
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;
}