我如何得到值和类型的当前异常在c++中使用gdb



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

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

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

详细信息请参阅手册中的页面。

更新


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

目前c++异常处理有一些限制Throw and catch catch) in gdb:

如果您以交互方式调用函数,gdb通常将控制权返回给当函数完成执行时。如果调用引发异常时,调用可能绕过返回的机制控件,并导致程序中止或简单地停止继续运行,直到它遇到一个断点,捕获一个信号,GDB正在监听或退出。即使你设置了a,情况也是如此异常的捕获点;异常的捕获点被禁用在交互式呼叫中。您不能交互式地引发异常。不能交互式地安装异常处理程序。有时候赶上是不是调试异常处理的最好方法:如果你需要知道在引发异常的确切位置,最好在调用异常处理程序,因为这样可以看到堆栈在任何unwind发生之前。中设置断点异常处理程序的位置可能不太容易找到异常被抛出。

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

     /* 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,

在__raise_exception上设置断点(参见Breakpoints;监测点;和例外)。


,

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

try { .... } catch (std::exception &e) {
   //do stuff
}

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

你可以做的另一件事是在gdb中捕获'throw'和'catch',如果你真的想要遵循整个流程。

gdb> catch catch  
gdb> catch throw

这样,在抛出异常之前和捕获异常时,您将获得一个断点,然后您可以遍历堆栈以获得有关正在发生的事情的更多信息。即使您处于另一个断点,您也应该能够向上堆栈(使用up或down)以获得异常可见的帧。

简短的回答:你不能,因为大多数异常处理工作是在你的程序之外完成的,因此在gdb的作用域之外。

解释回答:

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

如果你正在调试的二进制文件没有调试符号,那么二进制文件可能会被剥离,你根本找不到任何关于类型/值的信息。

如何检查当前异常的值?

我想你在这里假设异常是gdb可以检查的语言特性;事实上,c++中的一个例外是c++作为一种语言的特性,libc++和ABI的组合。甚至可能存在不止一个活动电流异常。

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

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

  1. 程序将调用libc++引发异常
  2. libc++将在glibc中调用"unwind"来启动堆栈展开
  3. unwind将为每个堆栈帧(基本上是堆栈中的每个函数调用)从libc++中回调一个"个性函数"
  4. 人格函数将以某种方式决定当前堆栈帧是否可以处理此异常
  5. 如果异常可以处理,catch块将被执行

现在,很难谈论细节,因为很多异常处理取决于你的工具链(编译器,平台,架构,libc++等),但在大多数情况下,"catch(…)"甚至不会接收原始异常作为参数。无论如何,要以某种方式回答您的问题:在gcc中使用gnu的libc++,您可以尝试这样做:

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

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

相关内容

  • 没有找到相关文章

最新更新