コードのどこかにブレークポイントを置いたとします。デバッガーはプログラムをその時点まで実行させるだけですか、それとも実際に命令ごとに解釈しますか? プログラムが -g フラグを使用してコンパイルされているとします。私の友人が、デバッガーがシンボル テーブルのスタックに変数のアドレスを保持できないため、解釈する必要があると言っていたので、質問しています。ただし、関数が入力されたときに、少なくともデバッガーはスタックの先頭からのスタック変数のオフセットを知っていると主張しました。
2 に答える
コードのどこかにブレークポイントを置いたとします。デバッガーはプログラムをその時点まで実行させるだけですか、それとも実際に命令ごとに解釈しますか?
場合によります!システムにハードウェア ブレークポイントがある場合、単にブレークするアドレスがハードウェア レジスタに書き込まれます。CPU プログラム カウンターがトラップ アドレスの 1 つに達すると、CPU はある種のトラップ/IRQ/... を生成し、プログラムを停止してデバッガーの関数を呼び出します。
システムに書き込み可能なメモリはあるが、ハードウェア ブレークポイントがない場合、多くの場合、ブレークポイントのコードは、デバッガでいくつかの機能を実行するある種のトラップ命令に置き換えられます。
実行メモリに書き込むことができず、利用可能なハードウェア ブレークポイントがない場合、シングル ステップ モードでコードを実行できる場合があります。アセンブラーの各ステップの後、デバッガーがコールバックされます。デバッガ自体がブレークポイントのリストを保持しています。
プログラムが -g フラグを使用してコンパイルされているとします。私の友人が、デバッガーが変数のアドレスをシンボル テーブルのスタックに保持できないため、解釈する必要があると言っていたので、質問しています。
これはかなり間違っています。デバッグ情報には、各スタック フレームのフォーマットも含まれます。どの情報/変数/コンテンツがスタック内のどのrealtiv位置に配置されるかは、実際に実行中のスタックフレームのコンテキストによって異なります。デバッグ情報には、これに必要なすべての情報が含まれています。プログラムを停止すると、デバッガーはアドレスを認識し、プログラムの実際のコンテキスト/ブロックを計算できます。また、デバッグ情報は、このフレームで実際に使用されているスタック フレームの内容を認識します。
ただし、関数が入力されたときに、少なくともデバッガーはスタックの先頭からのスタック変数のオフセットを知っていると主張しました。
右!
デバッガー自体は、プログラムを「実行」または「シミュレート」しませんでした。デバッガ自体は、特定のシステムでプログラムがどのように実行されるかのみを制御します。システムは、CPU とターゲット システムをシミュレートするシミュレーターにすることもできます。また、リモート デバッグもこのコンテキストのトピックです。どのような種類のシステムでも、システム自体へのデバッグ インターフェイスが必要です。
私の知る限り、GDBは環境を「仮想化」します。たとえば、リバース実行を考えてみましょう。実際の CPU を「リバース」する方法はまったくありません。GDB が行うことは、プロセスを追跡し、最も遠い時点で実行を一時停止し、実際の状態に戻るまで環境の以前の状態の「ビュー」を提供することです。
また、GDB は、システムで実行されている GDB と、接続された組み込みシステムで実行されているデバッグ済みの実行可能ファイルをクロスデバッグできます。この場合、GDB は同じ CPU アーキテクチャ上でさえ実行されていませんが、実行可能ファイルを「解釈」していません (実際に実行するには他のシステムが必要です)。つまり、物事を追跡し、一時停止してその実行を検査できるようにします。
-g
デバッグシンボルを追加することです。リリース コードでは、変数foo
はもはやfoo
ではなく、単なるメモリ内のアドレスです。デバッグ シンボルを使用すると、GDB はアドレス0xdeadbeef
が実際にfoo
. スタックトレースで関数名を見ることは、アドレスのリストよりもはるかに啓発的です...
(免責事項: 私は GDB の専門家とはほど遠いです。私は GDB を毎日使用していますが、私の使用法はパンとバターの種類です。他の人がもっと詳細な回答を表示したり、私がどこにいるのかを指摘したりすると確信しています。間違っていますが、それまでは、これが私ができる最善の答えです. ;-) )