在GDB中运行应用程序直到发生异常

123

我正在处理一个多线程应用程序,并希望使用GDB进行调试。

问题是,其中一个线程持续死亡并显示以下消息:

pure virtual method called
terminate called without an active exception
Abort

我知道这个消息的原因,但不知道它在我的线程中的具体位置。有一个回溯信息真的会很有帮助。

当我在GDB中运行我的应用程序时,每次线程被暂停或恢复时都会暂停。我希望我的应用程序继续正常运行,直到其中一个线程以该异常死亡,然后一切都应该停止,以便我可以获得回溯信息。


GDB 在暂停时报告了什么信号?您应该能够运行类似 handle SIGUSR1 pass noprint nostop 的命令。 - Hasturkun
4个回答

173
你可以尝试使用“catchpoint”(catch throw)在异常生成的地方停止调试器。
下面是来自gdb手册的摘录,描述了catchpoint功能。

5.1.3 设置捕获点

您可以使用捕获点来让调试器在某些程序事件发生时停止,例如C ++异常或共享库的加载。使用catch命令设置捕获点。

  • catch event

    当发生事件时停止。事件可以是以下任何一种:

    • throw

      C++异常抛出。

    • catch

      C++异常捕获。

    • exec

      执行exec调用。目前仅适用于HP-UX。

    • fork

      执行fork调用。目前仅适用于HP-UX。

    • vfork

      执行vfork调用。目前仅适用于HP-UX。

    • load or load libname

      动态加载任何共享库,或加载库libname。目前仅适用于HP-UX。

    • unload or unload libname

      卸载任何动态加载的共享库,或卸载库libname。目前仅适用于HP-UX。

  • tcatch event

    设置一个仅在一个停止时启用的捕获点。该捕获点在第一次捕获事件后会自动删除。

使用info break命令列出当前的捕获点。

目前,在GDB中使用C++异常处理(catch throw和catch catch)存在一些限制:

  • 如果您交互式调用一个函数,当函数执行完成时,GDB通常会将控制权返回给您。但是,如果该调用引发异常,则该调用可能会绕过将控制权返回给您的机制,并导致您的程序中止或仅继续运行,直到它遇到断点、捕获到GDB正在监听的信号或退出为止。即使您设置了异常的catchpoint,对于交互式调用,异常的catchpoints也会被禁用。

  • 您无法通过交互方式引发异常。

  • 您无法通过交互方式安装异常处理程序。

有时,catch并不是调试异常处理的最佳方法:如果您需要知道异常在哪里引发,最好在调用异常处理程序之前停止,因为这样您可以看到在任何展开操作发生之前的堆栈。如果您改为在异常处理程序中设置断点,可能很难找出异常是在哪里引发的。

要在调用异常处理程序之前停止,请您需要一些实现方面的知识。在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);

为了在堆栈展开之前使调试器捕获所有异常,请在 __raise_exception 上设置断点(请参阅“断点;观察点;和异常”一节)。
通过一个取决于 id 值的条件断点(请参阅“断点条件”一节),您可以在引发特定异常时停止程序。您可以使用多个条件断点,以在引发任何异常时停止程序。

2
您还可以指定要捕获的异常类型,例如 catch throw std::runtime_exception - scai

8

只有下面这种方法在我的gdb 8.3上有效:

break _Unwind_RaiseException

“catch throw”或“break __cxx_throw”对我来说没有用。

同意,gdb 8.3 + clang 8。 - tartaruga_casco_mole
catch throw worked but break __cxx_throw didn't on my machine the symbol seems to be __cxa_throw - avlec

7

据说,在gcc 4.1中,适当的函数名称已经改变,必须在此函数中设置断点。

__cxa_pure_virtual


5

在__pure_virtual上设置断点


在@JeffreyHill的回答中,现在被称为__cxa_pure_virtual。我不知道如何自己检查,所以我不想编辑答案。我不打算投反对票,但是回答现在可能是错误的,应该由知道正确答案的人进行编辑。 - Philipp Claßen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接