1
0
Fork 0
mirror of https://github.com/tobast/libunwind-eh_elf.git synced 2025-04-02 12:12:18 +02:00

(check_rbs_switch): New function. Split-off from update_frame_state().

(Logical change 1.41)
This commit is contained in:
mostang.com!davidm 2003-01-23 10:04:09 +00:00
parent a356356660
commit ad8830e9ce

View file

@ -27,11 +27,56 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "rse.h"
#include "unwind_i.h"
static int
check_rbs_switch (struct cursor *c)
{
unw_word_t saved_bsp, saved_bspstore, loadrs, ndirty;
int ret = 0;
saved_bsp = c->bsp;
if (c->pi.flags & UNW_PI_FLAG_IA64_RBS_SWITCH)
{
/* Got ourselves a frame that has saved ar.bspstore, ar.bsp,
and ar.rnat, so we're all set for rbs-switching: */
if ((ret = ia64_get (c, c->bsp_loc, &saved_bsp)) < 0
|| (ret = ia64_get (c, c->bspstore_loc, &saved_bspstore)))
return ret;
}
else if (c->is_signal_frame
&& c->bsp_loc == c->sigcontext_loc + SIGCONTEXT_AR_BSP_OFF)
{
/* 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
manually... */
/* 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). */
if ((ret = ia64_get (c, c->sigcontext_loc + SIGCONTEXT_AR_BSP_OFF,
&saved_bsp) < 0)
|| (ret = ia64_get (c, c->sigcontext_loc + SIGCONTEXT_LOADRS_OFF,
&loadrs) < 0))
return ret;
loadrs >>= 16;
ndirty = ia64_rse_num_regs (c->bsp - loadrs, c->bsp);
saved_bspstore = ia64_rse_skip_regs (saved_bsp, -ndirty);
}
if (saved_bsp != c->bsp)
ret = rbs_record_switch (c, saved_bsp, saved_bspstore, c->rnat_loc);
return ret;
}
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;
@ -67,40 +112,6 @@ 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
{
@ -110,19 +121,11 @@ update_frame_state (struct cursor *c)
num_regs = (cfm >> 7) & 0x7f; /* size of locals */
}
if (unlikely (c->pi.flags & UNW_PI_FLAG_IA64_RBS_SWITCH))
if (c->bsp_loc)
{
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)
ret = check_rbs_switch (c);
if (ret < 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);