Существует ли переносимый эквивалент DebugBreak()/__b debugbreak?

В MSVC, DebugBreak () или __debugbreak вызывают сбой отладчика. На x86 это эквивалентно написанию "_asm int 3", на x64 это что-то другое. При компиляции с помощью gcc (или любого другого стандартного компилятора) я также хочу сделать разрыв в отладчике. Есть ли независимая от платформы функция или встроенная? Я видел вопрос XCode об этом, но он не выглядит достаточно портативным.

Sidenote: Я в основном хочу реализовать ASSERT с этим, и я понимаю, что могу использовать assert() для этого, но я также хочу написать DEBUG_BREAK или что-то еще в коде.

11 ответов

Решение

Как насчет определения условного макроса на основе #ifdef, который расширяется до различных конструкций на основе текущей архитектуры или платформы.

Что-то вроде:

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

Это будет расширено препроцессором до правильной инструкции прерывания отладчика на основе платформы, на которой компилируется код. Таким образом, вы всегда используете DEBUG_BREAK в вашем коде.

Метод, который переносим для большинства систем POSIX:

raise(SIGTRAP);

Я просто добавил модуль в portable-snippets (набор фрагментов общедоступного домена переносимого кода), чтобы сделать это. Это не на 100% портативно, но должно быть довольно надежно:

  • __builtin_debugtrap для некоторых версий clang __has_builtin(__builtin_debugtrap))
  • На MSVC и компиляторе Intel C/C++: __debugbreak
  • Для компилятора ARM C/C++: __breakpoint(42)
  • Для x86/x86_64 сборка: int $03
  • Для большого пальца руки, сборка: .inst 0xde01
  • Для ARM AArch64, сборка: .inst 0xd4200000
  • Для других ARM, сборка: .inst 0xe7f001f0
  • Для Альфы, сборка: bpt
  • Для не размещенного C с GCC (или что-то, что маскируется под него), __builtin_trap
  • В противном случае, включить signal.h а также
    • Если defined(SIGTRAP) (то есть POSIX), raise(SIGTRAP)
    • Иначе, raise(SIGABRT)

В будущем модуль в переносимых фрагментах может расширяться, чтобы включать другую логику, и я, вероятно, забуду обновить этот ответ, так что вы должны искать там обновления. Это общественное достояние (CC0), поэтому не стесняйтесь воровать код.

GCC имеет встроенную функцию с именем __builtin_trap что вы можете увидеть здесь, однако предполагается, что выполнение кода останавливается, как только это будет достигнуто.

Вы должны убедиться, что __builtin_trap() Вызов условный, иначе код после него не будет выдан.

этот пост подпитывается всеми 5 минутами тестирования YMMV.

Это похоже на соответствующую библиотеку compat https://github.com/scottt/debugbreak

Кажется, это очень хорошее портативное решение этого вопроса:https://github.com/scottt/debugbreak

Заголовок, представленный в указанном репозитории (debugbreak.h), инкапсулирует файлы MSVC

    __debugbreak, 

а также

    __asm__ volatile("int $0x03");

на i386 и x86_64, а на ARM реализует

    __asm__ volatile(".inst 0xe7f001f0");

а также документировать некоторые обходные пути для проблем, отмеченных в заголовке для пошагового мимо точки останова в GDB плюс сценарий Python для расширения GDB на тех платформах, где СТЕПЬ или продолжение застревает. Сценарий добавляет в GDB шаг debugbreak-step и debugbreak-continue.

Если вы считаете assert(x) достаточно переносимым, assert(false) кажется очевидным переносимым решением вашей проблемы.

Если вы пытаетесь отладить состояние, связанное с падением, старый добрый abort() даст вам стек вызовов на большинстве платформ. Недостатком является то, что вы не можете продолжить с текущего ПК, что вы, вероятно, не хотите делать в любом случае.

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

FWIW, ни одно из этих решений не работало на nRF9160 с использованием NRF Connect SDK. Это среда 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") это все, что требуется.

#define __debugbreak() \
do \
{       static bool b; \
        while (!b) \
                sleep(1); \
        b = false; \
} while (false)

Когда процесс находится в спящем режиме, вы можете присоединить к нему отладчик, изменить переменную b, чтобы разорвать цикл и сделать свое дело. Этот код может не работать в оптимизированной сборке!

Вместо использования "нормальных" разрывов отладки, почему бы не использовать одно из следующего, например деление на ноль:

int iCrash = 13 / 0;

или разыменуйте нулевой указатель:

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

По крайней мере, это переносимо во многих платформах / архитектурах.

Во многих отладчиках вы можете указать, какое действие вы хотите выполнить с какими исключениями, чтобы вы могли действовать соответственно, когда выполняется одно из вышеперечисленных действий (например, выполнение паузы, ala инструкция "int 3") и генерируется исключение.

Другие вопросы по тегам