mirror of
https://github.com/tobast/libunwind-eh_elf.git
synced 2024-11-23 16:07:37 +01:00
(update_frame_state): Update c->sigcontext_off so unw_resume() can reconstruct the
original stack-pointer from c->sigcontext_loc. Handle rbs-switches for Linux signal deliver on alternate signal stack and for general case, indicated by UNW_PI_FLAG_IA64_RBS_SWITCH. Call rbs_underflow() when we detect a register-backing-store underflow. (Logical change 1.40)
This commit is contained in:
parent
7aaa1e995a
commit
56f367ca9c
1 changed files with 56 additions and 1 deletions
|
@ -1,5 +1,5 @@
|
|||
/* libunwind - a platform-independent unwind library
|
||||
Copyright (C) 2001-2002 Hewlett-Packard Co
|
||||
Copyright (C) 2001-2003 Hewlett-Packard Co
|
||||
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
|
||||
|
||||
This file is part of libunwind.
|
||||
|
@ -31,6 +31,7 @@ static inline int
|
|||
update_frame_state (struct cursor *c)
|
||||
{
|
||||
unw_word_t prev_ip, prev_sp, prev_bsp, ip, pr, num_regs, cfm;
|
||||
unw_word_t bsp, bspstore, rnat_addr, ndirty, loadrs;
|
||||
int ret;
|
||||
|
||||
prev_ip = c->ip;
|
||||
|
@ -48,6 +49,8 @@ update_frame_state (struct cursor *c)
|
|||
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
|
||||
|
@ -64,6 +67,40 @@ update_frame_state (struct cursor *c)
|
|||
return ret;
|
||||
|
||||
num_regs = cfm & 0x7f; /* size of frame */
|
||||
|
||||
/* When Linux delivers a signal on an alternate stack, it does
|
||||
things a bit differently from what the unwind conventions
|
||||
allow us to describe: instead of saving ar.rnat, ar.bsp, and
|
||||
ar.bspstore, it saves the former two plus the "loadrs" value.
|
||||
Because of this, we need to detect & record a potential
|
||||
rbs-area switch here manually... */
|
||||
if (c->bsp_loc)
|
||||
{
|
||||
/* If ar.bsp has been saved already AND the current bsp is
|
||||
not equal to the saved value, then we know for sure that
|
||||
we're past the point where the backing store has been
|
||||
switched (and before the point where it's restored). */
|
||||
ret = ia64_get (c, c->sigcontext_loc + SIGCONTEXT_AR_BSP_OFF, &bsp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (bsp != c->bsp)
|
||||
{
|
||||
assert (c->rnat_loc);
|
||||
|
||||
ret = ia64_get (c, c->sigcontext_loc + SIGCONTEXT_LOADRS_OFF,
|
||||
&loadrs);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
loadrs >>= 16;
|
||||
ndirty = ia64_rse_num_regs (c->bsp - loadrs, c->bsp);
|
||||
bspstore = ia64_rse_skip_regs (bsp, -ndirty);
|
||||
ret = rbs_record_switch (c, bsp, bspstore, c->rnat_loc);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -72,7 +109,25 @@ update_frame_state (struct cursor *c)
|
|||
return ret;
|
||||
num_regs = (cfm >> 7) & 0x7f; /* size of locals */
|
||||
}
|
||||
|
||||
if (unlikely (c->pi.flags & UNW_PI_FLAG_IA64_RBS_SWITCH))
|
||||
{
|
||||
if ((ret = ia64_get (c, c->bsp_loc, &bsp)) < 0
|
||||
|| (ret = ia64_get (c, c->bspstore_loc, &bspstore)) < 0
|
||||
|| (ret = ia64_get (c, c->rnat_loc, &rnat_addr)) < 0)
|
||||
return ret;
|
||||
|
||||
if (bsp != c->bsp)
|
||||
{
|
||||
ret = rbs_record_switch (c, bsp, bspstore, rnat_addr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
c->bsp = ia64_rse_skip_regs (c->bsp, -num_regs);
|
||||
if (c->rbs_area[c->rbs_curr].end - c->bsp > c->rbs_area[c->rbs_curr].size)
|
||||
rbs_underflow (c);
|
||||
|
||||
/* update the IP cache: */
|
||||
ret = ia64_get (c, c->ip_loc, &ip);
|
||||
|
|
Loading…
Reference in a new issue