Linux で glib のソースコードを gdb で追ってみる

glib を使っているプログラムを実行するときに、デバッグ版の共有ライブラリをリンクすると、gdb で実行中のバイナリに対応するソースコードを追うことができる。

まず、インストールされている glib のバージョンを調べる。

$ pkg-config --modversion glib-2.0
2.14.1

このバージョンの glib をダウンロードして展開して configure する。CFLAGS="-g" を指定しないと、CFLAGS に -O2 オプションがついてしまいバイナリが最適化コンパイルされてしまうようだ。そうするとデバッグ時にバイナリとソースコードが対応しなくて困ることになる (実は最初この問題ではまったorz) 。

$ wget http://ftp.gnome.org/pub/gnome/sources/glib/2.14/glib-2.14.1.tar.bz2
$ tar jxf glib-2.14.1.tar.bz2
$ cd glib-2.14.1
$ ./configure CFLAGS="-g"

make する。(make install は不要)

$ make

ここまでの操作で、./glib/.libs の中に libglib-2.0.so ができているはず。これがデバッグ版の glib となる。

この後、プログラムを実行するとき環境変数 LD_LIBRARY_PATH にこのデバッグ版の glib のパスを指定すると、gdbソースコードを追うことができるようになる。こんな感じ。

$ LD_LIBRARY_PATH=/home/.../glib-2.14.1/glib/.libs/ gdb ./sample
GNU gdb 6.6-debian
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...
Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".
(gdb) run
Starting program: /home/.../sample
^C
Program received signal SIGINT, Interrupt.
0xffffe410 in __kernel_vsyscall ()
(gdb) i s
#0  0xffffe410 in __kernel_vsyscall ()
#1  0xb7dbd5ab in poll () from /lib/tls/i686/cmov/libc.so.6
#2  0xb7e855f3 in g_main_context_poll (context=0x804a008, timeout=1000,
    priority=2147483647, fds=0x0, n_fds=0) at gmain.c:2996
#3  0xb7e849ba in g_main_context_iterate (context=0x804a008, block=1,
    dispatch=1, self=0x804ae98) at gmain.c:2689
#4  0xb7e851c5 in IA__g_main_loop_run (loop=0x804ae88) at gmain.c:2898
#5  0x080484ea in main () at example2.c:22
(gdb) up 2
#2  0xb7e855f3 in g_main_context_poll (context=0x804a008, timeout=1000,
    priority=2147483647, fds=0x0, n_fds=0) at gmain.c:2996
2996          if ((*poll_func) (fds, n_fds, timeout) < 0 && errno != EINTR)
(gdb) list
2991          LOCK_CONTEXT (context);
2992
2993          poll_func = context->poll_func;
2994
2995          UNLOCK_CONTEXT (context);
2996          if ((*poll_func) (fds, n_fds, timeout) < 0 && errno != EINTR)
2997            {
2998    #ifndef G_OS_WIN32
2999              g_warning ("poll(2) failed due to: %s.",
3000                         g_strerror (errno));
(gdb)