gdb
's add-symbol-file
command is versatile and powerful, but it has some gotchas that will catch the unaware. I haven't found good examples showing how to use it, so I thought I'd write down a few notes:
First, you can read the official documentation, to get a general idea: Commands to specify files.
There is a variety of situations where you'll have gdb
attached to a process and it won't find the dynamic modules and debug symbols. In the example below we have a game running under proton that spits out an error message and crashes: *** bit out of range 0 - FD_SETSIZE on fd_set ***: terminated.
A bit of googling and you'll know this crashes in glibc
. We would like to obtain a backtrace and investigate, but here is what we have as a starting point:
Thread 248 "IPC:CSteamEngin" received signal SIGABRT, Aborted.
[Switching to LWP 1059407]
0x00007b0c1edd683c in ?? ()
(gdb) bt
#0 0x00007b0c1edd683c in ?? ()
#1 0x0000000000000000 in ?? ()
We know we should be in glibc
, we can verify this by looking at the maps:
root@vanguard ~# cat /proc/1059034/maps | grep libc
7b0c1ed48000-7b0c1ed6e000 r--p 00000000 00:19 43674755 /run/host/usr/lib/libc.so.6
7b0c1ed6e000-7b0c1eec8000 r-xp 00026000 00:19 43674755 /run/host/usr/lib/libc.so.6
7b0c1eec8000-7b0c1ef1c000 r--p 00180000 00:19 43674755 /run/host/usr/lib/libc.so.6
We are interested in the executable section (r-xp), also known as the .text
section. 7b0c1edd683c is within 7b0c1ed6e000-7b0c1eec8000, that checks out.
But gdb didn't load the symbols for glibc, can we fix that?
This is where the fun begins! Based on the documentation, one might be tempted to type:
add-symbol-file /usr/lib/libc.so.6 0x7b0c1ed6e000
gdb happily eats that up, finds the glibc debug symbols on Arch's debuginfod servers, and shows you this:
(gdb) bt
#0 0x00007b0c1edd683c in __pthread_mutex_cond_lock_full (mutex=0x102a4f) at ../nptl/pthread_mutex_lock.c:514
#1 0x0000000000000000 in ?? ()
Still no backtrace. Mutexes when we should be in FD_SET and friends? What gives?
It turns out we gave gdb the wrong address, and since it doesn't know any better, it did what we asked for, loaded the symbols in the wrong location and now they are off. We need to figure the correct address for the .text
section.
We can use readelf
to find the offset of the .text
section:
readelf -S /usr/lib/libc.so.6
The offset is 263c0
And the /proc/1059034/maps above reports that offset 26000 in libc.so.6 was loaded at address 7b0c1ed6e000
So that's the correction we need. The .text
section is actually at 7b0c1ed6e000 + 3c0:
add-symbol-file /usr/lib/libc.so.6 -s .text 0x7b0c1ed6e3c0
Now we get the beginnings of a valid backtrace:
(gdb) bt
#0 __pthread_kill_implementation (threadid=<optimized out>, signo=signo@entry=6, no_tid=no_tid@entry=0) at pthread_kill.c:44
#1 0x00007b0c1edd68a3 in __pthread_kill_internal (signo=6, threadid=<optimized out>) at pthread_kill.c:78
#2 0x00007b0c1ed86668 in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
#3 0x00007b0c1ed6e4b8 in __GI_abort () at abort.c:79
#4 0x00007b0c1ed6f390 in __libc_message (fmt=fmt@entry=0x7b0c1eee62fc "*** %s ***: terminated\n") at ../sysdeps/posix/libc_fatal.c:150
#5 0x00007b0c1ee66b4b in __GI___fortify_fail (msg=msg@entry=0x7b0c1eeeb418 "bit out of range 0 - FD_SETSIZE on fd_set") at fortify_fail.c:24
#6 0x00007b0c1ee66642 in __GI___fdelt_chk (d=<optimized out>) at fdelt_chk.c:26
#7 0x00007b0c1a067f26 in ?? ()
Frame #7 is in steamclient.so
, which I can't show you here, but the same process applies to load the symbols in and get the complete trace (if you have them that is).
I've been bit by this on several occasions. Now I have some notes I can go back to! I hope it'll be useful to someone else.