事後デバッグを有効にする

ユーザー モード例外処理

例外とブレークポイント

最も一般的なアプリケーション エラーは例外と呼ばれます。 これには、アクセス違反、0 除算エラー、数値オーバーフロー、CLR 例外、その他多くの種類のエラーが含まれます。 アプリケーションによってブレークポイントの割り込みが発生する場合もあります。 これらは、Windows がアプリケーションを実行できない場合 (たとえば、必要なモジュールを読み込むことができない場合)、またはブレークポイントが発生したときに発生します。 ブレークポイントは、デバッガーによってコードに挿入することも、DebugBreak などの関数を介して呼び出すこともできます。

例外ハンドラーの優先順位

構成値とアクティブなデバッガーに基づいて、Windows はさまざまな方法でユーザー モード エラーを処理します。 次のシーケンスは、ユーザー モードのエラー処理に使用される優先順位を示しています。

  1. ユーザー モード デバッガーが現在障害発生プロセスにアタッチされている場合、すべてのエラーによってターゲットがこのデバッガーに分割されます。

    ユーザー モード デバッガーがアタッチされている限り、gn (Go With Exception Not Handled) コマンドが使用されている場合でも、他のエラー処理メソッドは使用されません。

  2. ユーザー モード デバッガーがアタッチされておらず、実行中のコードに独自の例外処理ルーチンがある場合 (例: try - except)、この例外処理ルーチンはエラーの処理を試みます。

  3. ユーザー モード デバッガーがアタッチされておらず、Windows にカーネル デバッグ接続が開いている場合、エラーがブレークポイント割り込みである場合、Windows はカーネル デバッガーへの接続を試みます。

    カーネル デバッグ接続は、Windows のブート プロセス中に開く必要があります。 ユーザー モードの割り込みがカーネル デバッガーに割り込まれるのを防ぐには、-du パラメーターで KDbgCtrl ユーティリティを使用できます。 カーネル デバッグ接続の構成方法と KDbgCtrl の使用方法の詳細については、「デバッグのセットアップ」を参照してください。

    カーネル デバッガーでは、gh (Go With Exception Handled) を使用してエラーを無視し、ターゲットの実行を続行できます。 gn (Go With Exception Not Handled) を使用してカーネル デバッガーをバイパスし、手順 4 に進むことができます。

  4. 手順 1、2、3 の条件が適用されない場合、Windows は AeDebug レジストリ値で構成されたデバッグ ツールをアクティブにします。 この状況で使用するツールとして、任意のプログラムを事前に選択できます。 選択したプログラムは、事後デバッガーと呼ばれます。

  5. 手順 1、2、3 の条件が適用されず、事後デバッガーが登録されていない場合、Windows エラー報告 (WER) はメッセージを表示し、使用可能な場合は解決策を提供します。 WER は、レジストリに適切な値が設定されている場合にもメモリ ダンプ ファイルを書き込みます。 詳細については、「WER の使用」「ユーザー モード ダンプの収集」を参照してください。

DebugBreak 関数

事後デバッガーがインストールされている場合は、DebugBreak 関数を呼び出すことによって、ユーザー モード アプリケーションから意図的にデバッガーに中断できます。

事後デバッガーの指定

このセクションでは、WinDbg などのツールを事後デバッガーとして構成する方法について説明します。 構成が完了すると、アプリケーションがクラッシュするたびに事後デバッガーが自動的に開始されます。

事後デバッガー レジストリ キー

Windows エラー報告 (WER) は、AeDebug レジストリ キーに設定された値を使用して事後デバッガー プロセスを作成します。

HKLM\Software\Microsoft\Windows NT\CurrentVersion\AeDebug

レジストリ値には、[デバッガー][自動] の 2 つの主要な値があります。[デバッガー] レジストリ値は、事後デバッガーのコマンド ラインを指定します。 [自動] レジストリ値は、事後デバッガーが自動的に開始されるか、または確認メッセージ ボックスが最初に表示されるかを指定します。

デバッガー (REG_SZ)

この REG_SZ 値は、事後デバッグを処理するデバッガーを指定します。

既定のパスにあるディレクトリにデバッガーが配置されている場合を除き、デバッガーへの完全なパスを一覧表示する必要があります。

コマンド ラインは、3 つのパラメーターを含む printf スタイルの呼び出しを介してデバッガー文字列から生成されます。 順序は固定されていますが、使用可能なパラメーターの一部またはすべてを使用する必要はありません。

DWORD (%ld) - ターゲット プロセスのプロセス ID。

DWORD (%ld) - 事後デバッガー プロセスに複製されたイベント ハンドル。 事後デバッガーがイベントを通知した場合、WER は事後デバッガーが終了するのを待たずにターゲット プロセスを続行します。 このイベントは、問題が解決された場合にのみ通知されます。 イベントを通知せずに事後デバッガーが終了した場合、WER はターゲット プロセスに関する情報の収集を続行します。

void* (%p) - ターゲット プロセスのアドレス空間に割り当てられた JIT_DEBUG_INFO 構造体のアドレス。 構造体には、追加の例外情報とコンテキストが含まれています。

Auto (REG_SZ) この REG_SZ 値は常に 0 または 1 です

[自動]0 に設定すると、事後デバッグ プロセスが開始される前に確認メッセージ ボックスが表示されます。

[自動]1 に設定すると、事後デバッガーがすぐに作成されます。

レジストリを手動で編集する場合は、非常に慎重に行ってください。これは、レジストリの不適切な変更によって Windows の起動が許可されない場合があるからです。

コマンド ラインの使用例

多くの事後デバッガーでは、-p スイッチと -e スイッチを含むコマンド ラインを使用して、パラメーターが PID とイベント (それぞれ) であることを示します。 たとえば、windbg.exe -I 経由で WinDbg をインストールすると、以下の値が作成されます。

Debugger = "<Path>\WinDbg -p %ld -e %ld -g"
Auto = 1

WER %ld %ld %p パラメーターは柔軟に使用できます。 たとえば次のようになります。 WER パラメーターの前後または間のスイッチを指定する必要はありません。 たとえば、procdump.exe -i を使用して Windows Sysinternals ProcDump をインストールすると、WER %ld %ld %p パラメータ間を切り替えることなく以下の値が作成されます。

Debugger = "<Path>\procdump.exe" -accepteula -j "c:\Dumps" %ld %ld %p
Auto = 1

32 ビットおよび 64 ビット デバッガー

64 ビット プラットフォームでは、デバッガー (REG_SZ) と自動 (REG_SZ) のレジストリ値は、64 ビットおよび 32 ビット アプリケーションに対して個別に定義されます。 Windows 上の追加の Windows (WOW) キーは、32 ビット アプリケーションの事後デバッグ値を格納するために使用されます。

HKLM\Software\Wow6432Node\Microsoft\Windows NT\CurrentVersion\AeDebug

64 ビット プラットフォームでは、32 ビット プロセスには 32 ビット事後デバッガーを使用し、64 ビット プロセスには 64 ビット デバッガーを使用します。 これにより、32 ビット プロセスで、32 ビット スレッドではなく WOW64 スレッドに焦点を当てた 64 ビット デバッガーが回避されます。

多くの事後デバッガー (Windows 事後デバッガーのデバッグ ツールなど) では、インストール コマンドを x86 バージョンで 1 回、x64 バージョンで 1 回 と 2 回実行する必要があります。 たとえば、対話型の事後デバッガーとして WinDbg を使用する場合、windbg.exe -I コマンドはバージョンごとに 1 回ずつ、合計 2 回実行されます。

64 ビット インストール:

C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\windbg.exe –I

これにより、レジストリ キーがこれらの値で更新されます。

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug
Debugger = "C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\windbg.exe" -p %ld -e %ld –g

32 ビット インストール:

C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\windbg.exe –I

これにより、レジストリ キーがこれらの値で更新されます。

HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion\AeDebug
Debugger = "C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\windbg.exe" -p %ld -e %ld –g

事後デバッガーの構成

Windows 用デバッグ ツール

Debugging Tools for Windows デバッガーでは、事後デバッガーとして設定されているすべてのサポートがサポートされます。 install コマンドは、プロセスを対話形式でデバッグすることを目的としています。

WinDbg

事後デバッガーを WinDbg に設定するには、windbg -I を実行します。 (I は、大文字にする必要があります)。このコマンドを使用すると、成功または失敗のメッセージが表示されます。 32 ビットと 64 ビットの両方のアプリケーションを操作するには、64 と 32 の両方のデバッガーに対してコマンドを実行します。

C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\windbg.exe –I
C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\windbg.exe –I

これは、windbg -I 実行時に AeDebug レジストリ エントリを構成する方法です。

Debugger = "<Path>\WinDbg -p %ld -e %ld -g"
Auto = 1

例では、<Path> はデバッガーが配置されているディレクトリです。

-p パラメーターと -e パラメーターは、前に説明したように、プロセス ID とイベントを渡します。

-g は g (Go) コマンドを WinDbg に渡し、現在の命令から実行を続行します。

注: g (Go) コマンドを渡すと、大きな問題が発生します。 この方法の問題は、コードの再起動時に一時的な状態が存在しなくなったため、例外が常に繰り返されるとは限らないということです。 この問題の詳細については、「.jdinfo (JIT_DEBUG_INFO の使用)」を参照してください。

この問題を回避するには、.jdinfo または .dump /j を使用します。 この方法を使用すると、デバッガーを対象のコード エラーのコンテキストに入ることができます。 詳細については、このトピックで後述する「Just In Time (JIT) デバッグ」を参照してください。

CDB

事後デバッガーを CDB に設定するには、cdb -iae (AeDebug のインストール) または cdb -iaecKeyString (コマンドを使用して AeDebug をインストール) を実行します。

C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\cdb.exe -iae
C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\cdb.exe -iae

-iaec パラメーターを使用する場合、KeyString は、事後デバッガーを起動するために使用されるコマンド ラインの末尾に追加する文字列を指定します。 KeyString にスペースが含まれる場合は、引用符で囲む必要があります。

C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\cdb.exe -iaec [KeyString]
C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\cdb.exe -iaec [KeyString]

このコマンドでは、成功した場合は何も表示されません。失敗した場合はエラー メッセージが表示されます。

NTSD

事後デバッガーを NTSD に設定するには、ntsd -iae (AeDebug のインストール) または ntsd -iaecKeyString (コマンドを使用して AeDebug をインストール) を実行します。

C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\ntsd.exe -iae
C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\ntsd.exe -iae

-iaec パラメーターを使用する場合、KeyString は、事後デバッガーを起動するために使用されるコマンド ラインの末尾に追加する文字列を指定します。 KeyString にスペースが含まれる場合は、引用符で囲む必要があります。

C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\ntsd.exe -iaec [KeyString]
C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\ntsd.exe -iaec [KeyString]

このコマンドは、成功した場合は何も表示されません。失敗した場合は新しいコンソール ウィンドウにエラーが表示されます。

注意 -p %ld -e %ld -g パラメーターは常に事後デバッガーのコマンド ラインで最初に表示されるため、-iaec スイッチを使用して -server パラメーターを指定しないでください。これは、-server はコマンド ラインで最初に表示されない限り機能しないためです。 このパラメーターを含む事後デバッガーをインストールするには、レジストリを手動で編集する必要があります。

Visual Studio JIT デバッガー

Visual Studio がインストールされている場合、vsjitdebugger.exe は事後デバッガーとして登録されます。 Visual Studio JIT デバッガーは、プロセスを対話形式でデバッグすることを意図しています。

Debugger = "C:\WINDOWS\system32\vsjitdebugger.exe" -p %ld -e %ld

Visual Studio が更新または再インストールされると、このエントリが再度書き込まれ、設定された代替値が上書きされます。

Window Sysinternals ProcDump

The Windows Sysinternals ProcDump ユーティリティは、事後ダンプ キャプチャにも使用できます。 ProcDump の使用とダウンロードの詳細については、「ProcDump」を参照してください。

.dump WinDbg コマンドと同様に、ProcDump はクラッシュのダンプを非対話形式でキャプチャできます。 キャプチャは、任意の Windows システム セッションで発生する可能性があります。

ProcDump は、ダンプ ファイル キャプチャが完了すると終了し、WER によってエラーが報告され、エラー プロセスが終了します。

procdump -i を使用して、procdump をインストールし、-u をし用意して、32 ビットと 64 ビットの事後デバッグの両方で ProcDump をアンインストールします。

<Path>\procdump.exe -i

インストールとアンインストールのコマンドは、成功した場合に変更されたレジストリ値と、失敗した場合のエラーを出力します。

レジストリの ProcDump コマンド ライン オプションは、次の値に設定されます。

Debugger = <Path>\ProcDump.exe -accepteula -j "<DumpFolder>" %ld %ld %p

ProcDump では、PID、イベント、JIT_DEBUG_INFO の 3 つのパラメーターがすべて使用されます。 JIT_DEBUG_INFO パラメーターの詳細については、以下の「Just-In-Time (JIT) デバッグ」を参照してください。

キャプチャされたダンプのサイズは、サイズ オプションが設定されていない Mini (process/threads/handles/modules/address space)、-mp が設定された MiniPlus (Mini plus MEM_PRIVATE ページ)、または -ma が設定された完全 (すべてのメモリ - 「.dump /mA」に相当) に既定で設定されます。

十分なドライブ領域を持つシステムの場合は、Full (-ma) キャプチャをお勧めします。

-i オプションと共に -ma を使用して、すべてのメモリ キャプチャを指定します。 必要に応じて、ダンプ ファイルのパスを指定します。

<Path>\procdump.exe -ma -i c:\Dumps

ドライブ領域が限られているシステムの場合は、MiniPlus (-mp) キャプチャをお勧めします。

<Path>\procdump.exe -mp -i c:\Dumps

ダンプ ファイルを保存するフォルダーは省略可能です。 既定値は現在のフォルダーです。 フォルダーは、C:\Windows\Temp で使用されているものと同じかそれ以上の ACL で保護する必要があります。フォルダーに関連するセキュリティの管理の詳細については、「事後デバッグ中のセキュリティ」を参照してください。

事後デバッガーとして ProcDump をアンインストールし、前の設定を復元するには、-u (アンインストール) オプションを使用します。

<Path>\procdump.exe -u

ProcDump の詳細については、「ProcDump」と Microsoft Press 発行の Mark Russinovich and Aaron Margosis 著 「Windows SysInternals 管理者用参照資料」を参照してください。

Just In Time (JIT) デバッグ

障害が発生しているアプリケーションへのコンテキストの設定

既に説明したように、JIT_DEBUG_INFO パラメーターを使用してクラッシュの原因となった例外にコンテキストを設定することが非常に望ましいです。 この詳細については、「.jdinfo (JIT_DEBUG_INFO の使用)」を参照してください。

Windows 用デバッグ ツール

この例では、レジストリを編集して、.jdinfo <address> コマンドを使用して追加の例外情報を表示する初期コマンド (-c) を実行し、コンテキストを例外の場所に変更する方法を示します (.ecxr の使用方法と同様に、コンテキストを例外レコードに設定します)。

Debugger = "<Path>\windbg.exe -p %ld -e %ld -c ".jdinfo 0x%p"
Auto = 1

%p パラメーターは、ターゲット プロセスのアドレス領域内の JIT_DEBUG_INFO 構造体のアドレスです。 %p パラメーターは、16 進値として解釈されるように、0x で事前に追加されます。 詳細については、「.jdinfo (JIT_DEBUG_INFO を使用する)」を参照してください。

32 ビットアプリと 64 ビット アプリの組み合わせをデバッグするには、32 ビットと 64 ビットの両方のレジストリ キー (前述) を構成し、適切なパスを 64 ビットと 32 ビットの WinDbg.exe の場所に設定します。

.dump を使用したダンプ ファイルの作成

JIT_DEBUG_INFO データを含む障害が発生するたびにダンプ ファイルをキャプチャするには、.dump /j <address> を使用します。

<Path>\windbg.exe -p %ld -e %ld -c ".dump /j %p /u <DumpPath>\AeDebug.dmp; qd"

/u オプションを使用して一意のファイル名を生成し、複数のダンプ ファイルを自動的に作成できるようにします。 オプションの詳細については、「.dump (ダンプ ファイルの作成)」を参照してください。

作成されたダンプには、JITDEBUG_INFO データが既定の例外コンテキストとして格納されます。 .jdinfo を使用して例外情報を表示し、コンテキストを設定する代わりに、.exr -1 を使用して例外レコードを表示し、.ecxr を使用してコンテキストを設定します。 詳細については、「.exr (例外レコードの表示)」「.ecxr (例外コンテキスト レコードの表示)」を参照してください。

Windows エラー報告 - q / qd

デバッグ セッションの終了方法によって、Windows エラー報告がエラーを報告するかどうかが決まります。

デバッガーを閉じる前に qd を使用してデバッグ セッションがデタッチされた場合、WER はエラーを報告します。

デバッグ セッションが q を使用して終了した場合 (またはデタッチせずにデバッガーが閉じている場合)、WER はエラーを報告しません。

;q または ;qd をコマンド文字列の末尾に追加して、目的の動作を呼び出します。

たとえば、CDB がダンプをキャプチャした後に WER がエラーを報告できるようにするには、このコマンド文字列を構成します。

<Path>\cdb.exe -p %ld -e %ld -c ".dump /j 0x%p /u c:\Dumps\AeDebug.dmp; qd"

この例では、WinDbg がダンプをキャプチャした後に、WER がエラーを報告できるようにします。

<Path>\windbg.exe -p %ld -e %ld -c ".dump /j %p /u <DumpPath>\AeDebug.dmp; qd""

セキュリティの脆弱性

他のユーザーと共有するコンピューターで事後デバッグを有効にすることを検討している場合は、「事後デバッグ中のセキュリティ」を参照してください。