コンテキストの変更

カーネル モードのデバッグでは、多数のプロセス、スレッド、時にはユーザー セッションが同時に実行されることがあります。 そのため、"仮想アドレス 0x80002000" や "eax レジスタ" などの語句はあいまいです。 このような語句を理解できる コンテキスト を指定する必要があります。

デバッガーには、デバッグ中に設定できる 5 つの異なるコンテキストがあります。

  1. セッション コンテキストは、既定のユーザー セッションを示します。

  2. プロセス コンテキストは、デバッガーが仮想アドレスを解釈する方法を決定します。

  3. ユーザー モードのアドレス コンテキストが直接設定されることは、ほとんどありません。 このコンテキストは、プロセス コンテキストを変更すると自動的に設定されます。

  4. レジスタ コンテキストは、デバッガーがレジスタを解釈する方法を決定し、スタック トレースの結果も制御します。 このコンテキストはスレッド コンテキストとも呼ばれますが、その用語は完全には正確ではありません。 明示的なコンテキストも、レジスタ コンテキストの一種です。 明示的なコンテキストを指定した場合、現在のレジスタ コンテキストではなく、そのコンテキストが使用されます。

  5. ローカル コンテキストは、デバッガーがローカル変数を解釈する方法を決定します。 このコンテキストはスコープとも呼ばれます。

セッション コンテキスト

同時に複数のセッションを実行することができます。 各ログオン セッションには、独自のプロセスがあります。

!session 拡張機能は、すべてのログオン セッションを表示するか、現在のセッション コンテキストを変更します。

セッション番号が "-2" と入力された場合、セッション コンテキストは、!sprocess および !spoolused 拡張機能によって使用されます。

セッション コンテキストが変更されると、プロセス コンテキストは自動的にそのセッションのアクティブなプロセスに変更されます。

プロセス コンテキスト

各プロセスには、仮想アドレスが物理アドレスにマップされる方法を記録する独自のページ ディレクトリがあります。 プロセス内のスレッドが実行中の場合、Windows オペレーティング システムはこのページ ディレクトリを使用して仮想アドレスを解釈します。

ユーザー モードのデバッグ中は、現在のプロセスによってプロセス コンテキストが決定されます。 デバッガー コマンド、拡張機能、デバッグ情報ウィンドウで使用される仮想アドレスは、現在のプロセスのページ ディレクトリを使用して解釈されます。

カーネル モードのデバッグ中は、.process (プロセス コンテキストの設定) コマンドを使用してプロセス コンテキストを設定できます。 このコマンドを使用して、どのプロセスのページ ディレクトリを仮想アドレスの解釈に使用するかを選択します。 プロセス コンテキストを設定した後は、アドレスを受け取る任意のコマンドでこのコンテキストを使用できます。 このアドレスにブレークポイントを設定することもできます。 .process コマンドに /i オプションを含めて侵入デバッグを指定することで、カーネル デバッガーを使用してユーザー空間にブレークポイントを設定することもできます。

カーネル空間関数でプロセス固有のブレークポイントを使用して、カーネル デバッガーからユーザー モードのブレークポイントを設定することもできます。 戦略的なブレークポイントを設定し、適切なコンテキストが表示されるまで待ちます。

ユーザー モード アドレス コンテキストは、プロセス コンテキストの一部です。 通常、ユーザー モードのアドレス コンテキストを直接設定する必要はありません。 プロセス コンテキストを設定すると、ユーザー モードのアドレス コンテキストは、プロセスに関連するページ テーブルのディレクトリ ベースに自動的に変更されます。

カーネル モード デバッグ中にプロセス コンテキストを設定すると、別の .process コマンドによってコンテキストが変更されるまで、そのプロセス コンテキストが保持されます。 ユーザー モードのアドレス コンテキストも、.process または .context コマンドによって変更されるまで保持されます。 これらのコンテキストは、ターゲット コンピューターの実行時に変更されず、レジスタ コンテキストまたはローカル コンテキストの変更の影響を受けません。

レジスタ コンテキスト

各スレッドには独自のレジスタ値があります。 これらの値は、スレッドの実行中は CPU レジスタに保存され、別のスレッドの実行中はメモリに保存されます。

通常、ユーザー モードのデバッグ中は、現在のスレッドによってレジスタ コンテキストが決定されます。 デバッガー コマンド、拡張機能、デバッグ情報ウィンドウ内のレジスタへの参照は、現在のスレッドのレジスタに従って解釈されます。

次のいずれかのコマンドを使用して、ユーザー モード デバッグの実行中に、レジスタ コンテキストを現在のスレッド以外の値に変更できます。

.cxr (コンテキスト レコードの表示)

.ecxr (例外コンテキスト レコードの表示)

カーネル モードのデバッグ中は、次のコマンドを含むさまざまなデバッガー コマンドを使用してレジスタ コンテキストを制御できます。

.thread (レジスタ コンテキストの設定)

.cxr (コンテキスト レコードの表示)

.trap (トラップ フレームの表示)

これらのコマンドは、CPU レジスタの値を変更しません。 代わりに、デバッガーはメモリ内の場所から指定されたレジスタ コンテキストを取得します。 実際には、デバッガーは保存されたレジスタ値のみを取得できます。 (その他の値は動的に設定され、保存されません。 保存された値は、スタック トレースを再作成するのに十分です。

レジスタ コンテキストが設定されると、k (Display Stack Backtrace)r (Registers) のようなレジスタ値を使用するすべてのコマンドに新しいレジスタ コンテキストが使用されます。

ただし、マルチプロセッサ コンピューターをデバッグする場合、一部のコマンドではプロセッサを指定することができます。 (このようなコマンドの詳細については、「マルチプロセッサ構文」を参照してください。) コマンドにプロセッサを指定すると、指定したプロセッサが現在アクティブなプロセッサであっても、現在のレジスタ コンテキストではなく、指定したプロセッサ上のアクティブ スレッドのレジスタ コンテキストが使用されます。

また、レジスタ コンテキストが現在のプロセッサ モードの設定と一致しない場合、これらのコマンドは正しくない出力または意味のない出力を生成します。 出力エラーを回避するために、レジスタの状態に依存するコマンドは、プロセッサ モードをレジスタ コンテキストに一致するように変更するまで失敗します。 プロセッサ モードを変更するには、.effmach (Effective Machine) コマンドを使用します。

レジスタ コンテキストを変更すると、ローカル コンテキストも変更されます。 このように、レジスタ コンテキストはローカル変数の表示に影響を与える場合があります。

アプリケーションの実行、ステップ実行、またはトレースが発生した場合、レジスタ コンテキストはプログラム カウンターの位置に一致するように直ちにリセットされます。 ユーザー モードでは、現在のプロセスまたはスレッドが変更されると、レジスタ コンテキストもリセットされます。

スタック トレースはスタック ポインター レジスタ (x86 ベースのプロセッサでは esp) が指す位置から始まるため、レジスタ コンテキストはスタック トレースに影響します。 レジスタ コンテキストが無効またはアクセスできない値に設定されている場合、スタック トレースは取得できません。

.apply_dbp (データ ブレークポイントをコンテキストに適用) コマンドを使用すると、特定のレジスタ コンテキストにプロセッサ ブレークポイント (データ ブレークポイント) を適用できます。

ローカル コンテキスト

プログラムが実行されている場合、ローカル変数の意味はプログラム カウンターの場所によって異なります。このような変数のスコープは、定義されている関数にのみ拡張されるためです。

ユーザー モードまたはカーネル モードのデバッグを実行する場合、デバッガーはローカル コンテキストとして現在の関数 (スタック上の現在のフレーム) のスコープを使用します。 このコンテキストを変更するには、.frame (ローカル コンテキストの 設定) コマンドを使用するか、[呼び出し] ウィンドウで目的のフレームをダブルクリックします。

ユーザー モード デバッグでは、ローカル コンテキストは常に現在のスレッドのスタック トレース内のフレームです。 カーネル モード デバッグでは、ローカル コンテキストは常に、現在のレジスタ コンテキストのスレッドのスタック トレース内のフレームです。

ローカル コンテキストには、一度に 1 つのスタック フレームのみを使用できます。 他のフレームのローカル変数にはアクセスできません。

次のいずれかのイベントが発生すると、ローカル コンテキストはリセットされます。

  • プログラムの実行、ステップ実行、またはトレース

  • 任意のコマンドでスレッド区切り記号 (~) の使用

  • レジスタ コンテキストの変更

!for_each_frame拡張機能を使用すると、スタック内のフレームごとに 1 回、1 つのコマンドを繰り返し実行できます。 このコマンドは、各フレームのローカル コンテキストを変更し、指定したコマンドを実行して、ローカル コンテキストを元の値に戻します。