mirror of
https://github.com/tobast/libunwind-eh_elf.git
synced 2025-04-08 14:42:16 +02:00
(check_rbs_switch): New function. Split-off from update_frame_state().
(Logical change 1.41)
This commit is contained in:
parent
a356356660
commit
ad8830e9ce
1 changed files with 49 additions and 46 deletions
|
@ -27,11 +27,56 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
#include "rse.h"
|
#include "rse.h"
|
||||||
#include "unwind_i.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
|
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;
|
||||||
|
@ -67,40 +112,6 @@ 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
|
||||||
{
|
{
|
||||||
|
@ -110,19 +121,11 @@ update_frame_state (struct cursor *c)
|
||||||
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 (c->bsp_loc)
|
||||||
{
|
{
|
||||||
if ((ret = ia64_get (c, c->bsp_loc, &bsp)) < 0
|
ret = check_rbs_switch (c);
|
||||||
|| (ret = ia64_get (c, c->bspstore_loc, &bspstore)) < 0
|
if (ret < 0)
|
||||||
|| (ret = ia64_get (c, c->rnat_loc, &rnat_addr)) < 0)
|
|
||||||
return ret;
|
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);
|
||||||
|
|
Loading…
Add table
Reference in a new issue