質問
デバッガはどのように動作するのでしょうか?特に、すでに実行中の実行可能ファイルに「接続」できるものです。コンパイラーがコードを機械語に変換することは理解していますが、では、デバッガーはコードが何に接続されているかをどのように「認識」するのでしょうか?
解決
デバッガーの動作の詳細は、デバッグ対象とOSによって異なります。 Windowsでのネイティブデバッグについては、MSDNで詳細を確認できます。 Win32デバッグAPI 。
ユーザーは、名前またはプロセスIDのどちらでアタッチするプロセスをデバッガーに指示します。名前の場合、デバッガーはプロセスIDを検索し、システムコールを介してデバッグセッションを開始します。 Windowsでは、これは DebugActiveProcess になります。
>アタッチされると、デバッガーはUIのようにイベントループに入りますが、ウィンドウシステムからのイベントの代わりに、OSはデバッグ中のプロセスで発生することに基づいてイベントを生成します–たとえば、例外が発生します。 WaitForDebugEvent を参照してください。
デバッガーは、ターゲットプロセスの仮想メモリの読み取りと書き込みを行い、OSが提供するAPIを介してレジスタ値を調整することもできます。 Windowsのデバッグ関数のリストを参照してください。
デバッガーは、シンボルファイルの情報を使用して、アドレスからソースコード内の変数名と場所に変換できます。シンボルファイル情報はAPIの別個のセットであり、OSのコア部分ではありません。 Windowsでは、これは Debug Interface Access SDK を介して行われます。
管理環境(.NET、Javaなど)をデバッグしている場合、プロセスは通常似ていますが、仮想マシン環境は基盤となるOSではなくデバッグAPIを提供するため、詳細は異なります。
他のヒント
私が理解しているように:
x86 上のソフトウェア ブレークポイントの場合、デバッガは命令の最初のバイトを次のバイトに置き換えます。 CC
(int3
)。これは次のように行われます WriteProcessMemory
Windows 上で。CPU がその命令に到達し、 int3
, 、これにより、CPU がデバッグ例外を生成します。OS はこの割り込みを受信し、プロセスがデバッグ中であることを認識し、ブレークポイントにヒットしたことをデバッガー プロセスに通知します。
ブレークポイントにヒットしてプロセスが停止すると、デバッガーはブレークポイントのリストを調べ、ブレークポイントを置き換えます。 CC
もともとそこにあったバイトで。デバッガセット TF
, 、トラップフラグ で EFLAGS
(変更することで、 CONTEXT
)、プロセスを続行します。トラップ フラグにより、CPU はシングルステップ例外を自動的に生成します (INT 1
) 次の指示で。
デバッグ中のプロセスが次回停止するとき、デバッガはブレークポイント命令の最初のバイトを再び次のバイトに置き換えます。 CC
, となり、プロセスが続行されます。
これがすべてのデバッガーで正確に実装されている方法であるかどうかはわかりませんが、このメカニズムを使用して自身をデバッグできる Win32 プログラムを作成しました。まったく役に立たないが、勉強になる。
Windows OS を使用している場合、これに関する優れたリソースは、John Robbins の「Debugging Applications for Microsoft .NET and Microsoft Windows」です。
(または古いバージョンでも: 「アプリケーションのデバッグ」)
この本には、デバッガの仕組みに関する章があり、いくつかの単純な (ただし動作する) デバッガのコードが含まれています。
私は Unix/Linux のデバッグの詳細には詳しくないので、この内容は他の OS にはまったく当てはまらないかもしれません。しかし、非常に複雑な主題への入門として、概念 (詳細や API ではないにしても) は、ほとんどの OS に「移植」されるべきだと思います。
デバッグを理解するためのもう1つの貴重な情報源は、Intel CPUマニュアル(Intel® 64およびIA-32アーキテクチャです) ソフトウェア開発者のマニュアル)。ボリューム3Aの第16章では、特別な例外やハードウェアデバッグレジスタなど、デバッグのハードウェアサポートを紹介しました。以下はその章からのものです:
T(トラップ)フラグ、TSS—試行が行われたときにデバッグ例外(#DB)を生成します TSSにTフラグが設定されたタスクに切り替えるようにしました。
WindowまたはLinuxがこのフラグを使用するかどうかはわかりませんが、その章を読むのは非常に興味深いです。
これが誰かの助けになることを願っています。
私の理解では、アプリケーションまたはDLLファイルをコンパイルするとき、コンパイルするものにはすべて、関数と変数を表すシンボルが含まれます。
デバッグビルドを使用している場合、これらのシンボルはリリースビルドの場合よりもはるかに詳細であるため、デバッガはより多くの情報を提供できます。デバッガーをプロセスにアタッチすると、現在アクセスされている関数が調べられ、ここから利用可能なすべてのデバッグシンボルが解決されます(コンパイルされたファイルの内部がどのようなものかがわかっているため、メモリ内の内容を確認できます) 、int、float、stringなどのコンテンツを含む)。最初のポスターが言ったように、この情報とこれらの記号がどのように機能するかは、環境と言語に大きく依存します。
ここで答えるべき2つの主な質問があると思います:
1。デバッガーは、例外が発生したことをどのように認識するのですか?
デバッグ中のプロセスで例外が発生すると、ターゲットプロセスで定義されたユーザー例外ハンドラーが例外に応答する機会が与えられる前に、OSからデバッガーに通知されます。デバッガーがこの(最初の)例外通知を処理しないことを選択した場合、例外ディスパッチシーケンスはさらに進み、ターゲットスレッドは、必要に応じて例外を処理する機会を与えられます。 SEH例外がターゲットプロセスによって処理されない場合、デバッガにはセカンドチャンス通知と呼ばれる別のデバッグイベントが送信され、ターゲットプロセスで未処理の例外が発生したことが通知されます。 ソース
2。デバッガーがブレークポイントで停止する方法をどのように認識するか
回答 is:ブレークポイントをプログラムに入れると、デバッガーはそのポイントのコードをソフトウェア割り込み。結果として、プログラムは中断され、デバッガーが呼び出されます。