According to the documentation I can break on specific exception type by using conditional breakpoints. However the syntax for the condition isn\'t very clear to me:
Let's assume you have the following code.cpp with a thread that throws an exception:
#include
#include
void thr()
{
while (true) {
new int[1000000000000ul];
}
}
int main(int argc, char* argv[]) {
std::thread t(thr);
t.join();
std::cout << "Hello, World!" << std::endl;
return 0;
}
Compile it with using the following CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(tutorial)
set(CMAKE_CXX_STANDARD 11)
add_executable(test_exceptions main.cpp)
target_link_libraries(test stdc++ pthread)
Now you can play with, running it will give you an abort because of bad_alloc.
Before going on, it's better if you install libstd debug symbols, sudo apt-get install libstdc++6-5-dbg or whatever version you have.
If you are compiling in Debug you can follow this answer https://stackoverflow.com/a/12434170/5639395 because constructors are usually defined.
If you are compiling in DebWithRelInfo you may not be able to find a proper constructor where to put your breakpoint because of the compiler optimization. In this case, you have some other options. Let's continue.
If you can change the source code easily, this will work https://stackoverflow.com/a/9363680/5639395
If you don't want to change the code, you can try to see if catch throw bad_alloc or in general catch throw exception_name works.
I will build on top of this answer https://stackoverflow.com/a/6849989/5639395
We will add a breakpoint in gdb in the function __cxxabiv1::__cxa_throw . This function takes a parameter called tinfo that has the information we need to conditionally check for the exception we care about.
We want something like catch throw if exception==bad_alloc, so how to find the proper comparison?
It turns out that tinfo is a pointer to a structure that has a variable called __name inside. This variable has a string with the mangled name of the exception type.
So we can do something like: catch throw if tinfo->__name == mangled_exception_name
We are almost there!
We need a way to do string comparison, and it turns out gdb has a built-in function $_streq(str1,str2) that does exactly what we need. The mangled name of the exception is a little harder to find, but you can try to guess it or check the Appendix of this answer. Let's assume for now it is "St9bad_alloc".
The final instruction is:
catch throw if $_streq(tinfo->__name , "St9bad_alloc")
or equivalent
break __cxxabiv1::__cxa_throw if $_streq(tinfo->__name , "St9bad_alloc")
You have two options
Assuming that you installed the libstd debug symbols, you can find the library name like this:
apt search libstd | grep dbg | grep installed
The name is something like this libstdc++6-5-dbg
Now check the files installed:
dpkg -L libstdc++6-5-dbg
Look for something that has a debug in the path, and a .so extension. In my pc I have /usr/lib/x86_64-linux-gnu/debug/libstdc++.so.6.0.21.
Finally, look for the exception you want in there.
nm /usr/lib/x86_64-linux-gnu/debug/libstdc++.so.6.0.21 | grep -i bad_alloc
Or
nm /usr/lib/x86_64-linux-gnu/debug/libstdc++.so.6.0.21 | grep -i runtime_error
etc.
In my case I found something like 00000000003a4b20 V _ZTISt9bad_alloc which suggested me to use "St9bad_alloc" as the name.
This is easy, just start gdb, catch throw everything and run the small executable I wrote before. When you are inside gdb, you can issue a p *tinfo and look for the __name description from gdb.
gdb -ex 'file test_exceptions' -ex 'catch throw' -ex 'run'
(gdb) p *tinfo
$1 = {_vptr.type_info = 0x406260