This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Do not unwind frames past NULL PC
- From: "Maciej W. Rozycki" <macro at mips dot com>
- To: gdb-patches at sourceware dot org
- Cc: Nigel Stephens <nigel at mips dot com>, "Maciej W. Rozycki" <macro at linux-mips dot org>
- Date: Fri, 22 Feb 2008 17:12:18 +0000 (GMT)
- Subject: Do not unwind frames past NULL PC
Hello,
Some architectures, like MIPS, specify in the ABI that the value of the
return address in a frame (or in other words the value of the PC the frame
would have been called from) being zero denotes the outermost frame. At
the moment GDB does not seem to have a way to terminate frame unwinding in
an architecture-specific way (or to that matter any that would not imply
an error condition) in get_prev_frame_1(), which is where such a check
would be needed.
However even for these architectures which may not necessarily specify in
the relevant ABI that a NULL PC is the terminating value it seems rather
unlikely for a function to have been called in a way which would make its
return address to be zero and yet it having a genuine caller with an
associated frame. Therefore I propose the following check to be
introduced to get_prev_frame_1(). It removes the confusing bogus frame at
the bottom of a backtrace like below:
(gdb) bt
#0 main (argc=1, argv=0x8114fdd0, envp=0x801065a8)
at gdb/testsuite/gdb.base/run.c:59
#1 0x801003a3 in __wrap_main ()
#2 0x801000a4 in _start ()
at sdemdi/crt0.S:93
#3 0x00000000 in ?? ()
(gdb)
If my assumption is in fact wrong for some other architecture, then
please let me know. Otherwise this change has been tested using the
mipsisa32-sde-elf target, with the mips-sim-sde32/-EB/-mips32r2 and
mips-sim-sde32/-EL/-mips32r2 boards with no regressions.
2008-02-22 Maciej W. Rozycki <macro@mips.com>
* frame.c (get_prev_frame_1): Stop unwinding if the PC of zero
has been reached.
OK to apply?
Maciej
gdb-get_prev_frame.diff
Index: binutils-quilt/ChangeLog-gdb-get_prev_frame
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils-quilt/ChangeLog-gdb-get_prev_frame 2008-02-22 16:38:40.000000000 +0000
@@ -0,0 +1,4 @@
+2008-02-22 Maciej W. Rozycki <macro@mips.com>
+
+ * frame.c (get_prev_frame_1): Stop unwinding if the PC of zero
+ has been reached.
Index: binutils-quilt/src/gdb/frame.c
===================================================================
--- binutils-quilt.orig/src/gdb/frame.c 2008-02-22 14:52:45.000000000 +0000
+++ binutils-quilt/src/gdb/frame.c 2008-02-22 16:38:40.000000000 +0000
@@ -1122,13 +1122,18 @@
static struct frame_info *
get_prev_frame_1 (struct frame_info *this_frame)
{
+ enum frame_type this_frame_type;
struct frame_info *prev_frame;
struct frame_id this_id;
struct gdbarch *gdbarch;
+ int pc_regnum;
gdb_assert (this_frame != NULL);
gdbarch = get_frame_arch (this_frame);
+ pc_regnum = gdbarch_pc_regnum (gdbarch);
+ this_frame_type = get_frame_type (this_frame);
+
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog, "{ get_prev_frame_1 (this_frame=");
@@ -1219,19 +1224,17 @@
method set the same lval and location information as
frame_register_unwind. */
if (this_frame->level > 0
- && gdbarch_pc_regnum (gdbarch) >= 0
- && get_frame_type (this_frame) == NORMAL_FRAME
+ && pc_regnum >= 0
+ && this_frame_type == NORMAL_FRAME
&& get_frame_type (this_frame->next) == NORMAL_FRAME)
{
int optimized, realnum, nrealnum;
enum lval_type lval, nlval;
CORE_ADDR addr, naddr;
- frame_register_unwind_location (this_frame,
- gdbarch_pc_regnum (gdbarch),
+ frame_register_unwind_location (this_frame, pc_regnum,
&optimized, &lval, &addr, &realnum);
- frame_register_unwind_location (get_next_frame (this_frame),
- gdbarch_pc_regnum (gdbarch),
+ frame_register_unwind_location (get_next_frame (this_frame), pc_regnum,
&optimized, &nlval, &naddr, &nrealnum);
if ((lval == lval_memory && lval == nlval && addr == naddr)
@@ -1250,6 +1253,23 @@
}
}
+ /* Check for the unwound PC being zero, which means this is
+ the outermost frame. */
+ if (pc_regnum >= 0
+ && this_frame_type == NORMAL_FRAME
+ && frame_pc_unwind (this_frame) == 0)
+ {
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, NULL);
+ fprintf_unfiltered (gdb_stdlog, " // NULL saved PC }\n");
+ }
+
+ this_frame->prev = NULL;
+ return NULL;
+ }
+
/* Allocate the new frame but do not wire it in to the frame chain.
Some (bad) code in INIT_FRAME_EXTRA_INFO tries to look along
frame->next to pull some fancy tricks (of course such code is, by