ご存知かもしれませんが、GDBを使用してコードにブレークポイントを設定し、デバッグのために実行を一時停止できます。
私の質問は、GDBがプロセスをどのように一時停止しi r
、たとえばレジスタを使用してレジスタの内容を表示できるかです。これらのレジスタは、他のOSプロセスで常に使用されていませんか?どうして上書きされないのですか?
ライブデータではなく、コンテンツのスナップショットだけですか?
ご存知かもしれませんが、GDBを使用してコードにブレークポイントを設定し、デバッグのために実行を一時停止できます。
私の質問は、GDBがプロセスをどのように一時停止しi r
、たとえばレジスタを使用してレジスタの内容を表示できるかです。これらのレジスタは、他のOSプロセスで常に使用されていませんか?どうして上書きされないのですか?
ライブデータではなく、コンテンツのスナップショットだけですか?
回答:
アーキテクチャによって多少異なりますが、重要な点はほぼ例外なく適用されます。
割り込みサービスにより、ISRを実行する前にCPUの状態(レジスタを含む)がメモリに保存され、ISRの終了時に復元されます。
割り込みサービスルーチンが、これらのレジスタが保存されているメモリ位置の内容をスワップする場合、コンテキストスイッチを実行できます。すべてのスレッドには、スレッドが実行されていないときにレジスタが保存されるメモリ領域があります。
コンテキストスイッチは、スレッドがI / O、同期、その優先順位、シグナル配信などを待機しているかどうかを考慮するスレッドスケジューラによって制御されます。多くの場合、考慮される中断カウントがあります。
デバッガーは、スレッドが実行可能でないことを保証する中断カウントをインクリメントできます。その後、スレッドの保存されたレジスタのコピーを検査(および変更)できます。
@BenVoigtによる素晴らしい情報に加えて、いくつかの追加を許可します。
ブレークポイントは、デバッグするプロセスのマシンコード値(命令または命令の一部)を、ブレークする目的の(ソース)行に対応するコード内の特定のトラップ命令で置き換えることにより、デバッガーによって設定されます。この特定のトラップ命令は、ブレークポイントとして使用するためのものです。デバッガーはこれを認識し、オペレーティングシステムも認識します。
デバッグ中のプロセス/スレッドがトラップ命令にヒットすると、@ Benが記述しているプロセスをトリガーします。これには、現在実行中のスレッドを中断するコンテキストスワップの半分(CPU状態をメモリに保存することを含む)が含まれます。このトラップはブレークポイントトラップであるため、オペレーティングシステムは、おそらく@Benが記述するメカニズムを使用して、デバッグ中のプロセスを中断したままにし、デバッガーに通知し、最終的に再開します。
デバッガーは、システムコールを使用して、デバッグ中の中断されたプロセス/スレッドの保存された状態にアクセスします。
壊れたコード行(特定のトラップ命令を含むようになった)を実行(再開)するために、デバッガーはブレークポイントトラップ命令で上書きした元のマシンコード値を復元し、別の場所に別のトラップを設定します(シングルステップの場合、またはユーザーが新しいブレークポイントを作成します)、プロセス/スレッドを実行可能としてマークします。おそらく@Benが説明するメカニズムを使用します。
実際の詳細はより複雑になる可能性があります。ヒットした長時間実行のブレークポイントを維持することは、実際のコードのブレークポイントトラップをスワップアウトして行を実行できるようにすることを意味し、その後ブレークポイントを再びスワップインすることを意味するためです...
これらのレジスタは他のOSプロセスによって常に使用されていませんか?どうして上書きされないのですか?
@Benが説明しているように、タイムスライシングを使用して複数のプロセス/スレッドでプロセッサを共有できる既存のスレッドのサスペンド/レジューム機能(マルチタスクのコンテキストスイッチング/スワッピング)を使用します。
ライブデータではなく、コンテンツのスナップショットだけですか?
両方です。ブレークポイントにヒットしたスレッドはサスペンドされているため、サスペンド時のライブデータ(CPUレジスタなど)のスナップショットであり、CPUレジスタの信頼できるマスターは、スレッドが再開された場合にプロセッサに復元する値を登録します。デバッガーのユーザーインターフェイスを使用して(デバッグ中のプロセスの)CPUレジスターを読み取りおよび/または変更すると、システムコールを使用してこのスナップショット/マスターを読み取りおよび/または変更します。
厳密に言えば、少なくともほとんどの場合、gdb自体は実行を一時停止しません。むしろ、gdbはOSに尋ね、OSは実行を一時停止します。
最初は違いのない区別のように見えるかもしれませんが、正直なところ、本当に違いがあります。違いは次のとおりです。スレッドの実行を一時停止および再開できる必要があるため、スレッドの実行がスケジュールされていない場合(たとえば、何らかのリソースが必要な場合)現在利用できません)、OSは実行をスケジュールできるようになるまで一時停止する必要があります。
そのために、OSは通常、スレッドごとにメモリブロックを確保して、マシンの現在の状態を保存します。スレッドを一時停止する必要がある場合、マシンの現在の状態がその領域に保存されます。スレッドを再開する必要がある場合、マシンの状態はその領域から復元されます。
デバッガがスレッドを一時停止する必要がある場合、OSは他の理由でスレッドをまったく同じ方法で一時停止します。次に、一時停止中のスレッドの状態を読み取るために、デバッガーはスレッドの保存状態を調べます。状態を変更すると、デバッガーは保存された状態に書き込み、スレッドが再開されたときに有効になります。