6. スタックの調査

 あなたのプログラムが停止した場合、あなたが最初に知りたいことは、 プログラムがどこで止まっており、そしてそこで何が得られたのかと いうことでしょう。

 あなたのプログラムが関数をコールする時、プログラムがどのようにコール されたのかという情報は、スタックフレームと呼ばれるデータの ブロックに保存されます。フレームはまた、コール時の引数と、コール された関数のローカル変数の内容を含んでいます。全てのスタック フレームはコールスタックと呼ばれるメモリ領域に配置されます。

 あなたのプログラムが停止した時、GDB のスタック調査用のコマンドを 使うことによって、あなたはこれらの全ての情報を見ることができます。

 ある特定のスタックフレームが GDB によって選択された場合、多くの GDB の コマンドは選択されたフレームを無条件に参照します。特に、プログラム 内の変数値を GDB に問い合わせた場合、その値は選択されたフレーム上の ものです。GDB には、あなたの興味あるフレームがどれであるのかを選択する ための特別なコマンドがあります。

 プログラムが停止した時、GDB はカレントで実行されているフレームを 自動的に選択します。フレームは `frame' コマンドによって簡単に指定 することができます(“6.4 フレーム上の情報”をご覧下さい)。


6.1 スタックフレーム

 コールスタックは、スタックフレーム群と呼ばれる隣接した断片、又は short のフレームという; コールされた一つの関数に関連するデータを 持つフレームに分けられます。フレームには関数に与えられた引数、関数の ローカル変数、そして関数が実行される先のアドレスに関する情報が含まれ ます。

 あなたのプログラムがスタートした時、スタックは関数 main に関する たった一つのフレームしかありません。これは初期のフレーム、 又は一番外のフレームと 呼ばれます。関数がコールされる度に、新しいフレームが生成されます。 関数がリターンする度に、その関数が作り出したフレームは削除されます。 関数がリカーシブな場合、同一関数に対するフレームが多数生成されます。 関数のフレームにおいて処理の実行が実際に行われるのは、最深部の フレームと呼ばれるものです。これは、存在する全てのスタックフレームの 中で一番最近に生成されたものです。

 あなたのプログラムの中で、スタックフレームはアドレスによって識別 されます。スタックフレームは自分自身のアドレスも持った多くのバイト列を 含んでおり; 様々な種類のコンピュータにおいて、フレームのアドレスを持ったバイト列の 一つを選ぶという選択上の決まりがあります。通常、このアドレスは、 フレーム内で処理が実行している時、フレームポインタ・レジスタと 呼ばれるレジスタに保持されています。

 GDB は、存在する全てのスタックフレームに、コールされた最深部の フレームをゼロとしてスタートした番号を、上に向かって順次割り当てて います。これらの番号はあなたのプログラムの中に実際に存在するわけでは ありません; これは、GDB のコマンドに対してスタックフレームを指示する方法として 与えられたものです。

 多くの GDB のコマンドは、一つのスタックフレームを無条件に参照します。 GDB は、選択されたスタックフレームと呼ばれるスタックフレームを記録 しており; あなたは任意のフレームをワンセットの GDB コマンドを使って選択することが でき、そこで、他のコマンドは新しいフレームを処理するようになります。 あなたのプログラムが停止した場合、GDB は最深部のフレームを自動的に 選択します。

 ある関数はスタック上にフレームを確保しないで動作するようにコンパイル されているかもしれません。このようなケースは、非常に多用される ライブラリ関数のスタック生成時間を省略するような場合、時々おこります。 GDB は、このような関数起動の振るまいに対する便宜を制限します; もし、最深部の関数がスタックフレームなしで起動されたら、GDB は0への 仮想スタックフレームを与え、関数コールのチェインが正しくトレース できるようにします。最深部の関数がフレームを持たない場合、 スタック上の結果は未定義となります。


6.2 バックトレース

 バックトレースは、どのようにしてプログラムがここに至ったのかという 概略です。これは、カレントで実行している (フレームゼロの) フレームから 開始して、次にそれのコール元 (フレーム1)、そして更に続く スタックといったように、多くのフレームを1行に1フレームずつ表示します。
backtrace
bt
スタック全体のバックトレースを表示します: スタック上の全てのフレームを、1行に1フレームずつ表示します。

あなたは、通常 Control-C に設定されているシステム割り込み文字を 入力することによって、いつでもバックトレースを停止させることができます。

backtrace n
bt n
上と似ていますが、最深部から n フレーム表示します。

backtrace -n
bt -n
上と似ていますが、一番外から n フレーム表示します。
 `where'`info stack' が、`backtrace' に 別名定義 (alias) されています。

 バックトレースが表示する各々の行には、フレーム番号、関数名、そして プログラムカウンタ値が表示されます。

 もし、ソースファイルと共に関数のシンボルテーブル・データがフルに 読み込まれたような状況にあれば、バックトレースはソースファイル名と 行番号、そして関数の引数を表示します。(プログラムカウンタ値は、行番号を 持つコードの先頭の場合、省略されます。)

 もし、ソースファイルのシンボルデータがフルに読み込まれた状態でない 場合は、スキャンのみ実行され、この拡張情報は省略符号 (...) に置き換え られます。あなたはまた、フレームを選択することで、フレームに関する ソースファイル上のシンボルデータを強制的に読み込ませることができます (“6.3 フレームの選択”を参照して下さい)。

 ここにバックトレースの例を示します。これは、`bt 3' というコマンドに よって生成されたもので、最深部から3つのフレームを表示しています。

#0  rtx_equal_p (x=(rtx) 0x8e58c, y=(rtx) 0x1086c4) (/gp/rms/cc/rtlanal.c line 337)
#1  0x246b0 in expand_call (...) (...)
#2  0x21cfc in expand_expr (...) (...)
(More stack frames follow...)
expand_callexpand_expr という関数は、シンボルの詳細に 関するファイルがまだ読み込まれていないものです。全ての詳細は、 rtx_equal_p という関数上に表れており、それは `rtlanal.c' と いうファイルの中に含まれています。この関数の引数である xy は、その値が表示されています。


6.3 フレームの選択

 スタックを調査するための多くのコマンドや、スタックフレーム上で プログラムが利用するその他のデータは、瞬間的に選択されているものです。 最後に、ここに、正に今選択されているフレーム上の手短な記述を表示する ような; スタックフレームを選択するためのコマンドを示します。
frame n
フレーム番号 n を選択します。フレームゼロは最深部 (カレントで 実行中) のフレームであり、フレーム1は最深部から一つ上、といったように 呼ばれることを思い起こして下さい。もっとも大きな番号がふられている フレームは main 関数のフレームです。

frame addr
addr で示されるフレームを選択します。これは、スタックフレームの チェインがバグにより破壊され、GDB が全てのフレームに番号を割り当てられ なくなった時などに、主に役に立ちます。加えて、これはプログラムが複数の スタックを持ち、それらを切り替えて使用している場合などにも有効です。

up n
直前に選択されていたフレームの n フレーム上にあるフレームを 選択します。n は正の数であり、高位のフレーム番号である一番外の フレームに向かって、フレーム番号を進めます。n は、デフォルトで 1です。

down n
直前に選択されていたフレームの n フレーム下にあるフレームを 選択します。n は正の数であり、低位のフレーム番号である最深部の フレームに向かって、フレーム番号を減らします。n は、デフォルトで 1です。
 これらのコマンドは、全て、選択されたフレームに関するある情報を表示して 終了します: フレーム番号、関数名、引数、ソースファイルとフレーム内で実行されている 行番号、そしてそのソースライン上のテキストです。例えば:
#3  main (argc=3, argv=??, env=??) at main.c, line 67
67        read_input_file (argv[i]);
 この表示のあと、引数なしの `list' コマンドは、このフレーム上で実行 されている処理を中心とした10行の内容を表示します。“7.1 ソース上の行の表示”を参照して下さい。


6.4 フレーム上の情報

 選択されているスタックフレームに対して、その他にもいくつかのコマンドが 存在します。
frame
このコマンドは、選択しているスタックフレームの概要を表示します。 このコマンドの省略形は `f' です。引数を指定した場合、このコマンドは スタックフレームを選択するために使われ; 引数なしだとフレームの変更は行いませんが、同様の情報を表示します。

info frame
このコマンドは、フレームのアドレス、(現在のフレームからコールされている) 次に入るフレームのアドレス、(現在のフレームのコール元である) 次に出ていく フレーム、フレームの引数のアドレス、フレーム上に保存されている プログラムカウンタ (コール元フレームの実行アドレス)、フレーム上に 保存されているレジスタ値といった内容を含む、選択されているスタック フレームの詳細を表示します。詳細情報は、何かまずいことが起こって、 スタックフォーマットが通常のやり方では適応できなくなった場合に有用です。

info frame addr
addr で示されるフレームの詳細を、そのフレームを選択することなしに 表示します。選択されているフレームは、このコマンドでは変更されません。

info args
選択されているフレームの引数を、それぞれ別の行の上に表示します。

info locals
選択されているフレーム上のローカル変数を、それぞれ別の行の上に表示します。 これらは全て、現在処理を実行しているフレームの一般に内側にあるという、 全てのプログラムブロックにおいて、static や automatic に宣言されている 変数です。


目次に戻る