How to find the place where an exception is thrown in C++?

Question:

The application with the exception crashes, in the backtrace (gdb) – system calls. Is there any way to find the place where the exception is thrown?

terminate called after throwing an instance of 'std::system_error'
what(): Invalid argument

gcc 4.8, debian

Dump: http://pastebin.com/ffX5mJqz

Answer:

Just write a catch throw to gdb before running the program. After that, gdb will stop whenever an exception is thrown at the location where it was thrown.

UPD : about catching certain types of exceptions. On my gdb platform, calling catch throw simply puts a breakpoint on the __cxxabiv1::__cxa_throw . This is an internal function that is called when an exception is thrown. If you look closely, among other things, typeinfo is passed to it about the type of the thrown exception. Therefore, you can simply put a condition on the breakpoint by the value of this parameter.

An example of how to get the stack trace for an exception with type std::invalid_argument :

$ cat test.cc
#include <stdexcept>

void foo() {
  throw std::invalid_argument("other_invalid_argument");
}

int main() {
  try {
    throw std::invalid_argument("invalid_argument");
  } catch (...) { }
  try {
    throw std::range_error("range_error");
  } catch (...) { }
  foo();
}

$ g++ -g -O0 ./test.cc
$ ./a.out
terminate called after throwing an instance of 'std::invalid_argument'
  what():  other_invalid_argument
Aborted (core dumped)

$ gdb --args ./a.out
(gdb) catch throw
Catchpoint 1 (throw)
(gdb) r
Starting program: /tmp/a.out 
Loading gdb's copy of v17 libstdc++ pretty-printers.
Catchpoint 1 (exception thrown), __cxxabiv1::__cxa_throw (obj=0x603090, 
    tinfo=0x6020d0 <typeinfo for std::invalid_argument@@GLIBCXX_3.4>, 
    dest=0x400ab0 <std::invalid_argument::~invalid_argument()@plt>)
    at ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc:62
62  ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc: No such file or directory.
(gdb) set $info=tinfo             <-- запоминаем tinfo
(gdb) cond 1 tinfo==$info         <-- ставим условие на catchpoint
(gdb) c    
Continuing.
Catchpoint 1 (exception thrown), __cxxabiv1::__cxa_throw (obj=0x603090, 
    tinfo=0x6020d0 <typeinfo for std::invalid_argument@@GLIBCXX_3.4>, 
    dest=0x400ab0 <std::invalid_argument::~invalid_argument()@plt>)
    at ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc:62
62  in ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc
(gdb) bt  <-- интересующий нас стектрейс
#0  __cxxabiv1::__cxa_throw (obj=0x603090, 
    tinfo=0x6020d0 <typeinfo for std::invalid_argument@@GLIBCXX_3.4>, 
    dest=0x400ab0 <std::invalid_argument::~invalid_argument()@plt>)
    at ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc:62
#1  0x0000000000400c5f in foo () at ./test.cc:4
#2  0x0000000000400de9 in main () at ./test.cc:14

UPD2 : I came up with another way, though it does not work for multi-threaded programs. You can create a checkpoint every time an exception is thrown, and after the program crashes, restore from the last checkpoint. The program is the same as above:

$ gdb --args ./a.out
(gdb) catch throw
Catchpoint 1 (throw)
(gdb) commands 1
Type commands for breakpoint(s) 1, one per line.
End with a line saying just "end".
>checkpoint 
>c
>end
(gdb) r
Starting program: /tmp/a.out 
Loading gdb's copy of v17 libstdc++ pretty-printers.
Catchpoint 1 (exception thrown), __cxxabiv1::__cxa_throw (obj=0x603090, 
    tinfo=0x6020d0 <typeinfo for std::invalid_argument@@GLIBCXX_3.4>, 
    dest=0x400ab0 <std::invalid_argument::~invalid_argument()@plt>)
    at ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc:62
62  ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc: No such file or directory.
Catchpoint 1 (exception thrown), __cxxabiv1::__cxa_throw (obj=0x603090, 
    tinfo=0x6020b0 <typeinfo for std::range_error@@GLIBCXX_3.4>, 
    dest=0x400a10 <std::range_error::~range_error()@plt>)
    at ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc:62
62  in ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc
Catchpoint 1 (exception thrown), __cxxabiv1::__cxa_throw (obj=0x603090, 
    tinfo=0x6020d0 <typeinfo for std::invalid_argument@@GLIBCXX_3.4>, 
    dest=0x400ab0 <std::invalid_argument::~invalid_argument()@plt>)
    at ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc:62
62  in ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc
terminate called after throwing an instance of 'std::invalid_argument'
  what():  other_invalid_argument

Program received signal SIGABRT, Aborted.
0x00007ffff7531cc9 in __GI_raise (sig=sig@entry=6)
    at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
56  ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) info checkpoints
  3 process 20315 at 0x7ffff7b348b0, file ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc, line 62
  2 process 20314 at 0x7ffff7b348b0, file ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc, line 62
  1 process 20313 at 0x7ffff7b348b0, file ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc, line 62
* 0 process 20309 (main process) at 0x7ffff7531cc9, file ../nptl/sysdeps/unix/sysv/linux/raise.c, line 56
(gdb) restart 3
Switching to process 20315
#0  __cxxabiv1::__cxa_throw (obj=0x603090, 
    tinfo=0x6020d0 <typeinfo for std::invalid_argument@@GLIBCXX_3.4>, 
    dest=0x400ab0 <std::invalid_argument::~invalid_argument()@plt>)
    at ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc:62
62  ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc: No such file or directory.
(gdb) bt
#0  __cxxabiv1::__cxa_throw (obj=0x603090, 
    tinfo=0x6020d0 <typeinfo for std::invalid_argument@@GLIBCXX_3.4>, 
    dest=0x400ab0 <std::invalid_argument::~invalid_argument()@plt>)
    at ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc:62
#1  0x0000000000400c5f in foo () at ./test.cc:4
#2  0x0000000000400de9 in main () at ./test.cc:14
Scroll to Top