例外の発生箇所を gdb で捕捉する

gdb で catch throw を使えば例外を捕捉できるという話をコメントで教えていただいたので、試してみた。

#include <string>

static void foo(void);

int main()
{
    foo();
    return 0;
}

static void foo()
{
    std::string s = "abc";
    s.replace(-1, 0, "d");
}
% g++ -g -Wall -W -O2 exc_bt.cpp -o exc_bt
% gdb exc_bt
GNU gdb 6.4.90-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/libthread_db.so.1".

(gdb) catch throw
Function "__cxa_throw" not defined.
(gdb)

ん?なんでだ。Google で検索してみたら、とりあえずプログラムを実行しないと設定できないらしい。たぶん必要な symbol を動的に解決しているんだろう。

% gdb exc_bt
GNU gdb 6.4.90-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/libthread_db.so.1".

(gdb) b main
Breakpoint 1 at 0x8048630: file exc_bt.cpp, line 13.
(gdb) run
Starting program: /home/oda/tmp/exc_bt

Breakpoint 1, main () at exc_bt.cpp:13
13          std::string s = "abc";
(gdb) catch throw
Catchpoint 2 (throw)
(gdb) c
Continuing.

Catchpoint 2 (exception thrown)
0xb7faaec5 in __cxa_throw () from /usr/lib/libstdc++.so.6
(gdb) bt
#0  0xb7faaec5 in __cxa_throw () from /usr/lib/libstdc++.so.6
#1  0xb7f41e5f in std::__throw_out_of_range () from /usr/lib/libstdc++.so.6
#2  0xb7f88a7e in std::string::replace () from /usr/lib/libstdc++.so.6
#3  0x0804867b in main () at /usr/include/c++/4.1.3/bits/basic_string.h:1246
(gdb)

うはは、インライン展開されてしまって意味がわからんね。まぁ、このへんは LD_PRELOAD を使って無理やりやったやつでも一緒。ということで -fno-inline をつけてリコンパイル

% g++ -g -Wall -W -O2 -fno-inline exc_bt.cpp -o exc_bt
% gdb exc_bt
GNU gdb 6.4.90-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/libthread_db.so.1".

(gdb) b main
Breakpoint 1 at 0x8048691: file exc_bt.cpp, line 7.
(gdb) run
Starting program: /home/oda/tmp/exc_bt

Breakpoint 1, main () at exc_bt.cpp:7
7           foo();
(gdb) catch throw
Catchpoint 2 (throw)
(gdb) c
Continuing.

Catchpoint 2 (exception thrown)
0xb7faaec5 in __cxa_throw () from /usr/lib/libstdc++.so.6
(gdb) bt
#0  0xb7faaec5 in __cxa_throw () from /usr/lib/libstdc++.so.6
#1  0xb7f41e5f in std::__throw_out_of_range () from /usr/lib/libstdc++.so.6
#2  0xb7f88a7e in std::string::replace () from /usr/lib/libstdc++.so.6
#3  0xb7f88d13 in std::string::replace () from /usr/lib/libstdc++.so.6
#4  0x08048639 in foo () at exc_bt.cpp:14
#5  0x08048696 in main () at exc_bt.cpp:7
(gdb)

すばらしい。