ソースレベルのデバッガーに取り組んでいます。elf形式で利用可能なデバッグ情報。「ステップオーバー」をどのように実装できますか?問題は「Point1」にありますが、とにかく次のソース行を待つことができます(.debug_lineテーブルから読み取ります)。
ありがとう
if (a == 1)
x = 1; //Point1
else if (a == 2)
x = 1;
z = 1;
質問を完全に理解しているかどうかはわかりませんが、GDB がそのstep
コマンドをどのように実装しているかはわかります。
制御が特定のコンパイル単位に入ると、GDB はその CU のデバッグ情報を読み取ります。特に、.debug_line セクションの CU の部分を読み取り、命令アドレスをソース コード位置にマップするテーブルを作成します。
がstep
開始されると、GDB は現在の PC のソースの場所を検索します。次に、ソースの場所が変更されるまで、新しい PC のソースの場所を毎回検索しながら、マシン命令に従って処理を進めます。ソースの場所が変わると、step
は完了です。
また、各ステップの後にフレーム ID (スタック フレームのベース アドレスと関数の開始アドレス) を計算し、それが変更されたかどうかを確認します。もしそうなら、それは再帰呼び出しにステップインしたか、再帰呼び出しから戻ったことを意味し、step
完了です。
フレーム ID とソースの場所を確認する必要がある理由を確認するには、次の関数の呼び出しをステップ実行することを検討してください。
int fact(n) { if (n > 0) { return n * fact(n-1); } else return 1; }
この関数は完全に同じソース行で定義されているため、ソース行が変更されるまで命令ごとにステップ実行すると、停止することなくすべての再帰呼び出しを実行できます。ただし、ファクトへの新しい呼び出しを入力すると、スタック フレームのベース アドレスが変更されているため、停止する必要があることが示されます。これにより、次の動作が得られます。
fact (n=10) at recurse.c:4
(gdb) step
fact (n=9) at recurse.c:4
(gdb) step
fact (n=8) at recurse.c:4
GDB のnext
コマンドは、この一般的な動作と、関数呼び出しを認識して完了に戻すための適切なロジックを組み合わせています。以前と同様に、フレーム ID を使用して、呼び出しが元のフレームに本当に戻ったときを判断する必要があります。そして他の合併症があります。
関数のインライン化されたインスタンスをどのように扱うかについて少し考える価値があります (これは DWARF で説明されています)。しかし、それはこの質問には少し多すぎます。
実験を思いとどまらせるわけではありませんが、もし私がデバッガー プロジェクトを始めたのであれば、オープン ソースであるApple の開発中のデバッガーlldbを見てみたいと思います。