1
0
Fork 0
mirror of https://github.com/tobast/libunwind-eh_elf.git synced 2024-12-23 20:03:43 +01:00

(unw_resume): Rewrite to make it work for resuming execution past a signal frame

(and also simplify it).

(Logical change 1.45)
This commit is contained in:
mostang.com!davidm 2003-02-08 10:10:59 +00:00
parent f5892c26be
commit 678d3209fb

View file

@ -34,39 +34,30 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
HIDDEN inline int HIDDEN inline int
ia64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) ia64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
{ {
unw_word_t val, sol, sof, pri_unat, loadrs, n, bspstore, pfs;
struct cursor *c = (struct cursor *) cursor; struct cursor *c = (struct cursor *) cursor;
long do_sigreturn = 0; struct
unw_fpreg_t fpval; {
ucontext_t *uc = arg; unw_word_t r1;
unw_word_t val, sol; unw_word_t r4;
int i, ret; unw_word_t r5;
# define SET_NAT(n) \ unw_word_t r6;
unw_word_t r7;
unw_word_t r15;
unw_word_t r16;
unw_word_t r17;
unw_word_t r18;
}
extra;
int ret;
# define GET_NAT(n) \
do \ do \
{ \ { \
ret = ia64_access_reg (c, UNW_IA64_NAT + (n), &val, 0); \ ret = ia64_access_reg (c, UNW_IA64_NAT + (n), &val, 0); \
if (ret < 0) \ if (ret < 0) \
return ret; \ return ret; \
if (val) \ if (val) \
uc->uc_mcontext.sc_nat |= (unw_word_t) 1 << n; \ pri_unat |= (unw_word_t) 1 << n; \
} \
while (0)
# define SET_REG(f, r) \
do \
{ \
ret = ia64_get (c, c->r, &val); \
if (ret < 0) \
return ret; \
uc->uc_mcontext.f = val; \
} \
while (0)
# define SET_FPREG(f, r) \
do \
{ \
ret = ia64_getfp (c, c->r, &fpval); \
if (ret < 0) \
return ret; \
uc->uc_mcontext.f.u.bits[0] = fpval.raw.bits[0]; \
uc->uc_mcontext.f.u.bits[1] = fpval.raw.bits[1]; \
} \ } \
while (0) while (0)
@ -74,38 +65,26 @@ ia64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
if ((ret = ia64_make_proc_info (c)) < 0) if ((ret = ia64_make_proc_info (c)) < 0)
return ret; return ret;
SET_REG (sc_ar_pfs, pfs_loc); /* Copy contents of r4-r7 into "extra", so that their values end up
SET_REG (sc_br[0], ip_loc); contiguous, so we can use a single (primary-) UNaT value. */
SET_REG (sc_pr, pr_loc); if ((ret = ia64_get (c, c->r4_loc, &extra.r4)) < 0
SET_REG (sc_ar_rnat, rnat_loc); || (ret = ia64_get (c, c->r5_loc, &extra.r5)) < 0
SET_REG (sc_ar_lc, lc_loc); || (ret = ia64_get (c, c->r6_loc, &extra.r6)) < 0
SET_REG (sc_ar_fpsr, fpsr_loc); || (ret = ia64_get (c, c->r7_loc, &extra.r7)) < 0)
return ret;
SET_REG (sc_gr[4], r4_loc); SET_REG(sc_gr[5], r5_loc); /* Form the primary UNaT value: */
SET_REG (sc_gr[6], r6_loc); SET_REG(sc_gr[7], r7_loc); pri_unat = 0;
uc->uc_mcontext.sc_nat = 0; GET_NAT (4); GET_NAT(5);
SET_NAT (4); SET_NAT(5); GET_NAT (6); GET_NAT(7);
SET_NAT (6); SET_NAT(7); n = (((uintptr_t) &extra.r4) / 8 - 4) % 64;
pri_unat = (pri_unat << n) | (pri_unat >> (64 - n));
SET_REG (sc_br[1], b1_loc);
SET_REG (sc_br[2], b2_loc);
SET_REG (sc_br[3], b3_loc);
SET_REG (sc_br[4], b4_loc);
SET_REG (sc_br[5], b5_loc);
SET_FPREG (sc_fr[2], f2_loc);
SET_FPREG (sc_fr[3], f3_loc);
SET_FPREG (sc_fr[4], f4_loc);
SET_FPREG (sc_fr[5], f5_loc);
for (i = 16; i < 32; ++i)
SET_FPREG (sc_fr[i], fr_loc[i - 16]);
uc->uc_mcontext.sc_flags = 0;
uc->uc_mcontext.sc_gr[1] = c->pi.gp;
uc->uc_mcontext.sc_gr[12] = c->psp;
if (unlikely (c->sigcontext_loc)) if (unlikely (c->sigcontext_loc))
{ {
struct sigcontext *sc = (struct sigcontext *) c->sigcontext_loc; struct sigcontext *sc = (struct sigcontext *) c->sigcontext_loc;
# define PR_SCRATCH 0xffc0 /* p6-p15 are scratch */
# define PR_PRESERVED (~(PR_SCRATCH | 1))
/* We're returning to a frame that was (either directly or /* We're returning to a frame that was (either directly or
indirectly) interrupted by a signal. We have to restore indirectly) interrupted by a signal. We have to restore
@ -118,37 +97,64 @@ ia64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
was indirectly interrupted by a signal. However, that is not was indirectly interrupted by a signal. However, that is not
safe because that frame and its descendants could have been safe because that frame and its descendants could have been
using a special convention that stores "preserved" state in using a special convention that stores "preserved" state in
scratch registers. The fsyscall convention does this with scratch registers. For example, the Linux fsyscall
r11 (to save ar.pfs) and b6 (to save "rp"), for example. */ convention does this with r11 (to save ar.pfs) and b6 (to
sc->sc_ip = uc->uc_mcontext.sc_br[0]; save "rp"). */
sc->sc_gr[12] = c->psp;
uc->uc_mcontext.sc_gr[12] = (c->sigcontext_loc - c->sigcontext_off);
do_sigreturn = 1;
/* Account for the fact that sigreturn will decrement bsp by sc->sc_gr[12] = c->psp;
size-of-frame. */ c->psp = (c->sigcontext_loc - c->sigcontext_off);
#if 0
sof = (uc->uc_mcontext.sc_ar_pfs >> 0) & 0x7f; sof = (c->cfm & 0x7f);
uc->uc_mcontext.sc_ar_bsp = ia64_rse_skip_regs (c->bsp, sof); bspstore = c->bsp;
#else c->bsp = ia64_rse_skip_regs (bspstore, sof);
uc->uc_mcontext.sc_ar_bsp = sc->sc_ar_bsp; loadrs = 0;
#endif
printf("uc->bsp=%p, sc->bsp=%p\n", uc->uc_mcontext.sc_ar_bsp, sc->sc_ar_bsp); sc->sc_ip = c->ip;
sc->sc_cfm = c->cfm & (((unw_word_t) 1 << 38) - 1);
sc->sc_pr = (c->pr & ~PR_SCRATCH) | (sc->sc_pr & ~PR_PRESERVED);
if ((ret = ia64_get (c, c->pfs_loc, &sc->sc_ar_pfs)) < 0
|| (ret = ia64_get (c, c->fpsr_loc, &sc->sc_ar_fpsr)) < 0
|| (ret = ia64_get (c, c->unat_loc, &sc->sc_ar_unat)) < 0)
return ret;
sc->sc_gr[1] = c->pi.gp;
if (c->eh_valid_mask & 0x1) sc->sc_gr[15] = c->eh_args[0];
if (c->eh_valid_mask & 0x2) sc->sc_gr[16] = c->eh_args[1];
if (c->eh_valid_mask & 0x4) sc->sc_gr[17] = c->eh_args[2];
if (c->eh_valid_mask & 0x8) sc->sc_gr[18] = c->eh_args[3];
} }
else else
{ {
/* Account for the fact that __ia64_install_context() returns /* Account for the fact that _Uia64_install_context() will
via br.ret, which will decrement bsp by size-of-locals. */ return via br.ret, which will decrement bsp by size-of-locals. */
sol = (uc->uc_mcontext.sc_ar_pfs >> 7) & 0x7f; if ((ret = ia64_get (c, c->pfs_loc, &pfs)) < 0)
printf("this needs fixing\n"); return ret;
uc->uc_mcontext.sc_ar_bsp = ia64_rse_skip_regs (c->bsp, sol); sol = (pfs >> 7) & 0x7f;
c->bsp = ia64_rse_skip_regs (c->bsp, sol);
loadrs = 0;
extra.r1 = c->pi.gp;
extra.r15 = c->eh_args[0];
extra.r16 = c->eh_args[1];
extra.r17 = c->eh_args[2];
extra.r18 = c->eh_args[3];
} }
__ia64_install_context (uc, c->eh_args[0], c->eh_args[1], c->eh_args[2], _Uia64_install_context (c, pri_unat, (unw_word_t *) &extra, loadrs);
c->eh_args[3], do_sigreturn);
} }
#endif /* !UNW_REMOTE_ONLY */ #endif /* !UNW_REMOTE_ONLY */
#ifndef UNW_LOCAL_ONLY
static inline int
remote_install_cursor (struct cursor *c)
{
printf ("%s: XXX implement me!\n", __FUNCTION__);
return -1;
}
#endif
int int
unw_resume (unw_cursor_t *cursor) unw_resume (unw_cursor_t *cursor)
{ {
@ -157,6 +163,12 @@ unw_resume (unw_cursor_t *cursor)
#ifdef UNW_LOCAL_ONLY #ifdef UNW_LOCAL_ONLY
return ia64_local_resume (c->as, cursor, c->as_arg); return ia64_local_resume (c->as, cursor, c->as_arg);
#else #else
{
int ret;
if ((ret = remote_install_cursor (c)) < 0)
return ret;
return (*c->as->acc.resume) (c->as, cursor, c->as_arg); return (*c->as->acc.resume) (c->as, cursor, c->as_arg);
}
#endif #endif
} }