mirror of
https://github.com/tobast/libunwind-eh_elf.git
synced 2024-11-17 13:47:37 +01:00
Adjust for save-loc member renaming.
Adjust for renaming of Linux sigcontext offset macros. (check_rbs_switch): Handle Linux-case only if abi_marker==ABI_MARKER_LINUX_SIGTRAMP. (update_frame_state): For cursor's with a non-zero abi_marker, do special Linux or HP-UX sigtramp handling as appropriate. Clear abi_marker instead of is_signal_frame. (Logical change 1.84)
This commit is contained in:
parent
f24e3d70a0
commit
237a66bc21
1 changed files with 73 additions and 51 deletions
|
@ -38,12 +38,14 @@ check_rbs_switch (struct cursor *c)
|
||||||
{
|
{
|
||||||
/* Got ourselves a frame that has saved ar.bspstore, ar.bsp,
|
/* Got ourselves a frame that has saved ar.bspstore, ar.bsp,
|
||||||
and ar.rnat, so we're all set for rbs-switching: */
|
and ar.rnat, so we're all set for rbs-switching: */
|
||||||
if ((ret = ia64_get (c, c->bsp_loc, &saved_bsp)) < 0
|
if ((ret = ia64_get (c, c->loc[IA64_REG_BSP], &saved_bsp)) < 0
|
||||||
|| (ret = ia64_get (c, c->bspstore_loc, &saved_bspstore)))
|
|| (ret = ia64_get (c, c->loc[IA64_REG_BSPSTORE], &saved_bspstore)))
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
else if (c->is_signal_frame
|
else if (c->abi_marker == ABI_MARKER_LINUX_SIGTRAMP
|
||||||
&& c->bsp_loc == c->sigcontext_loc + SIGCONTEXT_AR_BSP_OFF)
|
&& !IA64_IS_REG_LOC (c->loc[IA64_REG_BSP])
|
||||||
|
&& (IA64_GET_ADDR (c->loc[IA64_REG_BSP])
|
||||||
|
== c->sigcontext_addr + LINUX_SC_AR_BSP_OFF))
|
||||||
{
|
{
|
||||||
/* When Linux delivers a signal on an alternate stack, it
|
/* When Linux delivers a signal on an alternate stack, it
|
||||||
does things a bit differently from what the unwind
|
does things a bit differently from what the unwind
|
||||||
|
@ -57,9 +59,11 @@ check_rbs_switch (struct cursor *c)
|
||||||
not equal to the saved value, then we know for sure that
|
not equal to the saved value, then we know for sure that
|
||||||
we're past the point where the backing store has been
|
we're past the point where the backing store has been
|
||||||
switched (and before the point where it's restored). */
|
switched (and before the point where it's restored). */
|
||||||
if ((ret = ia64_get (c, c->sigcontext_loc + SIGCONTEXT_AR_BSP_OFF,
|
if ((ret = ia64_get (c, IA64_LOC_ADDR (c->sigcontext_addr
|
||||||
|
+ LINUX_SC_AR_BSP_OFF, 0),
|
||||||
&saved_bsp) < 0)
|
&saved_bsp) < 0)
|
||||||
|| (ret = ia64_get (c, c->sigcontext_loc + SIGCONTEXT_LOADRS_OFF,
|
|| (ret = ia64_get (c, IA64_LOC_ADDR (c->sigcontext_addr
|
||||||
|
+ LINUX_SC_LOADRS_OFF, 0),
|
||||||
&loadrs) < 0))
|
&loadrs) < 0))
|
||||||
return ret;
|
return ret;
|
||||||
loadrs >>= 16;
|
loadrs >>= 16;
|
||||||
|
@ -70,7 +74,7 @@ check_rbs_switch (struct cursor *c)
|
||||||
if (saved_bsp == c->bsp)
|
if (saved_bsp == c->bsp)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return rbs_switch (c, saved_bsp, saved_bspstore, c->rnat_loc);
|
return rbs_switch (c, saved_bsp, saved_bspstore, c->loc[IA64_REG_RNAT]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
|
@ -86,7 +90,7 @@ update_frame_state (struct cursor *c)
|
||||||
/* Update the IP cache (do this first: if we reach the end of the
|
/* Update the IP cache (do this first: if we reach the end of the
|
||||||
frame-chain, the rest of the info may not be valid/useful
|
frame-chain, the rest of the info may not be valid/useful
|
||||||
anymore. */
|
anymore. */
|
||||||
ret = ia64_get (c, c->ip_loc, &ip);
|
ret = ia64_get (c, c->loc[IA64_REG_IP], &ip);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
c->ip = ip;
|
c->ip = ip;
|
||||||
|
@ -101,62 +105,80 @@ update_frame_state (struct cursor *c)
|
||||||
/* end of frame-chain reached */
|
/* end of frame-chain reached */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
c->cfm_loc = c->pfs_loc;
|
c->cfm_loc = c->loc[IA64_REG_PFS];
|
||||||
/* update the CFM cache: */
|
/* update the CFM cache: */
|
||||||
ret = ia64_get (c, c->cfm_loc, &c->cfm);
|
ret = ia64_get (c, c->cfm_loc, &c->cfm);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
num_regs = 0;
|
num_regs = 0;
|
||||||
if (c->is_signal_frame)
|
if (c->abi_marker)
|
||||||
{
|
{
|
||||||
/* Caveat: #ifdef __hpux is wrong here. The code below is just
|
switch (c->abi_marker)
|
||||||
a placeholder until HP-UX is fully supported. Once this gets
|
|
||||||
fixed, we need to check the unwind cursor to see if the
|
|
||||||
target is running HP-UX or Linux. We can infer that from the
|
|
||||||
.unwabi directive associated with a signal trampoline. */
|
|
||||||
#ifdef __hpux
|
|
||||||
/* HP-UX passes the address of ucontext_t in r32: */
|
|
||||||
ret = ia64_get_stacked (c, 32, &c->sigcontext_loc, NULL);
|
|
||||||
#else
|
|
||||||
ret = ia64_get (c, c->sp + 0x10 + SIGFRAME_ARG2_OFF, &c->sigcontext_loc);
|
|
||||||
#endif
|
|
||||||
debug (100, "%s: sigcontext_loc=%lx (ret=%d)\n",
|
|
||||||
__FUNCTION__, c->sigcontext_loc, ret);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
c->sigcontext_off = c->sigcontext_loc - c->sp;
|
|
||||||
|
|
||||||
if (c->ip_loc == c->sigcontext_loc + SIGCONTEXT_BR_OFF + 0*8)
|
|
||||||
{
|
{
|
||||||
/* Earlier kernels (before 2.4.19 and 2.5.10) had buggy
|
#if !defined(UNW_LOCAL_ONLY) || defined(__linux)
|
||||||
unwind info for sigtramp. Fix it up here. */
|
case ABI_MARKER_LINUX_SIGTRAMP:
|
||||||
c->ip_loc = (c->sigcontext_loc + SIGCONTEXT_IP_OFF);
|
if ((ret = ia64_get (c, IA64_LOC_ADDR (c->sp + 0x10
|
||||||
c->cfm_loc = (c->sigcontext_loc + SIGCONTEXT_CFM_OFF);
|
+ LINUX_SIGFRAME_ARG2_OFF, 0),
|
||||||
/* update the IP cache: */
|
&c->sigcontext_addr)) < 0)
|
||||||
ret = ia64_get (c, c->ip_loc, &ip);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
c->ip = ip;
|
|
||||||
if (ip == 0)
|
|
||||||
/* end of frame-chain reached */
|
|
||||||
return 0;
|
|
||||||
/* update the CFM cache: */
|
|
||||||
ret = ia64_get (c, c->cfm_loc, &c->cfm);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
if (!IA64_IS_REG_LOC (c->loc[IA64_REG_IP])
|
||||||
|
&& (IA64_GET_ADDR (c->loc[IA64_REG_IP])
|
||||||
|
== c->sigcontext_addr + LINUX_SC_BR_OFF + 0*8))
|
||||||
|
{
|
||||||
|
/* Linux kernels before 2.4.19 and 2.5.10 had buggy
|
||||||
|
unwind info for sigtramp. Fix it up here. */
|
||||||
|
c->loc[IA64_REG_IP] = IA64_LOC_ADDR (c->sigcontext_addr
|
||||||
|
+ LINUX_SC_IP_OFF, 0);
|
||||||
|
c->cfm_loc = IA64_LOC_ADDR (c->sigcontext_addr
|
||||||
|
+ LINUX_SC_CFM_OFF, 0);
|
||||||
|
/* update the IP cache: */
|
||||||
|
if ((ret = ia64_get (c, c->loc[IA64_REG_IP], &ip)) < 0)
|
||||||
|
return ret;
|
||||||
|
c->ip = ip;
|
||||||
|
if (ip == 0)
|
||||||
|
/* end of frame-chain reached */
|
||||||
|
return 0;
|
||||||
|
/* update the CFM cache: */
|
||||||
|
if ((ret = ia64_get (c, c->cfm_loc, &c->cfm)) < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* do what can't be described by unwind directives: */
|
||||||
|
c->loc[IA64_REG_PFS] = IA64_LOC_ADDR (c->sigcontext_addr
|
||||||
|
+ LINUX_SC_AR_PFS_OFF, 0);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(UNW_LOCAL_ONLY) || defined(__hpux)
|
||||||
|
case ABI_MARKER_HP_UX_SIGTRAMP:
|
||||||
|
{
|
||||||
|
ia64_loc_t sc_loc;
|
||||||
|
|
||||||
|
/* HP-UX passes the address of ucontext_t in r32: */
|
||||||
|
if ((ret = ia64_get_stacked (c, 32, &sc_loc, NULL)) < 0)
|
||||||
|
return ret;
|
||||||
|
c->sigcontext_addr = IA64_GET_ADDR (sc_loc);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
default:
|
||||||
|
debug (1, "%s: unknown ABI marker: ABI=%u, context=%u\n",
|
||||||
|
__FUNCTION__, c->abi_marker >> 8, c->abi_marker & 0xff);
|
||||||
|
return -UNW_EINVAL;
|
||||||
}
|
}
|
||||||
|
debug (100, "%s: sigcontext_addr=%lx (ret=%d)\n",
|
||||||
|
__FUNCTION__, c->sigcontext_addr, ret);
|
||||||
|
|
||||||
/* do what can't be described by unwind directives: */
|
c->sigcontext_off = c->sigcontext_addr - c->sp;
|
||||||
c->pfs_loc = (c->sigcontext_loc + SIGCONTEXT_AR_PFS_OFF);
|
|
||||||
|
|
||||||
num_regs = c->cfm & 0x7f; /* size of frame */
|
num_regs = c->cfm & 0x7f; /* size of frame */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
num_regs = (c->cfm >> 7) & 0x7f; /* size of locals */
|
num_regs = (c->cfm >> 7) & 0x7f; /* size of locals */
|
||||||
|
|
||||||
if (c->bsp_loc)
|
if (!IA64_IS_NULL_LOC (c->loc[IA64_REG_BSP]))
|
||||||
{
|
{
|
||||||
ret = check_rbs_switch (c);
|
ret = check_rbs_switch (c);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -167,7 +189,7 @@ update_frame_state (struct cursor *c)
|
||||||
|
|
||||||
pr = c->pr;
|
pr = c->pr;
|
||||||
c->sp = c->psp;
|
c->sp = c->psp;
|
||||||
c->is_signal_frame = 0;
|
c->abi_marker = 0;
|
||||||
|
|
||||||
if (c->ip == prev_ip && c->sp == prev_sp && c->bsp == prev_bsp)
|
if (c->ip == prev_ip && c->sp == prev_sp && c->bsp == prev_bsp)
|
||||||
{
|
{
|
||||||
|
@ -177,10 +199,10 @@ update_frame_state (struct cursor *c)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* as we unwind, the saved ar.unat becomes the primary unat: */
|
/* as we unwind, the saved ar.unat becomes the primary unat: */
|
||||||
c->pri_unat_loc = c->unat_loc;
|
c->loc[IA64_REG_PRI_UNAT_MEM] = c->loc[IA64_REG_UNAT];
|
||||||
|
|
||||||
/* restore the predicates: */
|
/* restore the predicates: */
|
||||||
ret = ia64_get (c, c->pr_loc, &c->pr);
|
ret = ia64_get (c, c->loc[IA64_REG_PR], &c->pr);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue