There seems to be no post with reasonably condensed information on this topic (in a solution/howto format, not complete-and-hard-to-find-details-you-need documentation), so I thought gathering these misc. pieces might be useful.

To debug execution of your program inside a shared library we need a bit more than just compiling it with -g. Let’s see a simple case - a program using a call to a function from SDL2_mixer, as an example.

Initially requesting step-into results in step-over:

78              audio_mix_chunks[i] = Mix_LoadWAV(fname);
(gdb) s
80              if (audio_mix_chunks[i] == NULL)

and, well, that’s not what we want…

Two things are probably missing: debug information in the binary (library in this case), and the source code for it.

Debug information for the library

In case of Debian - you just have to install libXYZ-dbg package (where XYZ is the library you want to examine). So:

$ aptitude install libsdl2-mixer-dbg

and we have:

(gdb) s
Mix_LoadWAV_RW (src=0x7fffffffe270, freesrc=4203968) at mixer.c:573
573     mixer.c: No such file or directory.
(gdb) s
581     in mixer.c
(gdb) s
587     in mixer.c
(gdb) s
596     in mixer.c

Now, we can see the line number and the name of the source file - but gdb does not show any code… In this case the reason is that this external code is not a part of our code, but is one of the sources of a dynamically linked library (here SDL2_mixer).

This leads us to the 2nd missing thing:

The source code of the library

We know more less how to get it ;-), eg.:

$ apt-get source libsdl2-mixer-dev

what results in my case in sources in libsdl2-mixer-2.0.0+dfsg1/.

But where should we put them so that gdb finds them?

(gdb) s
Mix_LoadWAV_RW (src=0x7fffffffe270, freesrc=4203968) at mixer.c:573
573     mixer.c: No such file or directory.
(gdb) info frame
Stack level 0, frame at 0x7fffffffe140:
 rip = 0x7ffff6b04be0 in Mix_LoadWAV_RW (mixer.c:573); saved rip = 0x4092b6
 called by frame at 0x7fffffffe280
 source language c.
 Arglist at 0x7fffffffe130, args: src=0x7fffffffe270, freesrc=4203968
 Locals at 0x7fffffffe130, Previous frame's sp is 0x7fffffffe140
 Saved registers:
  rip at 0x7fffffffe138

– and still no clue…

Since libSDL2_mixer is clearly dependent on libSDL2 we can try:

$ apt-get install libsdl2-dbg

– and now(!):

78              audio_mix_chunks[i] = Mix_LoadWAV(fname);
(gdb) s
SDL_RWFromFile (a=0x7fffffffe160 "data/snd/S00.wav", b=0x43b7bf "rb")
    at /tmp/buildd/libsdl2-2.0.2+dfsg1/src/dynapi/SDL_dynapi_procs.h:386
386     /tmp/buildd/libsdl2-2.0.2+dfsg1/src/dynapi/SDL_dynapi_procs.h: No such file or directory.

(gdb) info frame
Stack level 0, frame at 0x7fffffffe140:
 rip = 0x7ffff6d925b0 in SDL_RWFromFile
    (/tmp/buildd/libsdl2-2.0.2+dfsg1/src/dynapi/SDL_dynapi_procs.h:386); saved rip = 0x4092a9
 called by frame at 0x7fffffffe280
 source language c.
 Arglist at 0x7fffffffe130, args: a=0x7fffffffe160 "data/snd/S00.wav", b=0x43b7bf "rb"
 Locals at 0x7fffffffe130, Previous frame's sp is 0x7fffffffe140
 Saved registers:
  rip at 0x7fffffffe138

Finally gdb is informing us nicely where it expects the source code of the libraries - so we can provide it:

$ mkdir /tmp/buildd ; cd /tmp/buildd/
$ apt-get source libsdl2-mixer-dev
$ apt-get source libsdl2-dev

This time we should see what’s inside the library, for instance:

78              audio_mix_chunks[i] = Mix_LoadWAV(fname);
(gdb) s
SDL_RWFromFile (a=0x7fffffffe160 "data/snd/S00.wav", b=0x43b7bf "rb")
    at /tmp/buildd/libsdl2-2.0.2+dfsg1/src/dynapi/SDL_dynapi_procs.h:386
386     SDL_DYNAPI_PROC(SDL_RWops*,SDL_RWFromFile,(const char *a, const char *b),(a,b),return)
(gdb) s
SDL_RWFromFile_REAL (file=0x7fffffffe160 "data/snd/S00.wav", mode=0x43b7bf "rb")
    at /tmp/buildd/libsdl2-2.0.2+dfsg1/src/file/SDL_rwops.c:461
461         if (!file || !*file || !mode || !*mode) {
(gdb) s
459     {
(gdb) s
461         if (!file || !*file || !mode || !*mode) {
(gdb) s
526             FILE *fp = fopen(file, mode);
(gdb) n
528             if (fp == NULL) {

There is also another (better!) way to find out the source files and their paths, as expected by gdb:

(gdb) info sources

(a looong list...)

/tmp/buildd/libsdl2-mixer-2.0.0+dfsg1/music.c, /tmp/buildd/libsdl2-mixer-2.0.0+dfsg1/mixer.c,

(another looong list...)

– although it is necessary to go through a looong list of files.

Information on another blog suggests that it is possible also to specify gdb the directory with sources doing eg:

(gdb) dir /var/tmp/sources/libc6/eglibc-2.15/malloc/

even saving in a file:

$ echo dir /var/tmp/sources/libc6/eglibc-2.15/malloc/ > gdb.setup
$ gdb program -c core -x gdb.setup

but (if I understand it well…) it specifies a single directory, not complete directory tree with all sources of a library that can be used easily by gdb.

  1. Debian maintainer’s guide
  2. Debian Policy Manual
  3. Few GDB Commands – Debug Core, Disassemble, Load Shared Library (Blog article)
  4. Make system library source code available to gdb on Ubuntu
  5. Related GDB docs:

Misc.

  • useful gdb commands
    • (gdb) info sharedlibrary
    • (gdb) info sources
    • (gdb) info frame