早期的答案在编写时(2013年)是正确的,但从那时起,gdb和libstdc发生了变化。 libstdc现在有一些钩子,让gdb更好地与异常系统交互。特别是,现在有足够的信息公开给gdb,为用户提供一个$_exception方便变量。这个变量保存被抛出的异常。它只在异常被捕获的位置有效;你可以在使用catch catch时停止。 详情请参见the page from the manual。
/* addr is where the exception identifier is stored.
id is the exception identifier. */
void __raise_exception (void **addr, void *id); To make the debugger catch all exceptions before any stack unwinding takes place,
3条答案
按热度按时间hsvhsicv1#
早期的答案在编写时(2013年)是正确的,但从那时起,gdb和libstdc发生了变化。
libstdc现在有一些钩子,让gdb更好地与异常系统交互。特别是,现在有足够的信息公开给gdb,为用户提供一个
$_exception
方便变量。这个变量保存被抛出的异常。它只在异常被捕获的位置有效;你可以在使用catch catch
时停止。详情请参见the page from the manual。
bd1hkmkf2#
更新
下面是广发手册中的一些信息
目前在gdb中对C异常处理(catch throw和catch catch)有一些限制:
如果你以交互方式调用一个函数,gdb通常会在函数完成执行后将控制权返回给你。但是,如果调用引发异常,调用可能会绕过将控制权返回给你的机制,导致你的程序要么中止,要么继续运行,直到它遇到断点,捕获gdb正在监听的信号,或exits。即使您为异常设置了捕获点,情况也是如此;异常上的捕获点在交互式调用中被禁用。您不能交互式引发异常。您不能交互式安装异常处理程序。有时catch不是调试异常处理的最佳方法:如果你需要知道异常发生的确切位置,最好在异常处理程序被调用之前停止,因为这样你就可以在任何展开发生之前看到堆栈。如果你在异常处理程序中设置断点,可能不容易找到异常发生的位置。
要在异常处理程序被调用之前停止,你需要一些实现的知识。在gnu C的情况下,异常是通过调用一个名为__raise_exception的库函数来引发的,该函数具有以下ANSI C接口:
在__raise_exception上设置断点(请参阅断点、监视点和断点)。
所述
这取决于代码和你在堆栈中的位置。如果你实际上捕获了异常,如:
你可以尝试打印
e.what()
,或者查看异常的成员。如果你只是将其捕获为(...),那么我不确定你能收集到什么。你可以做的另一件处理事情是在gdb中捕获'throw',如果你真的想跟踪整个流程,也可以捕获'catch'。
这样你就可以在抛出异常之前得到一个断点,在捕获异常的时候得到一个断点,然后你可以遍历堆栈来获得更多关于发生了什么的信息。即使你在另一个断点,你也应该能够遍历堆栈(使用up或down)来获得异常可见的帧。
tag5nh1u3#
简短的回答:你不能,因为异常处理的大部分工作是在你的程序之外完成的,因此在gdb的范围之外。
解释答案:
有时抛出异常的行没有符号
如果你正在调试的二进制文件没有调试符号,那么这个二进制文件很可能被剥离了,你将无法找到任何关于类型/值的信息。
如何检查当前异常的值?
我认为你在这里假设异常是gdb可以检查的语言特性;事实上,C中的异常是C作为一种语言的特性,libc和ABI的组合。
就像UpAndAdam指出的那样,你可以用类型说明符在catch块中设置一个断点,然后检查那个元素,但我怀疑你的问题是在你找到一个“catch(...)"的情况下。在这些情况下,除非你深入研究异常处理的实现,否则你将无法了解更多关于当前异常的信息。
通过一个非常简短和不完整的描述,我们可以说抛出一个异常:
1.您的程序将调用libc来引发异常
1.个性函数将以某种方式决定当前堆栈帧是否可以处理此异常
1.如果可以处理异常,则将执行catch块
现在,很难谈论细节,因为很多异常处理取决于你的工具链(编译器,平台,架构,libc等),但在大多数情况下,“catch(...)”甚至不会接收原始异常作为参数。无论如何,为了回答你的问题:在gcc中使用gnu的libc++,你可以尝试这样做:
1.获取带有调试符号的libc++
1.在__gxx_personality_v0中设置一个断点(称为personality函数)。该函数将被调用以确定堆栈帧(基本上是函数调用)是否有合适的catch块来处理异常
1.在personality函数中,可以找到指向_Unwind_Exception的指针,它是真实的异常的 Package 器
1.像这样获取异常的类型信息:__cxa_exception exception_header =(__cxa_exception)(unwind_exception+1)-1; std::type_info *thrown_exception_type = exception_header->exceptionType;
1.您将获得一个异常类型,然后可以使用为代码定义的RTTI的其余部分查找该异常类型
无论如何,你可能需要花很多时间来理解异常处理是如何在你的平台上实现的。如果你想了解更多关于异常处理的知识,我在过去花了一些时间写了关于@http://monoinfinito.wordpress.com/series/exception-handling-in-c/的主题。它不是官方来源,但它确实有链接到处理异常所涉及的每个部分的规范。