更新 : 2007 年 11 月
このトピックでは、共通言語ランタイム (CLR: Common Language Runtime) デバッグ サービスに用意されている機能の概要を説明します。次のサブセクションがあります。
プログラムへのアタッチまたはプログラムの起動
実行の制御
プログラムの状態の確認
プログラムの状態の変更
エディット コンティニュの使用
関数の評価
コードの動的な挿入
プログラムへのアタッチまたはプログラムの起動
CLR を使用すると、実行中のプログラムにデバッガをアタッチしたり、新しいプロセスを開始したりできます。CLR デバッグ サービスは Just-In-Time (JIT) デバッグをサポートしており、ハンドルされない例外をスローしたプログラムにデバッガをアタッチできます。ただし、デバッグ可能モードで実行されていないプログラムでは、使用できるデバッグ情報が少ない場合があります。この問題を回避するには、プログラムを常にデバッグ可能なモードで実行します。デバッグ可能モードの詳細については、次のトピックを参照してください。
実行の制御
CLR デバッグ サービスには、プログラムの実行を制御するいくつかの方法が用意されています。これには、ブレークポイント、シングル ステップ実行、例外通知、関数の評価、およびプログラムの起動とシャットダウンに関係するその他のイベントが含まれます。
CLR デバッグ API ではマネージ コードのみの例外を制御できます。アンマネージ コードで例外制御を実行するには、デバッガにその機能を別途実装する必要があります。
ブレークポイント
コードを指定し、中断する位置の Miccrosoft Intermediate Language (MSIL) オフセットまたはネイティブ オフセットを指定することで、ブレークポイントを作成できます。ブレークポイントを作成すると、ブレークポイントが検出されたときにデバッガに通知されます。デバッグ API は条件付きブレークポイントを直接サポートしていませんが、デバッガで条件付きブレークポイントを実装できます。ブレークポイントに応じて式を評価し、ユーザーに停止を通知するかどうかを決定します。
ステップ実行
CLR デバッグ サービスにはさまざまなステップ実行機能が用意されています。プログラム コードで一度に 1 つの命令だけを実行するか (シングル ステップ実行)、ある範囲の命令を一度に実行できます (範囲ステップ実行)。関数に対するステップ オーバー、ステップ イン、またはステップ アウトを実行できます。ステップ実行を中断させる例外が発生した場合に、CLR デバッグ サービスによってデバッガに通知することもできます。
デバッグ サービスではアンマネージ コードのステップ実行を直接サポートはしていませんが、ステップ実行処理中にアンマネージ コードに達した場合にデバッガに制御を渡すコールバックが用意されています。また、アンマネージ コードからマネージ コードに入る直前の時点をデバッガで確認できる機能も用意されています。
CLR はソースレベルのステップ実行を直接サポートしていません。デバッガは、範囲ステップ実行と独自のソース マッピング情報を使用することで、この機能を実装できます。シンボル ストア インターフェイスを使用すると、ソースレベルの情報を取得できます。これらのインターフェイスの詳細については、「シンボル ストア診断 (アンマネージ API リファレンス)」を参照してください。
例外
CLR デバッグ サービスを使用すると、マネージ コード内の初回例外とセカンド チャンス例外の両方をデバッガに通知できます。スローされたオブジェクトを各ポイントで検査に使用できます。
アンマネージ コード内のネイティブな例外は、マネージ コードまで反映されない限り CLR では処理されません。ただし、CLR デバッグ サービスと共有されている Win32 デバッグ サービスを使用すると、アンマネージ例外を処理できます。
プログラム イベント
CLR デバッグ サービスにより、多数のプログラム イベントが、発生時にデバッガに通知されます。通知されるイベントには、プロセスの作成と終了、スレッドの作成と終了、アプリケーション ドメインの作成と終了、アセンブリの読み込みとアンロード、モジュールの読み込みとアンロード、クラスの読み込みとアンロードがあります。パフォーマンスを維持するために、モジュールに対するクラスの読み込みとアンロードのイベントを無効にすることができます。既定では、クラスの読み込みとアンロードのイベントは無効になっています。
スレッド コントロール
CLR デバッグ サービスには、個々の (マネージ) スレッドを保留および再開するためのインターフェイスが用意されています。
プログラムの状態の確認
CLR デバッグ サービスには、プロセスが停止状態のときに、マネージ コードを実行しているプロセスの各部分を検査する詳細な方法が用意されています。プロセスを検査することにより、物理スレッドのリストを取得できます。
スレッドを調査することにより、呼び出し履歴を検査できます。スレッドの呼び出し履歴は、チェーン レベルとスタック フレーム レベルの 2 つのレベルに分解されます。呼び出し履歴はまずチェーンに分解されます。チェーンは連続する呼び出し履歴の論理セグメントであり、完全にマネージまたはアンマネージのスタック フレームのみが含まれています。さらに、単一のチェーンに含まれるすべてのマネージ コール フレームは同じ CLR コンテキストを共有します。チェーンはマネージまたはアンマネージのどちらでもかまいません。
各マネージ チェーンは、さらに単一のスタック フレームに分解されます。各スタック フレームは 1 回のメソッド呼び出しを表します。スタック フレームに照会して、実行中のコードを取得できます。または、実行中のコードの引数、ローカル変数、およびネイティブ レジスタを取得できます。
アンマネージ チェーンにスタック フレームは含まれません。その代わりに、アンマネージ コードに割り当てられた広範囲のスタック アドレスが用意されています。アンマネージ コード デバッガは、スタックのアンマネージ部分のデコードとスタック トレースを行うかどうかを決定できます。
![]() |
---|
ローカル変数はソース コード内に存在するため、CLR デバッグ サービスはローカル変数の概念をサポートしません。デバッガはローカル変数を割り当てにマップするかどうかを決定できます。 |
CLR デバッグ サービスでは、グローバル変数、クラス静的変数、およびスレッド ローカル変数にアクセスすることもできます。
プログラムの状態の変更
CLR デバッグ サービスにより、デバッガは実行中に命令ポインタの物理位置を変更できます。ただし、これは危険を伴う操作です。次の条件が満たされている場合は、命令ポインタを正常に変更できる可能性があります。
現在の命令ポインタとターゲットの命令ポインタが両方ともシーケンス ポイントにある。シーケンス ポイントはおよそのステートメント境界を表します。
ターゲット命令ポインタが例外フィルタ、catch ブロック、または finally ブロック内にない。
catch ブロック内の場合、ターゲット命令ポインタが catch ブロックの外側にない。
ターゲット命令ポインタが現在の命令ポインタと同じフレーム内にある。
命令ポインタの物理位置が変更されると、現在の命令ポインタの位置にある変数が、ターゲット命令ポインタの位置にある変数にマップされます。ターゲット命令ポインタの位置にあるガベージ コレクション参照は、正しく初期化されます。
命令ポインタが変更された後、CLR デバッグ サービスはキャッシュされたスタック情報を有効とマークし、次回必要になったときに情報を更新します。フレームやチェーンなどのスタック情報へのポインタをキャッシュするデバッガは、命令ポインタを変更した後、この情報を更新する必要があります。
デバッガは、プログラムが停止しているときにプログラムのデータを変更することもできます。デバッガは検査と同様の方法で、関数の実行中に関数のローカル変数と引数を変更できます。また、配列およびオブジェクトのフィールドと、静的フィールドおよびグローバル変数を更新できます。
エディット コンティニュの使用
エディット コンティニュは、デバッグ セッションの途中でソース コードを編集し、変更したソースを再コンパイルした後、デバッグ セッションを続行できる機能です。実行可能ファイルを最初から再実行する必要はありません。関数の視点から説明すると、エディット コンティニュは、デバッグ中の実行可能ファイルの残りの部分の実行時状態を保持したまま、デバッガで実行中のコードを変更できる機能です。
関数の評価
ユーザー式とオブジェクトの動的なプロパティを評価するには、デバッグ対象プロセスのコードを実行するための方法がデバッガに必要です。CLR デバッグ サービスを使用すると、デバッガは関数またはメソッドを呼び出して、デバッガのプロセスの内部で実行できます。
このような処理は危険を伴うため、CLR により、デバッガはこのような処理を中止できます。たとえば、このような処理によって既存のコードにデッドロックが発生することがあります。評価が正常に中止されると、スレッドは、評価が行われなかった場合と同様に処理されます。ただし、例外として、部分的な評価によるローカル変数への副作用があります。関数からアンマネージ コードまたはアンマネージ ブロックに何らかの方法で呼び出しが行われると、評価を終了できない場合があります。
関数の評価が完了した場合、CLR はコールバックを使用して、評価が正常に終了したか、関数が例外をスローしたかをデバッガに通知します。ICorDebugValue メソッドおよび ICorDebugValue2 メソッドを使用して、評価の結果を検査できます。
関数の評価が実行されるスレッドは、マネージ コード内の、ガベージ コレクションに対して安全なポイントで停止する必要があります (関数の評価はハンドルされない例外に対しても実行できます)。最適化されていないコードでは、このようなセーフ ポイントはどこにでもあります。ブレークポイントまたは MSIL レベルのステップ処理のほとんどがセーフ ポイントで完了します。ただし、このようなポイントは、最適化されたコードにはほとんどありません。関数全体でセーフ ポイントが 1 つもない場合もあります。ガベージ コレクションに対して安全なポイントが出現する頻度は、関数によって異なります。最適化されていないコード内でも、セーフ ポイントで停止しないこともできます。最適化されたコードでも最適化されていないコードでも、ICorDebugController::Stop メソッドがセーフ ポイントで実行されることはほとんどありません。
CLR デバッグ サービスはスレッドに新しいチェーンを設定して関数の評価を開始し、要求された関数を呼び出します。評価が開始するとすぐに、実行制御、検査、関数の評価などのデバッグ API のすべての機能が使用できるようになります。入れ子の評価はサポートされています。ブレークポイントは通常どおり処理されます。
コードの動的な挿入
一部のデバッガでは、[イミディエイト] ウィンドウに任意のステートメントを入力し、入力したステートメントを実行できます。CLR デバッグ サービスはこのシナリオをサポートします。妥当な範囲内で、どのようなコードを動的に挿入できるかについての制限はありません (たとえば、ローカルでない goto ステートメントは使用できません)。
動的なコード挿入は、エディット コンティニュ操作と関数の評価を組み合わせて実装されています。挿入するコードは関数内にラップされ、エディット コンティニュを使用して挿入されます。その後、挿入された関数が評価されます。必要に応じて、ByRef として宣言した引数をラッパー関数に渡し、副作用を即時かつ永続的にすることができます。