假设您有以下带有抛出异常线程的 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 debug symbols,例如
sudo apt-get install libstdc++6-5-dbg
或其他版本。
调试编译
如果您正在进行调试编译,您可以按照此答案
(https://dev59.com/Mmw15IYBdhLWcg3wFH3f#12434170)的步骤进行操作,因为通常定义了构造函数。
发布编译
如果您正在进行发布编译,则可能无法找到适当的构造函数来设置断点,因为编译器已经进行了优化,这时您有其他选择。让我们继续。
源代码更改解决方案
如果您可以轻松更改源代码,则可以使用此方法
(https://dev59.com/Mmw15IYBdhLWcg3wFH3f#9363680)
Gdb catch throw 简单解决方案
如果您不想更改代码,则可以尝试看看
catch throw bad_alloc
或一般情况下的
catch throw exception_name
是否起作用。
Gdb catch throw 解决方案
我将在此答案
(https://dev59.com/Mmw15IYBdhLWcg3wFH3f#6849989)的基础上进行构建,在gdb中为函数
__cxxabiv1::__cxa_throw
设置断点。此函数需要一个称为
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
查找路径中具有debug和.so扩展名的内容。在我的PC上,我有/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
everything并运行我之前编写的小型可执行文件。当您在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"}