aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandolph Chung <tausq@debian.org>2004-11-12 00:48:12 +0000
committerRandolph Chung <tausq@debian.org>2004-11-12 00:48:12 +0000
commit50b2f48ac1fea9b0ae40e2e66b883802fa647193 (patch)
tree5febf6100e1c8b6fe38477f86ad917387f839cef
parent68086f6a3f04f6d10e375d4af10ee511bf6763c4 (diff)
downloadbinutils-50b2f48ac1fea9b0ae40e2e66b883802fa647193.zip
binutils-50b2f48ac1fea9b0ae40e2e66b883802fa647193.tar.gz
binutils-50b2f48ac1fea9b0ae40e2e66b883802fa647193.tar.bz2
2004-11-11 Randolph Chung <tausq@debian.org>
* hppa-tdep.c (hppa_frame_cache): Properly handle the frame pointer register so that it can be unwound from anywhere in the prologue.
-rw-r--r--gdb/ChangeLog5
-rw-r--r--gdb/hppa-tdep.c35
2 files changed, 30 insertions, 10 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 590de76..986318a 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,8 @@
+2004-11-11 Randolph Chung <tausq@debian.org>
+
+ * hppa-tdep.c (hppa_frame_cache): Properly handle the frame pointer
+ register so that it can be unwound from anywhere in the prologue.
+
2004-11-10 msnyder <msnyder@redhat.com>
* rs6000-tdep.c (skip_prologue): After saving lr_offset,
diff --git a/gdb/hppa-tdep.c b/gdb/hppa-tdep.c
index d272f21..c48ca86 100644
--- a/gdb/hppa-tdep.c
+++ b/gdb/hppa-tdep.c
@@ -1562,6 +1562,7 @@ hppa_frame_cache (struct frame_info *next_frame, void **this_cache)
long frame_size;
struct unwind_table_entry *u;
CORE_ADDR prologue_end;
+ int fp_in_r1 = 0;
int i;
if (hppa_debug)
@@ -1694,6 +1695,10 @@ hppa_frame_cache (struct frame_info *next_frame, void **this_cache)
looking_for_sp = 0;
cache->saved_regs[HPPA_FP_REGNUM].addr = 0;
}
+ else if (inst == 0x08030241) /* copy %r3, %r1 */
+ {
+ fp_in_r1 = 1;
+ }
/* Account for general and floating-point register saves. */
reg = inst_saves_gr (inst);
@@ -1802,9 +1807,6 @@ hppa_frame_cache (struct frame_info *next_frame, void **this_cache)
and saved on the stack, the Save_SP flag is set. We use this to
decide whether to use the frame pointer for unwinding.
- fp may be zero if it is not available in an inner frame because
- it has been modified by not yet saved.
-
TODO: For the HP compiler, maybe we should use the alloca_frame flag
instead of Save_SP. */
@@ -1867,13 +1869,26 @@ hppa_frame_cache (struct frame_info *next_frame, void **this_cache)
}
}
- /* If the frame pointer was not saved in this frame, but we should be saving
- it, set it to an invalid value so that another frame will not pick up the
- wrong frame pointer. This can happen if we start unwinding after the
- frame pointer has been modified, but before we've saved it to the
- stack. */
- if (u->Save_SP && !trad_frame_addr_p (cache->saved_regs, HPPA_FP_REGNUM))
- trad_frame_set_value (cache->saved_regs, HPPA_FP_REGNUM, 0);
+ /* If Save_SP is set, then we expect the frame pointer to be saved in the
+ frame. However, there is a one-insn window where we haven't saved it
+ yet, but we've already clobbered it. Detect this case and fix it up.
+
+ The prologue sequence for frame-pointer functions is:
+ 0: stw %rp, -20(%sp)
+ 4: copy %r3, %r1
+ 8: copy %sp, %r3
+ c: stw,ma %r1, XX(%sp)
+
+ So if we are at offset c, the r3 value that we want is not yet saved
+ on the stack, but it's been overwritten. The prologue analyzer will
+ set fp_in_r1 when it sees the copy insn so we know to get the value
+ from r1 instead. */
+ if (u->Save_SP && !trad_frame_addr_p (cache->saved_regs, HPPA_FP_REGNUM)
+ && fp_in_r1)
+ {
+ ULONGEST r1 = frame_unwind_register_unsigned (next_frame, 1);
+ trad_frame_set_value (cache->saved_regs, HPPA_FP_REGNUM, r1);
+ }
{
/* Convert all the offsets into addresses. */