イベントのデバッグ

デバッグ イベントは、システムがデバッガーに通知する原因となる、デバッグ中のプロセス内のインシデントです。 デバッグ イベントには、プロセスの作成、スレッドの作成、ダイナミック リンク ライブラリ (DLL) の読み込み、DLL のアンロード、出力文字列の送信、例外の生成などがあります。

デバッガーが待機中にデバッグ イベントが発生した場合、システムは WaitForDebugEvent で指定された DEBUG_EVENT 構造体にイベントを記述する情報を入力します。

システムがデバッグ イベントをデバッガーに通知すると、影響を受けるプロセス内のすべてのスレッドも中断されます。 デバッガーが ContinueDebugEvent を使用してデバッグ イベントを続行するまで、スレッドは実行を再開しません。 次のデバッグ イベントは、プロセスのデバッグ中に発生する可能性があります。

イベント デバッグ 説明
CREATE_PROCESS_DEBUG_EVENT
デバッグ中のプロセスで新しいプロセスが作成されたとき、またはデバッガーが既にアクティブなプロセスのデバッグを開始するたびに生成されます。 システムは、プロセスがユーザー モードで実行を開始する前と、システムが新しいプロセスの他のデバッグ イベントを生成する前に、このデバッグ イベントを生成します。
DEBUG_EVENT 構造体は CREATE_PROCESS_DEBUG_INFO 構造体を含みます。 この構造体には、新しいプロセスへのハンドル、プロセスのイメージ ファイルへのハンドル、プロセスの初期スレッドへのハンドル、および新しいプロセスを説明するその他の情報が含まれます。
プロセスへのハンドルには、PROCESS_VM_READとPROCESS_VM_WRITEアクセス権があります。 デバッガーにスレッドへのこのような種類のアクセス権がある場合は、 ReadProcessMemory 関数と WriteProcessMemory 関数を使用して、プロセスのメモリに対する読み取りと書き込みを行うことができます。 システムが以前に EXIT_PROCESS_DEBUG_EVENT イベントを報告した場合、デバッガーが ContinueDebugEvent 関数を呼び出すと、システムはこのハンドルを閉じます。
プロセスのイメージ ファイルへのハンドルにはGENERIC_READアクセス権があり、読み取り共有用に開かれます。 デバッガーは、CREATE_PROCESS_DEBUG_EVENTの処理中にこのハンドルを閉じる必要があります。
プロセスの初期スレッドへのハンドルには、スレッドへのTHREAD_GET_CONTEXT、THREAD_Standard EditionT_CONTEXT、およびTHREAD_SUSPEND_RESUMEアクセス権があります。 デバッガーがスレッドに対してこのような種類のアクセス権を持つ場合、 GetThreadContext 関数と SetThreadContext 関数を使用してスレッドのレジスタの読み取りと書き込みを行うことができます。また、 SuspendThread 関数と ResumeThread 関数を使用してスレッドを中断および再開できます。 システムが以前に EXIT_PROCESS_DEBUG_EVENT イベントを報告した場合、デバッガーが ContinueDebugEvent 関数を呼び出すと、システムはこのハンドルを閉じます。
CREATE_THREAD_DEBUG_EVENT
デバッグ中のプロセスで新しいスレッドが作成されたとき、またはデバッガーが既にアクティブなプロセスのデバッグを開始するたびに生成されます。 このデバッグ イベントは、新しいスレッドがユーザー モードで実行を開始する前に生成されます。
DEBUG_EVENT 構造体は CREATE_THREAD_DEBUG_INFO 構造体を含んでいます。 この構造体には、新しいスレッドとスレッドの開始アドレスへのハンドルが含まれます。 ハンドルには、スレッドへのTHREAD_GET_CONTEXT、THREAD_Standard EditionT_CONTEXT、およびTHREAD_SUSPEND_RESUMEアクセス権があります。 デバッガーがスレッドに対してこのような種類のアクセス権を持つ場合、 GetThreadContext 関数と SetThreadContext 関数を使用してスレッドのレジスタの読み取りと書き込みを行うことができます。また、 SuspendThread 関数と ResumeThread 関数を使用してスレッドを中断および再開できます。
システムが以前に EXIT_THREAD_DEBUG_EVENT イベントを報告した場合、デバッガーが ContinueDebugEvent 関数を呼び出すと、システムは新しいスレッドのハンドルを閉じます。
EXCEPTION_DEBUG_EVENT
デバッグ中のプロセスで例外が発生するたびに生成されます。 考えられる例外には、アクセスできないメモリへのアクセスの試行、ブレークポイント命令の実行、ゼロによる除算の試行、 構造化例外処理 に記載されているその他の例外などがあります。
DEBUG_EVENT 構造体には、 EXCEPTION_DEBUG_INFO 構造体が含まれています。 この構造体は、デバッグ イベントの原因となった例外を記述します。
標準の例外条件に加えて、コンソール プロセスのデバッグ中に追加の例外コードが発生する可能性があります。 Ctrl + C シグナルを処理し、デバッグ中のコンソール プロセスに Ctrl + C キーを押しながら入力すると、DBG_CONTROL_C例外コードが生成されます。 この例外コードは、アプリケーションによって処理されるものではありません。 アプリケーションでは、例外ハンドラーを使用して処理しないでください。 これはデバッガーの利点のためにのみ発生し、デバッガーがコンソール プロセスにアタッチされている場合にのみ使用されます。
プロセスがデバッグされていない場合、またはデバッガーが (gn コマンドを使用して) DBG_CONTROL_C例外をハンドルされない場合は、 SetConsoleCtrlHandler 関数に関するドキュメントに記載されているように、アプリケーションのハンドラー関数の一覧が検索されます。
デバッガーが (gh コマンドを使用して) DBG_CONTROL_C例外を処理する場合、次のようなコードを除き、アプリケーションは Ctrl + C キーを押します。
while ((inputChar = getchar()) != EOF) ...
したがって、デバッガーを使用して、このようなコードの読み取り待機が終了するのを停止することはできません。
EXIT_PROCESS_DEBUG_EVENT
デバッグ中のプロセスの最後のスレッドが終了するたびに生成されます。 このデバッグ イベントは、システムがプロセスの DLL をアンロードし、プロセスの終了コードを更新した直後に発生します。
DEBUG_EVENT 構造体には、終了コードを指定する EXIT_PROCESS_DEBUG_INFO 構造体が含まれています。
デバッガーは、このデバッグ イベントの受信時にプロセスに関連付けられている内部構造の割り当てを解除します。 システムは、終了プロセスとすべてのプロセスのスレッドに対するデバッガーのハンドルを閉じます。 デバッガーは、これらのハンドルを閉じてはなりません。
このイベントを受信するデバッガーが ContinueDebugEvent を呼び出すまで、プロセスのシャットダウンのカーネル モード部分を完了できません。 それまでは、プロセス ハンドルが開き、仮想アドレス空間が解放されないため、デバッガーは子プロセスを調べることができます。 プロセスのシャットダウンのカーネル モード部分が完了したときに通知を受信するには、CREATE_PROCESS_DEBUG_EVENTで返されたハンドルを複製し、 ContinueDebugEvent を呼び出して、重複したプロセス ハンドルが通知されるまで待機します。
EXIT_THREAD_DEBUG_EVENT
デバッグ中のプロセスの一部であるスレッドが終了するたびに生成されます。 システムは、スレッドの終了コードを更新した直後に、このデバッグ イベントを生成します。
DEBUG_EVENT 構造体には、終了コードを指定する EXIT_THREAD_DEBUG_INFO 構造体が含まれています。
終了スレッドがプロセスの最後のスレッドである場合、このデバッグ イベントは発生しません。 この場合、代わりにEXIT_PROCESS_DEBUG_EVENTデバッグ イベントが発生します。
デバッガーは、このデバッグ イベントの受信時にスレッドに関連付けられている内部構造の割り当てを解除します。 システムは、デバッガーのハンドルを終了スレッドに閉じます。 デバッガーでは、このハンドルを閉じてはいけません。
LOAD_DLL_DEBUG_EVENT
デバッグ中のプロセスが DLL を読み込むたびに生成されます。 このデバッグ イベントは、システム ローダーが DLL へのリンクを解決するとき、またはデバッグプロセスが LoadLibrary 関数を使用するときに発生します。 このデバッグ イベントは、システムがプロセスの仮想アドレス空間に DLL を初めてアタッチしたときにのみ発生します。
DEBUG_EVENT 構造には、 LOAD_DLL_DEBUG_INFO 構造が含まれています。 この構造体には、新しく読み込まれた DLL へのハンドル、DLL のベース アドレス、および DLL を記述するその他の情報が含まれます。 デバッガーは、LOAD_DLL_DEBUG_EVENTの処理中に DLL ハンドルのハンドルを閉じる必要があります。
通常、デバッガーは、このデバッグ イベントの受信時に DLL に関連付けられているシンボル テーブルを読み込みます。
OUTPUT_DEBUG_STRING_EVENT
デバッグ中のプロセスが、次を使用するときに生成されます
OutputDebugString 関数。 DEBUG_EVENT 構造には、 OUTPUT_DEBUG_STRING_INFO 構造が含まれています。 この構造体は、デバッグ文字列のアドレス、長さ、および形式を指定します。
UNLOAD_DLL_DEBUG_EVENT
デバッグ中のプロセスが FreeLibrary 関数を使用して DLL をアンロードするたびに生成されます。 このデバッグ イベントは、プロセスのアドレス空間から DLL が最後にアンロードされたとき (つまり、DLL の使用カウントが 0 の場合) にのみ発生します。
DEBUG_EVENT 構造には、 UNLOAD_DLL_DEBUG_INFO 構造が含まれています。 この構造体は、DLL をアンロードするプロセスのアドレス空間内の DLL のベース アドレスを指定します。
通常、デバッガーは、このデバッグ イベントを受信すると、DLL に関連付けられているシンボル テーブルをアンロードします。
プロセスが終了すると、システムはプロセスの DLL を自動的にアンロードしますが、UNLOAD_DLL_DEBUG_EVENTデバッグ イベントは生成しません。
RIP_EVENT
デバッグ中のプロセスがシステム デバッガーの制御外で終了するたびに生成されます。
DEBUG_EVENT 構造には、 RIP_INFO 構造が含まれています。 この構造体は、エラーとエラーの種類を指定します。