ユーザ・プログラムが停止したとき、 まず最初に、 どこで停止したのか、 そして、 どのようにしてそこに到達したのかを知る必要があるでしょう。
ユーザ・プログラムが関数呼び出しを行うたびに、 その呼び出しに関する情報が生成されます。 その情報には、 ユーザ・プログラム内においてその呼び出しが発生した場所、 関数呼び出しの引数、 呼び出された関数内部のローカル変数などが含まれます。 その情報は、 スタック・フレームと呼ばれるデータ・ブロックに保存されます。 スタック・フレームは、 呼び出しスタックと呼ばれるメモリ域に割り当てられます。
ユーザ・プログラムが停止すると、 スタックを検査するGDBコマンドを使用して、 この情報をすべて見ることができます。
GDBは1つのスタック・フレームを選択していて、 多くのGDBコマンドはこの選択されたフレームを暗黙のうちに参照します。 特に、 GDBに対してユーザ・プログラム内部の変数の値を問い合わせると、 GDBは選択されたフレームの内部においてその値を探そうとします。 関心のあるフレームを選択するための特別なGDBコマンドが提供されています。 フレームの選択 を参照してください。
ユーザ・プログラムが停止すると、
GDBはその時点において実行中のフレームを自動的に選択し、
frame
コマンド
(フレームに関する情報参照)
のように、
そのフレームに関する情報を簡潔に表示します。
呼び出しスタックは、 スタック・フレーム、 または短縮してフレームと呼ばれる、 連続した小部分に分割されます。 個々のフレームは、 ある関数に対する1回の呼び出しに関連するデータです。 フレームには、 関数への引数、 関数のローカル変数、 関数の実行アドレスなどの情報が含まれます。
ユーザ・プログラムが起動されたとき、
スタックにはmain
関数のフレームが1つ存在するだけです。
これは、
初期フレームまたは「最上位のフレーム」と呼ばれます。
関数が呼び出されるたびに、
新たにフレームが作成されます。
関数が復帰すると、
その関数を呼び出したときに生成されたフレームが取り除かれます。
関数が再帰的に呼び出される場合、
1つの関数に対して多くのフレームが生成されるということもありえます。
実際に実行中の関数に対応するフレームは、
「最下位のフレーム」と呼ばれます。
これは、
存在するすべてのスタック・フレームの中で、
最も新しく作成されたものです。
ユーザ・プログラムの内部においては、 スタック・フレームはアドレスによって識別されます。 スタック・フレームは多くのバイトから構成され、 それぞれがそれ自身のアドレスを持っています。 どのような種類のコンピュータにおいても、 これらのバイトのうちの1つのバイトのアドレスをもって フレームのアドレスとする慣習的な方法が提供されています。 通常、 あるフレーム内部で実行中は、 そのフレームのアドレスがフレーム・ポインタ・レジスタと呼ばれるレジスタに格納されています。
GDBは、 既存のスタック・フレームのすべてに番号を割り当てます。 最下位のフレームは0で、 それを呼び出したフレームは1となります。 以下、 最下位のフレームを起点として、 順番に値を割り当てていきます。 これらの番号はユーザ・プログラム内部には実際には存在しません。 これらの番号は、 GDBコマンドでスタック・フレームを指定することができるように、 GDBによって割り当てられたものです。
コンパイラによっては、 スタック・フレームを使用せずに実行されるように関数をコンパイルする方法を提供しているものもあります (例えば、 gccのオプション
`-fomit-frame-pointer'
を指定すると、 フレームを持たない関数が生成されます)。 これは、 フレームをセットアップする時間を節約するために、 頻繁に利用されるライブラリ関数に対してしばしば適用されます。 これらの関数の呼び出しを処理するためにGDBが提供する機能は限られています。 最下位のフレームの関数呼び出しがスタック・フレームを持たない場合、 GDBは、 あたかもそれが通常どおりに番号0のフレームを持つものとみなして、 関数呼び出しの連鎖を追跡できるようにします。 しかしながら、 最下位以外のスタック位置に存在する、 フレームを持たない関数に対しては、 GDBは特別な処置を取りません。
frame args
frame
コマンドによって、
あるスタック・フレームから別のスタック・フレームに移動し、
選択したスタック・フレームを表示させることができます。
argsは、
フレームのアドレスまたはスタック・フレーム番号です。
引数なしで実行すると、
frame
コマンドはカレントなスタック・フレームを表示します。
select-frame
select-frame
コマンドによって、
フレームを表示することなく、
あるスタック・フレームから別のスタック・フレームに移動することができます。
これは、
frame
コマンドから、
表示処理を取り除いたものです。
バックトレースとは、 ユーザ・プログラムが現在いる箇所にどのようにして到達したかを示す要約情報です。 複数のフレームが存在する場合、 1フレームの情報を1行に表示します。 現在実行中のフレーム (番号0のフレーム) を先頭に、 それを呼び出したフレーム (番号1のフレーム) を次行に、 以降、 同様にスタックをさかのぼって情報を表示します。
backtrace
bt
backtrace n
bt n
backtrace
コマンドと似ていますが、
最下位のフレームから数えてn個のフレームだけが表示されます。
backtrace -n
bt -n
backtrace
コマンドと似ていますが、
最上位のフレームから数えてn個のフレームだけが表示されます。
backtrace
の別名としては、
ほかにwhere
やinfo stack
(省略形はinfo s
)
があります。
backtrace
コマンドの出力結果の各行に、
フレーム番号と関数名が表示されます。
set print address off
コマンドを実行していなければ、
プログラム・カウンタの値も表示されます。
backtrace
コマンドの出力結果では、
関数への引数に加えて、
ソース・ファイル名や行番号も表示されます。
プログラム・カウンタが、
行番号で指定される行の最初のコードを指している場合、
その値は省略されます。
以下にbacktrace
の例を示します。
これは、
`bt 3'の出力であり、
したがって最下位のフレームから3フレームが表示されています。
#0 m4_traceon (obs=0x24eb0, argc=1, argv=0x2b8c8) at builtin.c:993 #1 0x6e38 in expand_macro (sym=0x2b600) at macro.c:242 #2 0x6840 in expand_token (obs=0x0, t=177664, td=0xf7fffb08) at macro.c:71 (More stack frames follow...)
番号0のフレームを表示する行の先頭には、
プログラム・カウンタの値がありません。
これは、
builtin.c
の993
行目の最初のコードにおいて
ユーザ・プログラムが停止したことを表わしています。
スタックやユーザ・プログラム内の他のデータを調べるためのほとんどのコマンドは、 それが実行された時点において選択されているスタック・フレーム上で動作します。 以下に、 スタック・フレームを選択するためのコマンドを列挙します。 どのコマンドも、 それによって選択されたスタック・フレームに関する簡単な説明を最後に表示します。
frame n
f n
main
のフレームです。
frame addr
f addr
frame
に指定する必要があります。
MIPS、
Alphaの両アーキテクチャでは、
スタック・ポインタ、
プログラム・カウンタの2つのアドレスが必要です。
29kアーキテクチャでは、
レジスタ・スタック・ポインタ、
プログラム・カウンタ、
メモリ・スタック・ポインタの3つのアドレスが必要です。
up n
down n
down
の省略形はdo
です。
これらのコマンドはいずれも、 最後にフレームに関する情報を2行で表示します。 1行めには、 フレーム番号、 関数名、 引数、 ソース・ファイル名、 そのフレーム内において実行停止中の行番号が表示されます。 2行めには、 実行停止中のソース行が表示されます。
以下に、 例を示します。
(gdb) up #1 0x22f0 in main (argc=1, argv=0xf7fffbf4, env=0xf7fffbfc) at env.c:10 10 read_input_file (argv[i]);
この情報が表示された後で、
list
コマンドを引数なしで実行すると、
フレーム内で実行停止中の行を中心に10行のソース行が表示されます。
ソース行の表示
を参照してください。
up-silently n
down-silently n
up
コマンド、
down
コマンドの変種です。
相違点は、
ここに挙げた2つのコマンドが、
新しいフレームに関する情報を表示することなく実行されるという点にあります。
これらは、
情報の出力が不必要で邪魔ですらある、
GDBのコマンド・スクリプトの中での使用を主に想定したものです。
既に挙げたもの以外にも、 選択されたスタック・フレームに関する情報を表示するコマンドがいくつかあります。
frame
f
f
です。
引数付きの場合、
このコマンドはスタック・フレームを選択するのに使用されます。
フレームの選択
を参照してください。
info frame
info f
info frame addr
info f addr
frame
コマンドに指定するのと同様のアドレスを
(アーキテクチャによっては複数)
指定する必要があります。
フレームの選択
を参照してください。
info args
info locals
info catch
up
コマンド、
down
コマンド、
frame
コマンドを使用して)
移動してから、
info catch
を実行します。
キャッチポイントの設定
を参照してください。