DebugBreak()/__debugbreak に相当する移植性の高いものはありますか?
-
05-07-2019 - |
質問
MSVCでは、 デバッグブレーク() または __デバッグブレイク デバッガが壊れる原因となります。x86 では、「_asm int 3」を記述するのと同じですが、x64 では異なります。gcc (またはその他の標準コンパイラ) でコンパイルするときに、デバッガにもブレークインしたいと思います。プラットフォームに依存しない関数または組み込み関数はありますか?私が見ました XCodeの質問 それについてですが、移植性が十分ではないようです。
サイドノート:私は主に ASSERT を実装したいと考えており、そのためにassert() を使用できることは理解していますが、コードに DEBUG_BREAK などを書きたいとも考えています。
解決
現在のアーキテクチャまたはプラットフォームに基づいてさまざまな構造に拡張される #ifdef に基づいた条件付きマクロを定義する場合はどうでしょうか。
何かのようなもの:
#ifdef _MSC_VER
#define DEBUG_BREAK __debugbreak()
#else
...
#endif
これは、コードがコンパイルされるプラットフォームに基づいて、プリプロセッサによって正しいデバッガー ブレーク命令に拡張されます。いつも使っているこの方法 DEBUG_BREAK
あなたのコードに。
他のヒント
ほとんどのPOSIXシステムに移植可能な方法は次のとおりです。
raise(SIGTRAP);
GCCには __ builtin_trap
という名前の組み込み関数があり、こちら、ただし、これに達するとコードの実行が停止すると想定されています。
__ builtin_trap()
の呼び出しが条件付きであることを確認する必要があります 、そうでない場合、その後にコードは出力されません。
この投稿は、5分間のすべてのテスト、YMMVによって強化されました。
これは適切な互換ライブラリのようです https://github.com/scottt/debugbreak
モジュールを portable-snippets (ポータブルコードのパブリックドメインスニペットのコレクション)を実行します。 100%の移植性はありませんが、かなり堅牢である必要があります。
-
cliの一部のバージョンの
-
__ builtin_debugtrap
(__ has_builtin(__ builtin_debugtrap)
で識別) - MSVCおよびIntel C / C ++コンパイラ:
__ debugbreak
- ARM C / C ++コンパイラの場合:
__ breakpoint(42)
- x86 / x86_64の場合、アセンブリ:
int $ 03
- 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)
-
将来、portable-snippetsのモジュールは他のロジックを含むように拡張される可能性があり、おそらくこの回答を更新するのを忘れるので、更新を確認する必要があります。パブリックドメイン(CC0)なので、コードを盗んでください。
assert(x)の移植性を十分に考慮している場合、assert(false)が問題に対する明白な移植性のあるソリューションのようです。
クラッシュ関連の状態をデバッグしようとしている場合、ほとんどのプラットフォームで古きよき形式のabort()が呼び出しスタックを提供します。欠点は、現在のPCから続行できないことです。これはおそらくとにかくしたくないでしょう。
「通常の」デバッグブレークを使用する代わりに、ゼロ除算など、次のいずれかを使用してください。
int iCrash = 13 / 0;
またはNULLポインターの逆参照:
BYTE bCrash = *(BYTE *)(NULL);
少なくともこれは多くのプラットフォーム/アーキテクチャ間で移植可能です。
多くのデバッガーでは、どの例外に対してどのアクションを実行するかを指定できるため、上記のいずれかがヒットした場合(実行の一時停止、ala int 3命令など)に応じてアクションを実行し、例外が生成されます。
#define __debugbreak() \
do \
{ static bool b; \
while (!b) \
sleep(1); \
b = false; \
} while (false)
プロセスがスリープ状態になったら、デバッガーをプロセスにアタッチし、変数bを変更してループを中断し、処理を実行できます。このコードは、最適化されたビルドでは機能しない可能性があります!