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

2021-12-14 00:00:00 debugging polymorphism gdb c++ multicore

我正在开发一个多线程应用程序,我想使用 GDB 调试它.

I'm working on a multithreaded application, and I want to debug it using GDB.

问题是,我的一个线程不断地随着消息而死:

Problem is, one of my threads keeps dying with the message:

pure virtual method called
terminate called without an active exception
Abort

我知道该消息的原因,但我不知道它出现在我的线程中的哪个位置.回溯真的很有帮助.

I know the cause of that message, but I have no idea where in my thread it occurs. A backtrace would really be helpful.

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

When I run my app in GDB, it pauses every time a thread is suspended or resumed. I want my app to continue running normally until one of the threads dies with that exception, at which point everything should halt so that I can get a backtrace.

推荐答案

您可以尝试使用捕获点"(catch throw)在生成异常的点停止调试器.

You can try using a "catchpoint" (catch throw) to stop the debugger at the point where the exception is generated.

以下 摘录 来自 gdb 手册描述了捕获点功能.

The following excerpt From the gdb manual describes the catchpoint feature.

5.1.3 设置捕捉点

5.1.3 Setting catchpoints

您可以使用捕获点使调试器因某些类型的程序事件而停止,例如 C++ 异常或共享库的加载.使用 catch 命令设置捕获点.

You can use catchpoints to cause the debugger to stop for certain kinds of program events, such as C++ exceptions or the loading of a shared library. Use the catch command to set a catchpoint.

  • 捕捉事件

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

Stop when event occurs. event can be any of the following:

    • throw

      抛出 C++ 异常.

    • 抓住

    • catch

      捕获 C++ 异常.

    • 执行

    • exec

      对 exec 的调用.目前仅适用于 HP-UX.

      A call to exec. This is currently only available for HP-UX.

    • fork

      调用 fork.目前仅适用于 HP-UX.

      A call to fork. This is currently only available for HP-UX.

    • vfork

    • vfork

      调用 vfork.目前仅适用于 HP-UX.

      A call to vfork. This is currently only available for HP-UX.

    • 加载或加载库名

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

      The dynamic loading of any shared library, or the loading of the library libname. This is currently only available for HP-UX.

    • 卸载或卸载libname

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

      The unloading of any dynamically loaded shared library, or the unloading of the library libname. This is currently only available for HP-UX.

    • tcatch 事件

      设置一个只启用一站的捕获点.第一次捕获事件后,捕获点会自动删除.

      Set a catchpoint that is enabled only for one stop. The catchpoint is automatically deleted after the first time the event is caught.

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

      Use the info break command to list the current catchpoints.

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

      There are currently some limitations to C++ exception handling (catch throw and catch catch) in GDB:

      • 如果您以交互方式调用函数,GDB 通常会在函数执行完毕后将控制权返回给您.但是,如果调用引发异常,则调用可能会绕过将控制权返回给您的机制,并导致您的程序中止或继续运行,直到遇到断点、捕获 GDB 正在侦听的信号或退出.即使您为异常设置了捕获点,情况也是如此;在交互式调用中禁用异常捕获点.

      • If you call a function interactively, GDB normally returns control to you when the function has finished executing. If the call raises an exception, however, the call may bypass the mechanism that returns control to you and cause your program either to abort or to simply continue running until it hits a breakpoint, catches a signal that GDB is listening for, or exits. This is the case even if you set a catchpoint for the exception; catchpoints on exceptions are disabled within interactive calls.

      您不能以交互方式引发异常.

      You cannot raise an exception interactively.

      您不能以交互方式安装异常处理程序.

      You cannot install an exception handler interactively.

      有时 catch 不是调试异常处理的最佳方式:如果您需要确切地知道异常在哪里引发,最好在调用异常处理程序之前停止,因为这样您可以在任何展开之前看到堆栈发生.如果您改为在异常处理程序中设置断点,则可能不容易找出引发异常的位置.

      Sometimes catch is not the best way to debug exception handling: if you need to know exactly where an exception is raised, it is better to stop before the exception handler is called, since that way you can see the stack before any unwinding takes place. If you set a breakpoint in an exception handler instead, it may not be easy to find out where the exception was raised.

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

      To stop just before an exception handler is called, you need some knowledge of the implementation. In the case of GNU C++, exceptions are raised by calling a library function named __raise_exception which has the following ANSI C interface:

      /* addr is where the exception identifier is stored.
         id is the exception identifier.  */
      void __raise_exception (void **addr, void *id);
      

      要使调试器在任何堆栈展开之前捕获所有异常,请在 __raise_exception 上设置断点(请参阅断点;观察点;和异常部分).

      To make the debugger catch all exceptions before any stack unwinding takes place, set a breakpoint on __raise_exception (see section Breakpoints; watchpoints; and exceptions).

      使用取决于 id 值的条件断点(参见中断条件部分),您可以在引发特定异常时停止程序.当引发多个异常中的任何一个时,您可以使用多个条件断点来停止您的程序.

      With a conditional breakpoint (see section Break conditions) that depends on the value of id, you can stop your program when a specific exception is raised. You can use multiple conditional breakpoints to stop your program when any of a number of exceptions are raised.

相关文章