1
0
Fork 0
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:
mostang.com!davidm 2003-01-21 17:41:20 +00:00
parent 7aaa1e995a
commit 56f367ca9c

View file

@ -1,5 +1,5 @@
/* libunwind - a platform-independent unwind library /* 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> Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind. This file is part of libunwind.
@ -31,6 +31,7 @@ static inline int
update_frame_state (struct cursor *c) update_frame_state (struct cursor *c)
{ {
unw_word_t prev_ip, prev_sp, prev_bsp, ip, pr, num_regs, cfm; 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; int ret;
prev_ip = c->ip; prev_ip = c->ip;
@ -48,6 +49,8 @@ update_frame_state (struct cursor *c)
if (ret < 0) if (ret < 0)
return ret; return ret;
c->sigcontext_off = c->sigcontext_loc - c->sp;
if (c->ip_loc == c->sigcontext_loc + SIGCONTEXT_BR_OFF + 0*8) if (c->ip_loc == c->sigcontext_loc + SIGCONTEXT_BR_OFF + 0*8)
{ {
/* Earlier kernels (before 2.4.19 and 2.5.10) had buggy /* Earlier kernels (before 2.4.19 and 2.5.10) had buggy
@ -64,6 +67,40 @@ update_frame_state (struct cursor *c)
return ret; return ret;
num_regs = cfm & 0x7f; /* size of frame */ 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 else
{ {
@ -72,7 +109,25 @@ update_frame_state (struct cursor *c)
return ret; return ret;
num_regs = (cfm >> 7) & 0x7f; /* size of locals */ 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); 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: */ /* update the IP cache: */
ret = ia64_get (c, c->ip_loc, &ip); ret = ia64_get (c, c->ip_loc, &ip);