This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[patch] Stop runaway unwinding on stripped executables
- From: Jan Kratochvil <jan dot kratochvil at redhat dot com>
- To: gdb-patches at sourceware dot org
- Date: Fri, 16 Mar 2012 13:02:07 +0100
- Subject: [patch] Stop runaway unwinding on stripped executables
Hi,
this situation came from the real world out there:
# inferior has symbols
echo 'main(){pause();}'|gcc -x c -; ./a.out& gdb -p $! -ex bt
#0 0x00007f9dc4d4f0d0 in __pause_nocancel () at ../sysdeps/unix/syscall-template.S:82
#1 0x00000000004004ea in main ()
(gdb) q
PROBLEM:
--------
# -s: inferior has no symbols
echo 'main(){pause();}'|gcc -x c - -s; ./a.out& gdb -p $! -ex bt
#0 0x00007f274fd5a0d0 in __pause_nocancel () at ../sysdeps/unix/syscall-template.S:82
#1 0x00000000004004ea in ?? ()
#2 0x00007f274fcc1735 in __libc_start_main (main=0x4004dc, ...) at libc-start.c:226
#3 0x00000000004003f9 in ?? ()
#4 0x00007fffdbdec7a8 in ?? ()
#5 0x000000000000001c in ?? ()
#6 0x0000000000000001 in ?? ()
#7 0x00007fffdbdede72 in ?? ()
#8 0x0000000000000000 in ?? ()
(gdb) q
--- In reality this backtrace can be much longer confusing the people
thinking they have wrong backtrace; it is correctly unwound, it is just
runaway unwinding garbage.
# -s, now with the fix below:
#0 0x00007f1b912b80d0 in __pause_nocancel () at ../sysdeps/unix/syscall-template.S:82
#1 0x00000000004004ea in ?? ()
#2 0x00007f1b9121f735 in __libc_start_main (main=0x4004dc, argc=1, ubp_av=0x7fff150f9038, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fff150f9028) at libc-start.c:226
# inferior has symbols, with set backtrace past-main
echo 'main(){pause();}'|gcc -x c -; ./a.out& ./gdb -nx -p $! -ex 'set backtrace past-main' -ex bt
#0 0x00007f8930f090d0 in __pause_nocancel () at ../sysdeps/unix/syscall-template.S:82
#1 0x00000000004004ea in main ()
^^^^^^^ Both addresses were unwound above but not
printed.
#2 0x00007f8930e70735 in __libc_start_main (main=0x4004dc <main>, ...) at libc-start.c:226
#3 0x00000000004003f9 in _start ()
^^^^^^^^^ Both addresses were unwound above but not
printed. GDB needs to know at least size
of "_start" for inside_entry_func but
without symbols it knows neither.
(gdb) q
One can see that with stripped inferior (-s) GDB cannot even stop at the entry
symbol as "_start" is also missing there.
I find the patch safe enough, if we want to stop at "main" and we see
"__libc_start_main" there is no chance "main" would be seen anymore.
Sure this whole patch has no effect with "set backtrace past-main".
I do not think a testcase makes sense, it would just duplicate the C code
logic in TCL being untested if "__libc_start_main" is not found.
No regressions on {x86_64,x86_64-m32,i686}-fedora17-linux-gnu.
Thanks,
Jan
gdb/
2012-03-16 Jan Kratochvil <jan.kratochvil@redhat.com>
Stop runaway unwinding of stripped executables.
* frame.c: Include objfiles.h.
(past_main_func): New function.
(get_prev_frame): Call it besides inside_main_func.
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -43,7 +43,8 @@
#include "gdbthread.h"
#include "block.h"
#include "inline-frame.h"
-#include "tracepoint.h"
+#include "tracepoint.h"
+#include "objfiles.h"
static struct frame_info *get_prev_frame_1 (struct frame_info *this_frame);
static struct frame_info *get_prev_frame_raw (struct frame_info *this_frame);
@@ -1856,6 +1857,43 @@ inside_main_func (struct frame_info *this_frame)
return maddr == get_frame_func (this_frame);
}
+/* Is this (non-sentinel) frame verified to be after (missed) "main"()
+ function? This is a safety stop of runaway unwinding on stripped
+ executables missing both "main" and "_start" (entry) symbols when
+ "set backtrace past-main on" in in use. */
+
+static int
+past_main_func (struct frame_info *this_frame)
+{
+ struct objfile *objfile;
+
+ ALL_OBJFILES (objfile)
+ {
+ struct minimal_symbol *msymbol;
+ CORE_ADDR maddr;
+
+ if (objfile->separate_debug_objfile_backlink)
+ continue;
+
+ if (strcmp (lbasename (objfile->name), "libc.so.6") != 0)
+ continue;
+
+ msymbol = lookup_minimal_symbol ("__libc_start_main", NULL, objfile);
+ if (msymbol == NULL)
+ continue;
+
+ /* Make certain that the code, and not descriptor, address is
+ returned. */
+ maddr = gdbarch_convert_from_func_ptr_addr (get_frame_arch (this_frame),
+ SYMBOL_VALUE_ADDRESS (msymbol),
+ ¤t_target);
+ if (maddr == get_frame_func (this_frame))
+ return 1;
+ }
+
+ return 0;
+}
+
/* Test whether THIS_FRAME is inside the process entry point function. */
static int
@@ -1904,7 +1942,7 @@ get_prev_frame (struct frame_info *this_frame)
&& get_frame_type (this_frame) == NORMAL_FRAME
&& !backtrace_past_main
&& frame_pc_p
- && inside_main_func (this_frame))
+ && (inside_main_func (this_frame) || past_main_func (this_frame)))
/* Don't unwind past main(). Note, this is done _before_ the
frame has been marked as previously unwound. That way if the
user later decides to enable unwinds past main(), that will