首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用gdb获取C++中当前异常的值和类型?

如何使用gdb获取C++中当前异常的值和类型?
EN

Stack Overflow用户
提问于 2013-05-01 13:29:36
回答 3查看 12.7K关注 0票数 33

gdb允许在抛出异常和捕获异常时捕获异常。但有时抛出异常的行没有符号,或者在异常处理期间触发断点。如何检查当前异常的值?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-10-21 02:40:20

早期的答案在写的时候是正确的(在2013年),但从那时起,gdb和libstdc++发生了变化。

libstdc++现在有一些钩子,可以让gdb与异常系统更好地交互。特别是,现在已经为gdb提供了足够的信息来为用户提供$_exception方便的变量。这个变量保存被抛出的异常。它只在捕获异常的地方有效;您可以在使用catch catch时停止。

详情请参见the page from the manual

票数 9
EN

Stack Overflow用户

发布于 2013-05-02 02:28:36

已更新

以下是GDB手册中的一些信息

目前在gdb中对C++异常处理(catch throw和catch catch)有一些限制:

如果以交互方式调用函数,gdb通常会在函数执行完毕后将控制权返回给您。但是,如果调用引发异常,则调用可能会绕过将控制权返回给您的机制,并导致程序中止或简单地继续运行,直到到达断点、捕获gdb正在侦听的信号或退出。即使为异常设置了catchpoint,情况也是如此;在交互式调用中禁用异常的catchpoint。您不能以交互方式引发异常。不能以交互方式安装异常处理程序。有时,catch不是调试异常处理的最佳方法:如果您需要确切地知道异常在何处引发,最好在调用异常处理程序之前停止,因为这样您就可以在任何展开发生之前看到堆栈。如果改为在异常处理程序中设置断点,则可能不容易找出异常引发的位置。

要在调用异常处理程序之前停止,您需要对实现有一些了解。在gnu C++的情况下,通过调用名为__raise_exception的库函数引发异常,该库函数具有以下ANSI接口:

/*地址是存储异常标识符的位置。id是异常标识符。*/ void __raise_exception (void **addr,void *id);为了使调试器在任何堆栈展开发生之前捕获所有异常,

在__raise_exception上设置断点(请参阅断点、观察点和异常)。

也就是说

这取决于代码和您在堆栈中的位置。如果您实际捕获了异常,如下所示:

代码语言:javascript
复制
try { .... } catch (std::exception &e) {
   //do stuff
}

您可以尝试打印e.what(),或者查看异常的成员。如果你只是把它当做(...)那我就不确定你能收集到什么。

你可以做的另一件处理事情是在gdb中捕获“抛出”,如果你真的想跟踪整个流程,也可以捕获“catch”。

代码语言:javascript
复制
gdb> catch catch  
gdb> catch throw

这样,您将在抛出异常之前获得断点,并在捕获到它们时正确地获取断点,然后您可以遍历堆栈以获得有关发生了什么的更多信息。即使您处于另一个断点,您也应该能够向上遍历堆栈(使用向上或向下),以获得其中异常可见的帧。

票数 8
EN

Stack Overflow用户

发布于 2013-05-06 22:10:15

简而言之:不能这样做,因为大多数异常处理工作都是在您的程序之外完成的,因此超出了gdb的范围。

解释的答案:

有时抛出异常的行没有符号

如果您正在调试的二进制文件没有调试符号,那么该二进制文件可能会被剥离,您将无法找到更多关于任何类型/值的内容。

如何检查当前异常的值?

我认为您在这里假设异常是gdb可以检查的语言特性;实际上,C++中的异常是C++语言、libc++和ABI的特性的组合。甚至可能存在不止一个活动的电流异常。

就像UpAndAdam指出的,您可以使用类型说明符在catch块中设置断点,然后检查该元素,但我怀疑您的问题是在找到"catch (...)“的情况下。在这些情况下,除非深入研究异常处理的实现,否则您将无法了解当前异常。

使用非常简短和不完整的描述,我们可以说抛出一个异常:

在glibc中调用“exception

  • libc++”来启动堆栈unwinding

  • unwind将为每个堆栈帧从libc++回调一个“
  1. function”(堆栈中的每个函数调用basically)
  2. the
    1. 函数都会以某种方式决定当前堆栈帧是否可以处理此异常
    2. 如果异常可以处理则

    将被执行

现在,很难谈论细节,因为许多异常处理依赖于您的工具链(编译器、平台、体系结构、libc++等),但在大多数情况下是"catch (...)“甚至不会接收原始异常作为参数。在任何情况下,以某种方式回答你的问题:在使用gnu的libc++的gcc中,你可以尝试这样的东西:

  1. 获取带有调试符号的libc++,
  2. 在__gxx_personality_v0中设置断点(这称为个性函数)。这个函数将被调用,以确定堆栈帧(基本上是一个函数调用)是否有合适的catch块来处理异常。在个性函数中,您将能够找到指向_Unwind_Exception的指针,它是一个包装,用于包装您的实际exception
  3. Get异常的类型信息,如下所示:__cxa_exception *exception_header = (__cxa_exception*)(unwind_exception+1)-1;std::type_info *thrown_exception_type = exception_header->exceptionType;
  4. 您将获得一个异常类型,然后可以使用为您的代码

定义的其余RTTI来查找该异常类型

在任何情况下,您都可能需要花费相当多的时间来尝试了解异常处理是如何在您的平台中实现的。如果你想阅读更多关于异常处理的内容,我在过去花了一些时间写了@ http://monoinfinito.wordpress.com/series/exception-handling-in-c/这个主题。它不是官方来源,但它确实有链接到处理异常所涉及的每个部分的规范。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16313227

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档