aboutsummaryrefslogtreecommitdiff
path: root/gdb/d10v-tdep.c
diff options
context:
space:
mode:
authorAndrew Cagney <cagney@redhat.com>2003-03-05 22:54:22 +0000
committerAndrew Cagney <cagney@redhat.com>2003-03-05 22:54:22 +0000
commitceea51452abd349231836ac2c4abde570a8bc8be (patch)
tree5b13762f50e8df8b6fe5d2cbaa9b14717bab3b12 /gdb/d10v-tdep.c
parent0d843116323281c1777f745582a962e373244dd6 (diff)
downloadgdb-ceea51452abd349231836ac2c4abde570a8bc8be.zip
gdb-ceea51452abd349231836ac2c4abde570a8bc8be.tar.gz
gdb-ceea51452abd349231836ac2c4abde570a8bc8be.tar.bz2
2003-03-05 Andrew Cagney <cagney@redhat.com>
* d10v-tdep.c (struct d10v_unwind_cache): Add field "base". (d10v_frame_unwind_cache): Rewrite code computing the base and SP. Do not use d10v_read_sp or d10v_read_fp when obtaining register values.
Diffstat (limited to 'gdb/d10v-tdep.c')
-rw-r--r--gdb/d10v-tdep.c61
1 files changed, 41 insertions, 20 deletions
diff --git a/gdb/d10v-tdep.c b/gdb/d10v-tdep.c
index f37f191..fc05e80 100644
--- a/gdb/d10v-tdep.c
+++ b/gdb/d10v-tdep.c
@@ -610,6 +610,8 @@ d10v_skip_prologue (CORE_ADDR pc)
struct d10v_unwind_cache
{
CORE_ADDR return_pc;
+ /* The frame's base. Used when constructing a frame ID. */
+ CORE_ADDR base;
int size;
CORE_ADDR *saved_regs;
/* How far the SP and r11 (FP) have been offset from the start of
@@ -706,7 +708,9 @@ struct d10v_unwind_cache *
d10v_frame_unwind_cache (struct frame_info *fi,
void **cache)
{
- CORE_ADDR fp, pc;
+ CORE_ADDR pc;
+ ULONGEST prev_sp;
+ ULONGEST this_base;
unsigned long op;
unsigned short op1, op2;
int i;
@@ -721,8 +725,6 @@ d10v_frame_unwind_cache (struct frame_info *fi,
info->size = 0;
info->return_pc = 0;
-
- fp = get_frame_base (fi);
info->sp_offset = 0;
pc = get_pc_function_start (get_frame_pc (fi));
@@ -780,13 +782,43 @@ d10v_frame_unwind_cache (struct frame_info *fi,
info->size = -info->sp_offset;
- if (!(fp & 0xffff))
- fp = d10v_read_sp ();
+ /* Compute the frame's base, and the previous frame's SP. */
+ if (info->uses_frame)
+ {
+ /* The SP was moved to the FP. This indicates that a new frame
+ was created. Get THIS frame's FP value by unwinding it from
+ the next frame. */
+ frame_read_unsigned_register (fi, FP_REGNUM, &this_base);
+ /* The FP points at the last saved register. Adjust the FP back
+ to before the first saved register giving the SP. */
+ prev_sp = this_base + info->size;
+ }
+ else if (info->saved_regs[SP_REGNUM])
+ {
+ /* The SP was saved (which is very unusual), the frame base is
+ just the PREV's frame's TOP-OF-STACK. */
+ this_base = read_memory_unsigned_integer (info->saved_regs[SP_REGNUM],
+ register_size (current_gdbarch,
+ SP_REGNUM));
+ prev_sp = this_base;
+ }
+ else
+ {
+ /* Assume that the FP is this frame's SP but with that pushed
+ stack space added back. */
+ frame_read_unsigned_register (fi, SP_REGNUM, &this_base);
+ prev_sp = this_base + info->size;
+ }
+
+ info->base = d10v_make_daddr (this_base);
+ prev_sp = d10v_make_daddr (prev_sp);
+ /* Adjust all the saved registers so that they contain addresses and
+ not offsets. */
for (i = 0; i < NUM_REGS - 1; i++)
if (info->saved_regs[i])
{
- info->saved_regs[i] = fp - (info->sp_offset - info->saved_regs[i]);
+ info->saved_regs[i] = (prev_sp + info->saved_regs[i]);
}
if (info->saved_regs[LR_REGNUM])
@@ -803,20 +835,9 @@ d10v_frame_unwind_cache (struct frame_info *fi,
info->return_pc = d10v_make_iaddr (return_pc);
}
- /* The SP is not normally (ever?) saved, but check anyway */
- if (!info->saved_regs[SP_REGNUM])
- {
- /* if the FP was saved, that means the current FP is valid, */
- /* otherwise, it isn't being used, so we use the SP instead */
- if (info->uses_frame)
- info->saved_regs[SP_REGNUM]
- = d10v_read_fp () + info->size;
- else
- {
- info->saved_regs[SP_REGNUM] = fp + info->size;
- info->saved_regs[FP_REGNUM] = 0;
- }
- }
+ /* The SP_REGNUM is special. Instead of the address of the SP, the
+ previous frame's SP value is saved. */
+ info->saved_regs[SP_REGNUM] = prev_sp;
return info;
}