This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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),
+						  &current_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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]