73

在 MSVC 中,DebugBreak()__debugbreak会导致调试器中断。在 x86 上它相当于写“_asm int 3”,在 x64 上它是不同的。使用 gcc(或任何其他标准编译器)编译时,我也想中断调试器。是否有独立于平台的功能或内在功能?我看到了关于这个的XCode 问题,但它似乎不够便携。

旁注:我主要想用它来实现 ASSERT,我知道我可以为此使用 assert(),但我也想在代码中写入 DEBUG_BREAK 或其他东西。

4

11 回答 11

59

一种可移植到大多数 POSIX 系统的方法是:

raise(SIGTRAP);
于 2011-04-06T03:07:32.107 回答
33

我刚刚向可移植代码片段(可移植代码的公共域片段集合)添加一个模块来执行此操作。它不是 100% 可移植的,但它应该非常健壮:

  • __builtin_debugtrap对于某些版本的 clang(用 标识__has_builtin(__builtin_debugtrap)
  • 在 MSVC 和英特尔 C/C++ 编译器上:__debugbreak
  • 对于 ARM C/C++ 编译器:__breakpoint(42)
  • 对于 x86/x86_64,组装:int3
  • 对于 ARM Thumb,组装:.inst 0xde01
  • 对于 ARM AArch64,汇编:.inst 0xd4200000
  • 对于其他 ARM,组装:.inst 0xe7f001f0
  • 对于 Alpha,组装:bpt
  • 对于带有 GCC 的非托管 C(或伪装成它的东西),__builtin_trap
  • 否则,包括signal.h
    • 如果defined(SIGTRAP)(即 POSIX),raise(SIGTRAP)
    • 除此以外,raise(SIGABRT)

将来可移植片段中的模块可能会扩展到包含其他逻辑,我可能会忘记更新这个答案,所以你应该在那里寻找更新。它是公共领域(CC0),所以请随意窃取代码。

于 2018-03-02T23:47:34.307 回答
19

如何定义一个基于#ifdef 的条件宏,该宏扩展为基于当前架构或平台的不同结构。

就像是:

#ifdef _MSC_VER
#define DEBUG_BREAK __debugbreak()
#else
...
#endif

这将由预处理器根据编译代码的平台扩展正确的调试器中断指令。这种方式你总是DEBUG_BREAK在你的代码中使用。

于 2008-10-06T09:05:26.477 回答
15

GCC 有一个名为的内置函数__builtin_trap,您可以在此处看到,但是假定一旦达到此代码执行就会停止。

应该确保__builtin_trap()调用是有条件的,否则在它之后不会发出任何代码。

这篇文章由所有 5 分钟的测试推动,YMMV。

于 2008-10-06T09:19:41.927 回答
13

这看起来像一个合适的兼容库https://github.com/scottt/debugbreak

于 2013-10-03T08:26:26.043 回答
5

对于这个问题,这似乎是一个非常好的、可移植的解决方案: https ://github.com/scottt/debugbreak

引用的存储库 (debugbreak.h) 中提供的标头封装了 MSVC 的

    __debugbreak, 

    __asm__ volatile("int $0x03");

在 i386 和 x86_64 上,在 ARM 上实现

    __asm__ volatile(".inst 0xe7f001f0");

以及记录标题中指出的问题的一些解决方法,用于单步越过 GDB 中的断点,以及用于在stepicont卡住的平台上扩展 GDB 的 Python 脚本。该脚本将debugbreak-stepdebugbreak-continue添加到 GDB。

于 2019-08-02T17:17:19.067 回答
2

如果您认为assert(x)便携性足够,assert(false)似乎是解决您问题的明显便携解决方案。

于 2008-10-06T11:18:58.317 回答
0

FWIW,这些解决方案都不适用于使用 NRF Connect SDK 的 nRF9160。那是一个 SEGGER Embedded Studio for ARM (Nordic Edition) 环境,使用arm-none-eabi-gcc编译器。

,和其他答案debug-trap.h中提到的都导致“未定义的操作码”和硬故障(或调试监视器故障,但结果相同),并且没有有用的程序计数器、堆栈帧或其他可调试信息。debugbreak.h__builtin_trap()

最后,这个替代方案确实奏效了。我从其他一些神秘的北欧图书馆派生出来,它被称为NRF_BREAKPOINT

#if defined(__GNUC__)
    __asm__("BKPT 0");
#else
    __BKPT(0)
#endif

在构建时,它是__GNUC__包含在内的路径,因此__asm__("BKPT 0")也是必需的。

于 2021-05-12T22:17:01.550 回答
-1

如果您尝试调试与崩溃相关的情况,老式的 abort() 将在大多数平台上为您提供调用堆栈。缺点是您无法从当前的 PC 继续,您可能无论如何都不想这样做。

http://www.cplusplus.com/reference/cstdlib/abort/

于 2013-12-26T22:33:00.343 回答
-6

与其使用“正常”调试中断,不如使用以下方法之一,例如除以零:

int iCrash = 13 / 0;

或取消引用 NULL 指针:

BYTE bCrash = *(BYTE *)(NULL);

至少这在许多平台/架构上是可移植的。

在许多调试器中,您可以指定要对哪些异常执行什么操作,以便在遇到上述任何一项(如暂停执行,ala“int 3”指令)并生成异常时采取相应措施。

于 2008-10-06T09:21:21.390 回答
-7
#define __debugbreak() \
do \
{       static bool b; \
        while (!b) \
                sleep(1); \
        b = false; \
} while (false)

当进程处于睡眠状态时,您可以将调试器附加到进程,更改变量 b 以中断循环并执行您的操作。此代码可能无法在优化的构建中运行!

于 2015-12-03T19:54:06.420 回答