gdb でおっかけ
see ぐあ間違えてリンクしてた - daily dayflower
ソースのパスの指定の仕方がわかったのでソースコードデバッグをしてみます。
$ gdb test GNU gdb 6.8-debian ...... snip snip snip ...... This GDB was configured as "i486-linux-gnu"... (gdb) set environment LD_LIBRARY_PATH=/usr/lib/debug
ソース検索パスを追加するには directory
コマンドを使います。
(gdb) directory /home/dayflower/src/samba-3.0.28a/source Source directories searched: /home/dayflower/src/samba-3.0.28a/source:$cdir:$cwd
個人的に lib/debug.c
の debug_add_class()
での挙動が怪しいとにらんでいるので breakpoint を設定します。
(gdb) b debug_add_class Function "debug_add_class" not defined. Make breakpoint pending on future shared library load? (y or [n]) y Breakpoint 1 (debug_add_class) pending.
まだ共有ライブラリがロードされていないので,そのシンボルしらないけど,ペンディングしとく?と聞かれました。y
を入力して,breakpoint を予約しておきます。
いざデバッグ。
(gdb) start SMB_SERVER_NAME Breakpoint 2 at 0x80484d5: file test.c, line 25. Starting program: /home/dayflower/test SMB_SERVER_NAME [Thread debugging using libthread_db enabled] [New Thread 0xb78e06d0 (LWP 8393)] [Switching to Thread 0xb78e06d0 (LWP 8393)] main (argc=2, argv=0xbf849974) at test.c:25 25 hp = gethostbyname(argv[1]);
んーなんか thread が生成されてますが,main の最初で止まりました。
breakpoint まで進めるために continue
します。
(gdb) cont Continuing. Breakpoint 1, debug_add_class (classname=0xb789b6f9 "all") at lib/debug.c:304 304 if (!classname)
おお,無事 breakpoint で止まりました。
ソースはきちんと見れるでしょうか?list
コマンドを使います。
(gdb) l 299 int debug_add_class(const char *classname) 300 { 301 int ndx; 302 void *new_ptr; 303 304 if (!classname) 305 return -1; 306 307 /* check the init has yet been called */ 308 debug_init();
きちんと Samba の対応するソースが読み込めているらしいです。
なお,今回睨んでいる関数の先頭部分を引用しておきます。
int debug_add_class(const char *classname) { int ndx; void *new_ptr; if (!classname) return -1; /* check the init has yet been called */ debug_init(); ndx = debug_lookup_classname_int(classname); if (ndx >= 0) return ndx; ndx = debug_num_classes; new_ptr = DEBUGLEVEL_CLASS; if (DEBUGLEVEL_CLASS == &debug_all_class_hack) { /* Initial loading... */ new_ptr = NULL; } new_ptr = SMB_REALLOC_ARRAY(new_ptr, int, debug_num_classes + 1); /******* snip snip snip *******/
憶測としては,Initial loading なのに new_ptr = NULL;
が実行されていないのではないか,というところです。なので realloc でエラーがでてしまうのではないか,と。
さてさて。同一ソース内でステップ実行するには next
コマンドを使います。
(gdb) n 308 debug_init();
ちなみに,next
コマンドで表示される行は,次に実行されるべき行です。
next
でステップ実行していきます。
(gdb) n 310 ndx = debug_lookup_classname_int(classname); (gdb) n 311 if (ndx >= 0) (gdb) n 310 ndx = debug_lookup_classname_int(classname); (gdb) n 311 if (ndx >= 0)
あれあれ?とくにループもないのに,行を後戻りしました。
よくわからないですが進めます。
(gdb) n 315 new_ptr = DEBUGLEVEL_CLASS; (gdb) n 313 ndx = debug_num_classes; (gdb) n 315 new_ptr = DEBUGLEVEL_CLASS;
あれ?またバックステップが発生しました。
(gdb) n 316 if (DEBUGLEVEL_CLASS == &debug_all_class_hack) {
ここの挙動がとくにあやしいと睨んでいるので,変数を表示させてみます。
print
コマンドで変数を表示することができます。
(gdb) print DEBUGLEVEL_CLASS $1 = (int *) 0xb78b670c (gdb) print &debug_all_class_hack $2 = (int *) 0xb78b670c (gdb) print new_ptr $3 = (void *) 0xb7ed906c
DEBUGLEVEL_CLASS
と &debug_all_class_hack
は同一になっています。なので new_ptr
は NULL
で初期化されるはずです。
でも new_ptr
は現時点で DEBUGLEVEL_CLASS
になっているはずなのに,すでにおかしいですね。
さて,next
してみます。
(gdb) n 320 new_ptr = SMB_REALLOC_ARRAY(new_ptr, int, debug_num_classes + 1);
見事に new_ptr = NULL;
がすっとばされました(泣)。
進めます。
(gdb) n 316 if (DEBUGLEVEL_CLASS == &debug_all_class_hack) { (gdb) n 320 new_ptr = SMB_REALLOC_ARRAY(new_ptr, int, debug_num_classes + 1); (gdb) n *** glibc detected *** /home/dayflower/test: realloc(): invalid pointer: 0xb7ed906c *** ======= Backtrace: ========= /usr/lib/debug/libc.so.6[0xb7bf8c37] ...... snip snip snip ...... Program received signal SIGABRT, Aborted. 0xb7bbb1b6 in *__GI_raise (sig=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64 64 ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory. in ../nptl/sysdeps/unix/sysv/linux/raise.c
またなぜかバックステップが発生して,その後 SMB_REALLOC_ARRAY()
に進み,エラーが発生してしまいました。
おそらく,最適化が強くはたらいておりソースコードと一対一対応できてないのではないかなーと思います。それともスレッドのせい?
結局 libc:gethostbyname()
が悪いのか debug_add_class()
が悪いのかはわからないままです。
なーんとなく DEBUGLEVEL_CLASS
を volatile
宣言すればいいような気もするのですが……