From ac77b88e5267498679463fb578fe89ba973977e2 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Fri, 14 Aug 2009 20:49:40 +0000 Subject: [PATCH] unwind-ia64.c (struct _Unwind_Context): Add new field 'signal_pfs_loc'. * 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 | 20 +++++++++++++++++ gcc/config/ia64/linux-unwind.h | 26 +++++++++++++++------- gcc/config/ia64/unwind-ia64.c | 40 ++++++++++++++++++++++++++-------- 3 files changed, 69 insertions(+), 17 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f89660bbc20..d2f328e3499 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,23 @@ +2009-08-14 Eric Botcazou + + * 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 Tristan Gingold diff --git a/gcc/config/ia64/linux-unwind.h b/gcc/config/ia64/linux-unwind.h index e2bad480b72..93f762de573 100644 --- a/gcc/config/ia64/linux-unwind.h +++ b/gcc/config/ia64/linux-unwind.h @@ -23,7 +23,7 @@ . */ /* 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 d69b7fc4d30..8e62f328a23 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; }