Существует ли переносимый эквивалент DebugBreak () / __ debugbreak? - PullRequest
47 голосов
/ 06 октября 2008

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

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

Ответы [ 9 ]

38 голосов
/ 06 апреля 2011

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

raise(SIGTRAP);
12 голосов
/ 06 октября 2008

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

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

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

12 голосов
/ 06 октября 2008

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

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

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

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

9 голосов
/ 03 октября 2013

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

6 голосов
/ 03 марта 2018

Я только что добавил модуль к 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
  • Для Alpha, сборка: bpt
  • Для не размещенного C с GCC (или чем-то, что маскируется под него), __builtin_trap
  • В противном случае, включите signal.h и
    • Если defined(SIGTRAP) (т.е. POSIX), raise(SIGTRAP)
    • В противном случае, raise(SIGABRT)

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

4 голосов
/ 06 октября 2008

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

1 голос
/ 27 декабря 2013

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

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

0 голосов
/ 03 декабря 2015
#define __debugbreak() \
do \
{       static bool b; \
        while (!b) \
                sleep(1); \
        b = false; \
} while (false)

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

0 голосов
/ 06 октября 2008

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

int iCrash = 13 / 0;

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

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

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

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

...