This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
[commit:d10v] Fix d10v sp/fp unwind
- From: Andrew Cagney <ac131313 at redhat dot com>
- To: gdb-patches at sources dot redhat dot com
- Date: Wed, 05 Mar 2003 17:53:49 -0500
- Subject: [commit:d10v] Fix d10v sp/fp unwind
Hello,
The d10v prologue analyzer was only correctly unwinding the SP when
given the innermost frame.
This is (mainly) because the d10v was using d10v_read_fp() and
d10v_read_sp() to obtain register values. That is simply wrong. Those
methods return the value of the register in the regcache, not the
register value for the relevant frame.
The attached cleans up the stack pointer unwind code, making recursive
register unwind calls where needed.
While the existing d10v's test results are not affected by this change,
a d10v GDB that implements unwind_dummy_id() shows regressions without
it. This is because unwind_dummy_id() is more heavily dependant on
correctly unwound register values.
committed,
Andrew
2003-03-05 Andrew Cagney <cagney at redhat dot 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.
Index: d10v-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/d10v-tdep.c,v
retrieving revision 1.81
diff -u -r1.81 d10v-tdep.c
--- d10v-tdep.c 5 Mar 2003 20:57:28 -0000 1.81
+++ d10v-tdep.c 5 Mar 2003 22:24:49 -0000
@@ -610,6 +610,8 @@
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 @@
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 @@
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 @@
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 @@
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;
}