その気になれば、 このマニュアルを使ってGDBのすべてを学習することももちろん可能ですが、 GDBを使い始めるには、 いくつかのコマンドを知っていれば十分です。 本章では、そのようなコマンドについて説明します。
GDBの出力情報との区別が容易につくように、 このサンプル・セッションでは、 ユーザの入力を input のように太字で表わします。
汎用的なマクロ・プロセッサであるGNU m4
には、
かつて、
まだ正式なバージョンがリリースされる以前に、
次のような不具合がありました。
引用を表わす文字列をデフォルトとは異なるものに変更すると、
あるマクロ定義の内部に入れ子状態になっている他のマクロ定義を取り出すために使われるコマンドが、
正しく動作しなくなることがある、
という不具合です。
以下の短いm4
セッションでは、
0000
に展開されるマクロfoo
を定義しています。
さらに、
m4
の組み込みコマンドdefn
を使って、
マクロbar
に同一の定義を与えています。
ところが、
引用の開始文字列を<QUOTE>
に、
引用の終了文字列を<UNQUOTE>
にそれぞれ変更すると、
全く同一の手順で新しい同義語baz
を定義しようとしても、
うまくいかないのです。
$ cd gnu/m4 $ ./m4 define(foo,0000) foo 0000 define(bar,defn(`foo')) bar 0000 changequote(<QUOTE>,<UNQUOTE>) define(baz,defn(<QUOTE>foo<UNQUOTE>)) baz C-d m4: End of input: 0: fatal error: EOF in string
ここでGDBを使って、 何が起こっているのか調べてみましょう。
$ gdb m4 GDB is free software and you are welcome to distribute copies of it under certain conditions; type "show copying" to see the conditions. There is absolutely no warranty for GDB; type "show warranty" for details. GDB 5.0, Copyright 1999 Free Software Foundation, Inc... (gdb)
GDBは、 必要なときに他のシンボルを見つけるのに最低限必要となるシンボル情報しか読み込みません。 その結果、 最初のプロンプトが表示されるまでの時間が極めて短いのです。 ここで、 出力情報がこのマニュアルの紙幅に収まるようにするために、 GDBに対して表示幅を通常よりも狭くするよう指示を出してみましょう。
(gdb) set width 70
m4
の組み込みコマンドであるchangequote
がどのように動作するのかを調べてみる必要があります。
ソースを見ると、
関連するサブルーチンがm4_changequote
であることが分かります。
そこで、
GDBのbreak
コマンドでブレイクポイントを設定してみます。
(gdb) break m4_changequote Breakpoint 1 at 0x62f4: file builtin.c, line 879.
run
コマンドを使って、
GDBの管理下でm4
を走らせます。
m4_changequote
サブルーチンに到達するまでは、
プログラムは通常どおりの動作をします。
(gdb) run Starting program: /work/Editorial/gdb/gnu/m4/m4 define(foo,0000) foo 0000
ブレイクポイントでプログラムを停止させるためにchangequote
を実行すると、
GDBはm4
の実行を停止し、
停止した箇所のコンテキスト情報を表示します。
changequote(<QUOTE>,<UNQUOTE>) Breakpoint 1, m4_changequote (argc=3, argv=0x33c70) at builtin.c:879 879 if (bad_argc(TOKEN_DATA_TEXT(argv[0]),argc,1,3))
次にn
(next
)コマンドを実行すると、
現在停止している関数の中で1行だけ処理が実行されます。
(gdb) n 882 set_quotes((argc >= 2) ? TOKEN_DATA_TEXT(argv[1])\ : nil,
set_quotes
というのは、
いわくありげなサブルーチンです。
next
コマンドの代わりにs
(step
)コマンドを使うことで、
このサブルーチンの中に入ることができます。
step
コマンドは、
それがどのサブルーチンの中にあるかということにかかわりなく、
次の1行に移動します。
この場合、
次の1行はset_quotes
の中ですから、
そこへ移動することになります。
(gdb) s set_quotes (lq=0x34c78 "<QUOTE>", rq=0x34c88 "<UNQUOTE>") at input.c:530 530 if (lquote != def_lquote)
m4
がその中で現在停止しているサブルーチン
(および、そのサブルーチンへの引数)
が表示されています。
これをスタック・フレーム表示と呼びます。
それは、
スタックの状態を要約した情報を表示しています。
backtrace
コマンド
(あるいは、
bt
と省略することもできます)
を使って、
現在、
スタック全体の中のどこにいるかを知ることもできます。
backtrace
コマンドは、
個々のアクティブなサブルーチンのスタック・フレームを表示します。
(gdb) bt #0 set_quotes (lq=0x34c78 "<QUOTE>", rq=0x34c88 "<UNQUOTE>") at input.c:530 #1 0x6344 in m4_changequote (argc=3, argv=0x33c70) at builtin.c:882 #2 0x8174 in expand_macro (sym=0x33320) at macro.c:242 #3 0x7a88 in expand_token (obs=0x0, t=209696, td=0xf7fffa30) at macro.c:71 #4 0x79dc in expand_input () at macro.c:40 #5 0x2930 in main (argc=0, argv=0xf7fffb20) at m4.c:195
次に、2、3行先に進んで、
何が起こっているのかを見てみましょう。
最初の2回は、
`s'コマンドを使います。
続く2回は、
xstrdup
サブルーチンの中に入ってしまうのを防ぐために、
n
コマンドを使います。
(gdb) s 0x3b5c 532 if (rquote != def_rquote) (gdb) s 0x3b80 535 lquote = (lq == nil || *lq == '\0') ? \ def_lquote : xstrdup(lq); (gdb) n 536 rquote = (rq == nil || *rq == '\0') ? def_rquote\ : xstrdup(rq); (gdb) n 538 len_lquote = strlen(rquote);
最後に表示された行は、少し妙な感じがします。
2つの変数lquote
、
rquote
を調べて、
本当にそれが、
新たに指定された引用開始文字列、
引用終了文字列であるかどうか確認することができます。
値を調べるにはp
(print
)コマンドを使用します。
(gdb) p lquote $1 = 0x35d40 "<QUOTE>" (gdb) p rquote $2 = 0x35d50 "<UNQUOTE>"
lquote
とrquote
は確かに引用開始文字列、
引用終了文字列のようです。
前後関係を調べるには、
l
(list
)コマンドを使って、
現在停止している行を中心にその前後10行を表示します。
(gdb) l 533 xfree(rquote); 534 535 lquote = (lq == nil || *lq == '\0') ? def_lquote\ : xstrdup (lq); 536 rquote = (rq == nil || *rq == '\0') ? def_rquote\ : xstrdup (rq); 537 538 len_lquote = strlen(rquote); 539 len_rquote = strlen(lquote); 540 } 541 542 void
len_lquote
とlen_rquote
に値を設定している行を実行させてから、
それらの値を調べてみましょう。
(gdb) n 539 len_rquote = strlen(lquote); (gdb) n 540 } (gdb) p len_lquote $3 = 9 (gdb) p len_rquote $4 = 7
len_lquote
とlen_rquote
が、
それぞれlquote
とrquote
の長さであるとすると、
ここに表示されている値は明らかに誤りです。
p
コマンドを使って、
正しい値を設定することができます。
p
コマンドによって任意の式の値を表示することができますが、
ここでいう「式」には、
サブルーチンの呼び出しや、
値の割り当ても含まれます。
(gdb) p len_lquote=strlen(lquote) $5 = 7 (gdb) p len_rquote=strlen(rquote) $6 = 9
新しい引用文字列をセットした状態で、
m4
の組み込みコマンドdefn
を使用しようとすると発生する問題を修正するには、
これだけで十分でしょうか?
c
(continue
)コマンドを使えば、
m4
に処理を継続させて、
実際に問題を発生させていた例を実行することができます。
(gdb) c Continuing. define(baz,defn(<QUOTE>foo<UNQUOTE>)) baz 0000
今度はうまくいきました。
新たにセットされた引用文字列は、
デフォルトの引用文字列と同じように機能しました。
問題の原因は、
プログラム内の2箇所のタイプ・ミスで、
長さの設定が正しく行われていないことにあったようです。
EOFを入力して、
m4
を終了させましょう。
C-d Program exited normally.
`Program exited normally.'というメッセージは、
GDBが出力したもので、
m4
の実行が終了したことを意味しています。
GDBの
quit
コマンドで、
GDBセッションを終了することができます。
(gdb) quit