假设您有以下 code.cpp 和一个抛出异常的线程:
#include <iostream>
#include <thread>
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;
}
使用以下 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)
现在你可以玩了,运行它会让你因为 bad_alloc 而中止。
在继续之前,最好安装 libstd 调试符号、sudo apt-get install libstdc++6-5-dbg 或您拥有的任何版本。
调试编译
如果您在Debug 中编译,您可以按照https://stackoverflow.com/a/12434170/5639395 这个答案进行操作,因为通常会定义构造函数。
发布编译
如果您在DebWithRelInfo 中编译,由于编译器优化,您可能无法找到合适的构造函数来放置断点。在这种情况下,您还有其他一些选择。让我们继续吧。
源码更改解决方案
如果您可以轻松更改源代码,这将起作用https://stackoverflow.com/a/9363680/5639395
gdb catch throw 简单的解决方案
如果您不想更改代码,可以尝试查看catch throw bad_alloc 或一般catch throw exception_name 是否有效。
Gdb catch throw 解决方法
我会在这个答案https://stackoverflow.com/a/6849989/5639395 的基础上再接再厉
我们将在函数 __cxxabiv1::__cxa_throw 的 gdb 中添加一个断点。该函数接受一个名为tinfo 的参数,该参数包含有条件检查我们关心的异常所需的信息。
我们想要catch throw if exception==bad_alloc,那么如何找到合适的比较呢?
事实证明,tinfo 是一个指向结构的指针,该结构内部有一个名为__name 的变量。这个变量有一个带有异常类型名称的字符串。
所以我们可以这样做:catch throw if tinfo->__name == mangled_exception_name
我们快到了!
我们需要一种方法来进行字符串比较,而 gdb 有一个内置函数 $_streq(str1,str2) 可以满足我们的需要。
异常的错误名称有点难以找到,但您可以尝试猜测它或查看此答案的附录。我们现在假设它是“St9bad_alloc”。
最后的指令是:
catch throw if $_streq(tinfo->__name , "St9bad_alloc")
或同等的
break __cxxabiv1::__cxa_throw if $_streq(tinfo->__name , "St9bad_alloc")
如何找到您的异常的名称
你有两个选择
在库中查找符号
假设您安装了 libstd 调试符号,您可以像这样找到库名称:
apt search libstd | grep dbg | grep installed
名字是这样的libstdc++6-5-dbg
现在检查安装的文件:
dpkg -L libstdc++6-5-dbg
查找路径中有调试信息和 .so 扩展名的内容。在我的电脑中,我有/usr/lib/x86_64-linux-gnu/debug/libstdc++.so.6.0.21。
最后,在里面寻找你想要的异常。
nm /usr/lib/x86_64-linux-gnu/debug/libstdc++.so.6.0.21 | grep -i bad_alloc
或者
nm /usr/lib/x86_64-linux-gnu/debug/libstdc++.so.6.0.21 | grep -i runtime_error
等等
在我的例子中,我发现了类似 00000000003a4b20 V _ZTISt9bad_alloc 的东西,它建议我使用“St9bad_alloc”作为名称。
将其放入 gdb 并检查其中的名称
这很简单,只需启动 gdb、catch throw 一切并运行我之前编写的小可执行文件。当您在 gdb 中时,您可以发出 p *tinfo 并从 gdb 中查找 __name 描述。
gdb -ex 'file test_exceptions' -ex 'catch throw' -ex 'run'
(gdb) p *tinfo
$1 = {_vptr.type_info = 0x406260 <vtable for __cxxabiv1::__si_class_type_info+16>,
__name = 0x7ffff7b8ae78 <typeinfo name for std::bad_alloc> "St9bad_alloc"}