aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormostang.com!davidm <mostang.com!davidm>2003-01-23 10:04:09 +0000
committermostang.com!davidm <mostang.com!davidm>2003-01-23 10:04:09 +0000
commitad8830e9ce039d063701e5e7ced42f4e9f44e1d3 (patch)
tree4882d63fec2b32d524fc0c9ff2f6a6a89f1cb1a0 /src
parenta356356660af77714ca0338a24bf965c71aade69 (diff)
downloadlibunwind-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.c95
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);