diff options
author | mostang.com!davidm <mostang.com!davidm> | 2003-01-23 10:04:09 +0000 |
---|---|---|
committer | mostang.com!davidm <mostang.com!davidm> | 2003-01-23 10:04:09 +0000 |
commit | ad8830e9ce039d063701e5e7ced42f4e9f44e1d3 (patch) | |
tree | 4882d63fec2b32d524fc0c9ff2f6a6a89f1cb1a0 /src | |
parent | a356356660af77714ca0338a24bf965c71aade69 (diff) | |
download | libunwind-ad8830e9ce039d063701e5e7ced42f4e9f44e1d3.tar.gz |
(check_rbs_switch): New function. Split-off from update_frame_state().
(Logical change 1.41)
Diffstat (limited to 'src')
-rw-r--r-- | src/ia64/Gstep-ia64.c | 95 |
1 files changed, 49 insertions, 46 deletions
diff --git a/src/ia64/Gstep-ia64.c b/src/ia64/Gstep-ia64.c index 408e472b..53a829d8 100644 --- a/src/ia64/Gstep-ia64.c +++ b/src/ia64/Gstep-ia64.c @@ -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); |