* [patch] Stop runaway unwinding on stripped executables
@ 2012-03-16 12:02 Jan Kratochvil
2012-03-16 13:51 ` Mark Kettenis
0 siblings, 1 reply; 6+ messages in thread
From: Jan Kratochvil @ 2012-03-16 12:02 UTC (permalink / raw)
To: gdb-patches
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
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [patch] Stop runaway unwinding on stripped executables
2012-03-16 12:02 [patch] Stop runaway unwinding on stripped executables Jan Kratochvil
@ 2012-03-16 13:51 ` Mark Kettenis
2012-03-16 14:46 ` Jan Kratochvil
0 siblings, 1 reply; 6+ messages in thread
From: Mark Kettenis @ 2012-03-16 13:51 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches
> Date: Fri, 16 Mar 2012 13:02:07 +0100
> From: Jan Kratochvil <jan.kratochvil@redhat.com>
>
> 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.
People need to learn that if they are debugging stripped stuff they're
going to end up with runaway backtraces every now and then. In this
particular example you're just getting lucky that you're hitting
__libc_start_main(). That probably wouldn't happen if you're somewhat
deeper into the call stack of the (stripped) program that you're
trying to debug.
> 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".
But the implementation and actually the whole idea is *very*
glibc-specific. It relies on the fact that that the startup code
calls a function in libc which in turn calls main(). You hardcode the
name of the libc shared library. And you hardcode the name of the
function. IMHO this does notbelong in the generic frame unwinding
code.
> 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
>
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [patch] Stop runaway unwinding on stripped executables
2012-03-16 13:51 ` Mark Kettenis
@ 2012-03-16 14:46 ` Jan Kratochvil
2012-03-16 16:14 ` Mark Kettenis
0 siblings, 1 reply; 6+ messages in thread
From: Jan Kratochvil @ 2012-03-16 14:46 UTC (permalink / raw)
To: Mark Kettenis; +Cc: gdb-patches
On Fri, 16 Mar 2012 14:50:56 +0100, Mark Kettenis wrote:
> People need to learn that if they are debugging stripped stuff they're
> going to end up with runaway backtraces every now and then.
There is no need to teach that them.
> In this particular example you're just getting lucky that you're hitting
> __libc_start_main().
In other cases they end up in 'start_thread' and its caller 'clone' which
correctly undefines $pc and stops the unwinding.
> That probably wouldn't happen if you're somewhat deeper into the call stack
> of the (stripped) program that you're trying to debug.
I can only imagine code which does not use -fasynchronous-unwind-tables.
But normal distros use it, therefore they can numerically unwind anything as
well as with full debug info.
Sure the correct solution is to terminate unwinding in '_start' (like it is
terminated in 'clone'), thanks for refreshing this idea. Still GDB could have
this workaround for older code.
> But the implementation and actually the whole idea is *very*
> glibc-specific.
Yes, I was thinking about it, but glibc is neither arch nor OS specific.
Where to put it into GDB better?
Thanks,
Jan
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [patch] Stop runaway unwinding on stripped executables
2012-03-16 14:46 ` Jan Kratochvil
@ 2012-03-16 16:14 ` Mark Kettenis
2012-03-16 16:57 ` Jan Kratochvil
0 siblings, 1 reply; 6+ messages in thread
From: Mark Kettenis @ 2012-03-16 16:14 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches
> Date: Fri, 16 Mar 2012 15:45:57 +0100
> From: Jan Kratochvil <jan.kratochvil@redhat.com>
>
> On Fri, 16 Mar 2012 14:50:56 +0100, Mark Kettenis wrote:
> > In this particular example you're just getting lucky that you're hitting
> > __libc_start_main().
>
> In other cases they end up in 'start_thread' and its caller 'clone' which
> correctly undefines $pc and stops the unwinding.
I was more thinking about the unwinder failing somewhere halfway.
> > That probably wouldn't happen if you're somewhat deeper into the call stack
> > of the (stripped) program that you're trying to debug.
>
> I can only imagine code which does not use -fasynchronous-unwind-tables.
> But normal distros use it, therefore they can numerically unwind anything as
> well as with full debug info.
It's not obvious to me that -fasynchronous-unwind-tables is the
default everywhere and on all architectures. But if it is, than yes,
you have a much better chance of hitting __libc_start_main in your
backtrace.
> Sure the correct solution is to terminate unwinding in '_start'
> (like it is terminated in 'clone'), thanks for refreshing this idea.
Heh, that *is* clever!
> Still GDB could have this workaround for older code.
Not sure about that. It means more code that has to be maintained.
But then I'm not bothered by these long backtraces since they make it
immediately obvious things went off the rails for me.
> > But the implementation and actually the whole idea is *very*
> > glibc-specific.
>
> Yes, I was thinking about it, but glibc is neither arch nor OS specific.
> Where to put it into GDB better?
We have glibc-tdep.c, so sticking it in there, with an appropriate
gdbarch hook seems a logical place to me.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [patch] Stop runaway unwinding on stripped executables
2012-03-16 16:14 ` Mark Kettenis
@ 2012-03-16 16:57 ` Jan Kratochvil
2012-03-16 19:28 ` cancel: " Jan Kratochvil
0 siblings, 1 reply; 6+ messages in thread
From: Jan Kratochvil @ 2012-03-16 16:57 UTC (permalink / raw)
To: Mark Kettenis; +Cc: gdb-patches
On Fri, 16 Mar 2012 17:14:25 +0100, Mark Kettenis wrote:
> It's not obvious to me that -fasynchronous-unwind-tables is the
> default everywhere and on all architectures.
It is not but it is on all the platforms I am involved with.
> Not sure about that. It means more code that has to be maintained.
Not sure why I found better to put it in GDB first, I am more inclined now to
push the glibc fix and forget about this patch. I will see how it gets
accepted for glibc.
Thanks,
Jan
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2012-03-16 19:28 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-03-16 12:02 [patch] Stop runaway unwinding on stripped executables Jan Kratochvil
2012-03-16 13:51 ` Mark Kettenis
2012-03-16 14:46 ` Jan Kratochvil
2012-03-16 16:14 ` Mark Kettenis
2012-03-16 16:57 ` Jan Kratochvil
2012-03-16 19:28 ` cancel: " Jan Kratochvil
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox