ianlancetaylor / libbacktrace

A C library that may be linked into a C/C++ program to produce symbolic backtraces

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Suboptimal information when no debug info is available

bhaible opened this issue · comments

When no debug info is available, the library just prints question marks. It could use the /proc/self/maps file (on Linux) to at least print the binary object file in which the code resides.

How to reproduce: Compile this file
backtrace-via-libbacktrace.c.gz
on Ubuntu 16.04 in 32-bit mode:

$ gcc -m32 -g -O2 backtrace-via-libbacktrace.c -lbacktrace
$ ./a.out

It prints

08048000-0805a000 r-xp 00000000 08:06 5785797                            /home/bruno/a.out
0805a000-0805b000 r--p 00011000 08:06 5785797                            /home/bruno/a.out
0805b000-0805c000 rw-p 00012000 08:06 5785797                            /home/bruno/a.out
f75d2000-f75d3000 rw-p 00000000 00:00 0 
f75d3000-f7783000 r-xp 00000000 08:06 263678                             /lib/i386-linux-gnu/libc-2.23.so
f7783000-f7784000 ---p 001b0000 08:06 263678                             /lib/i386-linux-gnu/libc-2.23.so
f7784000-f7786000 r--p 001b0000 08:06 263678                             /lib/i386-linux-gnu/libc-2.23.so
f7786000-f7787000 rw-p 001b2000 08:06 263678                             /lib/i386-linux-gnu/libc-2.23.so
f7787000-f778a000 rw-p 00000000 00:00 0 
f778a000-f77a6000 r-xp 00000000 08:06 272038                             /lib/i386-linux-gnu/libgcc_s.so.1
f77a6000-f77a7000 rw-p 0001b000 08:06 272038                             /lib/i386-linux-gnu/libgcc_s.so.1
f77d5000-f77d6000 rw-p 00000000 00:00 0 
f77d6000-f77d8000 r--p 00000000 00:00 0                                  [vvar]
f77d8000-f77d9000 r-xp 00000000 00:00 0                                  [vdso]
f77d9000-f77fc000 r-xp 00000000 08:06 263691                             /lib/i386-linux-gnu/ld-2.23.so
f77fc000-f77fd000 r--p 00022000 08:06 263691                             /lib/i386-linux-gnu/ld-2.23.so
f77fd000-f77fe000 rw-p 00023000 08:06 263691                             /lib/i386-linux-gnu/ld-2.23.so
fff07000-fff29000 rw-p 00000000 00:00 0                                  [stack]
0x8048e55 dummy_function
        /home/bruno/backtrace-via-libbacktrace.c:18
0x8048e55 main
        /home/bruno/backtrace-via-libbacktrace.c:28
0xf75eb646 ???
        ???:0
0x8048e96 ???
        ???:0

From the maps file, it would be evident that 0xf75eb646 is an address in /lib/i386-linux-gnu/libc-2.23.so, and 0x8048e96 is an address in /home/bruno/a.out.

I doubt it's necessary to read /proc/self/maps. On GNU/Linux the relevant information is most likely available in the dl_phdr_info structs passed to phdr_callback.

Yes, quite likely. And this would also be portable to musl libc, Android, FreeBSD, NetBSD, OpenBSD, and Solaris systems, which all have the dl_iterate_phdr function.

I doubt it's necessary to read /proc/self/maps. On GNU/Linux the relevant information is most likely available in the dl_phdr_info structs passed to phdr_callback.

does anyone have example code for this? I'd like to add the binary object path to my backtraces

I have hacked in support for printing the shared object name and base address/offset by exposing the dlpi_name and dlpi_addr values provided by dl_iterate_phdr here. Basically, I just added them to the internal elf_syminfo_data struct and let them bubble up all the way to the callback provided to the public API function backtrace_syminfo(). I added the dlpi_addr value as well to easily be able to retrieve the symbol at a later time.

I'd welcome any feedback on my implementation.

You can find example code using this here which will produce the following out output:

$ ./main
   0 # stacktrace in /home/user/code/main.c:55 from executable?(+0x401417)[0x0]
   1 # main in /home/user/code/main.c:60 from executable?(+0x40149c)[0x0]
   2 # __libc_start_main in ../csu/libc-start.c:332 from /lib64/libc.so.6(+0x27a50)[0x7feffe060000]
   3 # unknown in ../sysdeps/x86_64/start.S:120 from executable?(+0x4011d0)[0x0]
   4 # unknown in unknown:0 from executable?(+0x0)[0x0]
$ addr2line -e /lib64/libc.so.6 0x27a50
/usr/src/debug/glibc-2.33-5.2.x86_64/csu/../csu/libc-start.c:144

@barathrm just tried it in my app, looks good enough for me, thanks!

../src/utils/backtrace.c (_backtrace_get:339)
../src/zrythm_app.c (segv_handler:147)
??? unknown
../src/gui/widgets/channel_slot.c (drag_end:563)
??? unknown
??? g_signal_emit_valist from /usr/lib/libgobject-2.0.so.0(+0x2ee20)[0x7ffff7312000]
??? g_signal_emit from /usr/lib/libgobject-2.0.so.0(+0x30180)[0x7ffff7312000]
??? g_cclosure_marshal_VOID__BOXEDv from /usr/lib/libgobject-2.0.so.0(+0x17650)[0x7ffff7312000]
??? g_signal_emit_valist from /usr/lib/libgobject-2.0.so.0(+0x2ee20)[0x7ffff7312000]
??? g_signal_emit from /usr/lib/libgobject-2.0.so.0(+0x30180)[0x7ffff7312000]
??? unknown
??? unknown
??? unknown
??? gtk_event_controller_handle_event from /usr/lib/libgtk-3.so.0(+0x15a290)[0x7ffff77f3000]
??? unknown
??? unknown
??? unknown
??? gtk_main_do_event from /usr/lib/libgtk-3.so.0(+0x1df910)[0x7ffff77f3000]
??? unknown
??? unknown
??? g_main_context_dispatch from /usr/lib/libglib-2.0.so.0(+0x53dd0)[0x7ffff71dd000]
??? unknown
??? g_main_context_iteration from /usr/lib/libglib-2.0.so.0(+0x51750)[0x7ffff71dd000]
??? g_application_run from /usr/lib/libgio-2.0.so.0(+0xcd060)[0x7ffff736c000]
../src/main.c (main:52)
??? __libc_start_main from /usr/lib/libc.so.6(+0x27a50)[0x7ffff5fb2000]
??? _start from (+0x846ad0)[0x555555554000]
??? unknown

it would also be nice to have a way to run addr2line -e via a library call instead of having to run that binary

@barathrm just tried it in my app, looks good enough for me, thanks!

nice :)

it would also be nice to have a way to run addr2line -e via a library call instead of having to run that binary

Note that it's not necessary to run addr2line if you have the debug symbols installed in a default location, as libbacktrace will display the source code line corresponding to that address in that case. I only ran it to illustrate that the offset/base address is valid, so that if your program crashes in an environment which lacks those debug symbols (for example with a user who doesn't have the debug symbols installed), you can still take that address and find out what function was involved yourself, manually, after the crash.

For instance above, you can see that libbacktrace gave you ??? g_signal_emit from /usr/lib/libgobject-2.0.so.0(+0x30180)[0x7ffff7312000] because you have the libgobject-2.0 debug symbols, so you don't need to run addr2line for that.

Note that it's not necessary to run addr2line if you have the debug symbols installed in a default location, as libbacktrace will display the source code line corresponding to that address in that case

ah, I see, thanks

btw your version failed to build on macos and I fixed it: alex-tee@2cd5ac4

I am guessing there is more architecture-specific code that needs to be edited