06 August 2009

gdbでxsをデバッグ

xsで書かれたモジュールなどを、gdbを使ってデバッグする方法がわかりました。やり方は以外とストレートで、

  1. -gオプションをつけてコンパイルする。その際、最適化オプションは外す
  2. gdb --args perl foo.pl という風に、perlのコマンドごとgdbに渡す

という、普通にcのコードをデバッグするのと同じ要領です。

perlを-dをつけて起動すると、perlのデバッガを使いつつ、cのコードの方に処理が移ったときには、gdbでデバッグということもできます。

% gdb --args perl -d -I.libs t/index.t
GNU gdb 6.3.50-20050815 (Apple version gdb-962) (Sat Jul 26 08:14:40 UTC 2008)
Copyright 2004 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 "i386-apple-darwin"...Reading symbols for shared libraries ..... done

// c側のブレイクポイントを設置

(gdb) b _wrap_delete_WritableDatabase
Function "_wrap_delete_WritableDatabase" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (_wrap_delete_WritableDatabase) pending.

// プログラムを走らせる

(gdb) r
Starting program: /usr/bin/perl -d -I.libs t/index.t
Reading symbols for shared libraries ++++. done
Reading symbols for shared libraries warning: Could not find object file "/Users/kosei/.cpan/build/IO-1.25/IO.o" - no debug information available for "IO.c".

warning: Could not find object file "/Users/kosei/.cpan/build/IO-1.25/poll.o" - no debug information available for "poll.c".

. done

// perlのデバッガが起動

Loading DB routines from perl5db.pl version 1.28
Editor support available.

Enter h or `h h' for help, or `man perldebug' for more help.

1..81
Reading symbols for shared libraries .... done
Breakpoint 1 at 0x101d64f: file xapian_wrap.cc, line 28259.
Pending breakpoint 1 - "_wrap_delete_WritableDatabase" resolved
main::(t/index.t:17):   foreach my $backend ("inmemory", "auto") {
  DB<1> c

///////// 省略 //////////

// ブレイクポイントでちゃんと止まる。ここからはgdb

Breakpoint 1, _wrap_delete_WritableDatabase (my_perl=0x800000, cv=0x9677a8) at xapian_wrap.cc:28259
28259       dXSARGS;
(gdb) 

今回はXapianというライブラリのデバッグをしているのですが、こうしたある程度の規模のモジュールだと、makefileやconfigure.acが結構大きくなっているので、オプションのつけ外しで苦労しています。-gはCXX_FLAGSみたいな名前の変数に入れてやればいいのですが、最適かオプションがどこでオンになっているのか、まだ見つけられてないです。

もう一点少し困っているのが、ブレイクポイントがうまく設置できないことです。XS_Search__Xapian__WritableDatabase_DESTROYという関数にブレイクポイントを置きたいんですが、この関数名で指定してもうまくいきませんでした。代わりに、backtrace() と backtrace_symbols_fd()でプリントしたバックトレースの表示で見えている関数名で指定すると、うまくいきます。

(gdb) b XS_Search__Xapian__WritableDatabase_DESTROY       // うまくいかない
(gdb) b _Z43XS_Search__Xapian__WritableDatabase_DESTROYP11interpreterP2cv   // うまくいく

よくわかりません…

同様に、SWIGで生成したプログラムもデバッグしているのですが、こちらは問題なくデバッグできてます。SWIGも裏ではXSを自動生成しているので、当然ですね。

参考

xs を gdb で debug する - Vox