GDBはどのように実行を一時停止しますか


16

ご存知かもしれませんが、GDBを使用してコードにブレークポイントを設定し、デバッグのために実行を一時停止できます。

私の質問は、GDBがプロセスをどのように一時停止しi r、たとえばレジスタを使用してレジスタの内容を表示できるかです。これらのレジスタは、他のOSプロセスで常に使用されていませんか?どうして上書きされないのですか?

ライブデータではなく、コンテンツのスナップショットだけですか?


2
OSがプログラムを一時停止して別のプログラムを実行することを決定したときに、すべてのレジスタが上書きされないのはなぜですか?
user253751

CppCon 2018:サイモンブランド「C ++デバッガーの仕組み」youtube.com/watch?v=0DDrseUomfU
Robert Andrzejuk

回答:


24

アーキテクチャによって多少異なりますが、重要な点はほぼ例外なく適用されます。

  • 割り込みサービスにより、ISRを実行する前にCPUの状態(レジスタを含む)がメモリに保存され、ISRの終了時に復元されます。

  • 割り込みサービスルーチンが、これらのレジスタが保存されているメモリ位置の内容をスワップする場合、コンテキストスイッチを実行できます。すべてのスレッドには、スレッドが実行されていないときにレジスタが保存されるメモリ領域があります。

  • コンテキストスイッチは、スレッドがI / O、同期、その優先順位、シグナル配信などを待機しているかどうかを考慮するスレッドスケジューラによって制御されます。多くの場合、考慮される中断カウントがあります。

  • デバッガーは、スレッドが実行可能でないことを保証する中断カウントをインクリメントできます。その後、スレッドの保存されたレジスタのコピーを検査(および変更)できます。


14

@BenVoigtによる素晴らしい情報に加えて、いくつかの追加を許可します。

ブレークポイントは、デバッグするプロセスのマシンコード値(命令または命令の一部)を、ブレークする目的の(ソース)行に対応するコード内の特定のトラップ命令で置き換えることにより、デバッガーによって設定されます。この特定のトラップ命令は、ブレークポイントとして使用するためのものです。デバッガーはこれを認識し、オペレーティングシステムも認識します。

デバッグ中のプロセス/スレッドがトラップ命令にヒットすると、@ Benが記述しているプロセスをトリガーします。これには、現在実行中のスレッドを中断するコンテキストスワップの半分(CPU状態をメモリに保存することを含む)が含まれます。このトラップはブレークポイントトラップであるため、オペレーティングシステムは、おそらく@Benが記述するメカニズムを使用して、デバッグ中のプロセスを中断したままにし、デバッガーに通知し、最終的に再開します。

デバッガーは、システムコールを使用して、デバッグ中の中断されたプロセス/スレッドの保存された状態にアクセスします。

壊れたコード行(特定のトラップ命令を含むようになった)を実行(再開)するために、デバッガーはブレークポイントトラップ命令で上書きした元のマシンコード値を復元し、別の場所に別のトラップを設定します(シングルステップの場合、またはユーザーが新しいブレークポイントを作成します)、プロセス/スレッドを実行可能としてマークします。おそらく@Benが説明するメカニズムを使用します。

実際の詳細はより複雑になる可能性があります。ヒットした長時間実行のブレークポイントを維持することは、実際のコードのブレークポイントトラップをスワップアウトして行を実行できるようにすることを意味し、その後ブレークポイントを再びスワップインすることを意味するためです...

これらのレジスタは他のOSプロセスによって常に使用されていませんか?どうして上書きされないのですか?

@Benが説明しているように、タイムスライシングを使用して複数のプロセス/スレッドでプロセッサを共有できる既存のスレッドのサスペンド/レジューム機能(マルチタスクのコンテキストスイッチング/スワッピング)を使用します。

ライブデータではなく、コンテンツのスナップショットだけですか?

両方です。ブレークポイントにヒットしたスレッドはサスペンドされているため、サスペンド時のライブデータ(CPUレジスタなど)のスナップショットであり、CPUレジスタ信頼できるマスターは、スレッドが再開された場合にプロセッサに復元する値を登録します。デバッガーのユーザーインターフェイスを使用して(デバッグ中のプロセスの)CPUレジスターを読み取りおよび/または変更すると、システムコールを使用してこのスナップショット/マスターを読み取りおよび/または変更します。


1
さて、ほとんどのプロセッサアーキテクチャは、たとえばIP(命令ポインタ)がブレークポイントレジスタに格納されているアドレスと等しいときにトリガーするデバッグトラップをサポートしているため、コードを書き換える必要がありません。(IP以外のレジスタを照合することにより、データブレークポイントを取得でき、命令ごとにトラップすることにより、シングルステップを取得できます)コードが読み取り専用メモリにない限り、説明した内容ももちろん可能です。
ベンフォイト

最後の段落の「CPUレジスタを変更した場合...」について、「CUPレジスタの保存されたコピーを変更した場合...」を意味すると思います。その後、OSがプロセスを再開すると、変更したデータが書き戻されます実際のレジスタに。
14分、jamesqf

@jamesqf、はい、thx!
エリック・エイト

@BenVoigtは同意しました。ただし、デバッガーは無制限の数のブレークポイントを処理できますが、ハードウェアはゼロまたは少数を処理できるため、デバッガーはいくつかのジャグリングを行う必要があります。
エリック・エイト

@jamesqf:コピーとしてそれを記述することは少し誤解を招くです。これは、スレッドが実行されていない間のスレッド状態の公式ストレージです。
ベンフォイト

5

厳密に言えば、少なくともほとんどの場合、gdb自体は実行を一時停止しません。むしろ、gdbはOSに尋ね、OSは実行を一時停止します。

最初は違いのない区別のように見えるかもしれませんが、正直なところ、本当に違いがあります。違いは次のとおりです。スレッドの実行を一時停止および再開できる必要があるため、スレッドの実行がスケジュールされていない場合(たとえば、何らかのリソースが必要な場合)現在利用できません)、OSは実行をスケジュールできるようになるまで一時停止する必要があります。

そのために、OSは通常、スレッドごとにメモリブロックを確保して、マシンの現在の状態を保存します。スレッドを一時停止する必要がある場合、マシンの現在の状態がその領域に保存されます。スレッドを再開する必要がある場合、マシンの状態はその領域から復元されます。

デバッガがスレッドを一時停止する必要がある場合、OSは他の理由でスレッドをまったく同じ方法で一時停止します。次に、一時停止中のスレッドの状態を読み取るために、デバッガーはスレッドの保存状態を調べます。状態を変更すると、デバッガーは保存された状態に書き込み、スレッドが再開されたときに有効になります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.