デバッグの友。これなしでデバッグを行うことは困難だ。
(printfデバッグという手もあるが、printfを埋め込んで再コンパイルするのは面倒なものだ。)
gdbの詳しい説明はマニュアルにに譲るが、以下は使っていて便利なコマンド一覧。
なお、gdbは mule / emacs から M-x gdb として利用すると、ソースファイルを自動で開いてくれたり、ブレークポイントのあるソース行位置まで自動ジャンプしてくれたりするので便利。
gdbは、最初に ~/.gdbinit という設定ファイルを読み込むので、良く使うコマンドは define 〜 end でマクロにしておくと便利かも。
- gdb [filename] [corefile]
- filenameという実行ファイルと、corefileというコアファイルをもとに、デバッガを起動する。
- -d [directory]
- ソースファイルが置いてあるディレクトリを指定する。
コンパイルしたときと異なる場所にソースをおいてある環境でgdbを使う場合に便利なオプション。
- gdb内部コマンド
よく使うと思われるgdbの内部コマンドを以下に示す。
{ ... } で囲んであるのは mule から gdb を使った場合のショートカットキー。
- run [args]
- デバッガ内部でのプログラム実行開始。
argsにはコマンドライン引数を指定できる。
- b [filename:][funcname] - breakpoint - {C-x SPACE}
- ブレークポイントの設定。
引数として、関数名や、ソースファイル名:行数という指定が可能。
- c [n] - continue
- ブレークポイントで止めた後、実行を再開するコマンド。
引数として数字を指定すると、n回連続してcontinueする。
- p [var] - print
- 変数の内容を表示する。
p/x var などとすると、変数 var の内容を16進数で表示する。
- n [n] - next - {M-n}
- 次の行まで実行する。
引数として数字を指定すると、n回nextを行う。
step との違いは、関数コールをあっさり素通りすること。
- s [n] - step - {M-s}
- 次の行まで実行する。
引数として数字を指定すると、n回stepを行う。
next との違いは、関数コールの内部まで追跡して1行実行を行うこと。
- u [line] - until
- 〜行まで実行して止って欲しい場合に使う。
for とか while なんかのループの終了行を指定することが多い。
- finish - finish - {C-c C-f}
- 現在選択中のフレームを最後まで実行する。
今見ている関数内部はもうステップ実行しなくてもいいや、ってな場合に使う。
- i s - info stack
- bt - backtrace
- スタック情報表示。
up , down でスタックを上ったり下ったりできるぞ。
- i func [funcname] - info function
- 関数名などのシンボルを表示する。
引数に関数名の一部を指定することもできる。
関数名でブレークポイントを仕掛けようとしたのは良いか、肝心の関数名を忘れてしまった場合などに重宝する。
- core-file [filename]
- coreファイルを読み込む。
ゲロの分析をすると、何が原因でゲロったか判明するかも。
core-file と info stack(スタック情報表示) , up, down はセットで使うことが多い。
- up - {M-u}
- スタックフレームを一つ上がる。
core dumpの原因は呼び出し元の不正な引数が原因だったときとかに便利。
呼び出し元をどんどんたどれるぞ。
- down - {M-d}
- スタックフレームを一つ下がる。
upの逆。
- attach [pid] - attach
- すでに動作中のプロセスのプロセスIDを指定すると、横からデバッガの制御化におくことができ、デバッグできるようになるという激しいコマンド。
デバッガを使うと画面が乱れてしまい、わけがわからなくなるアプリケーション(エディタなど)のデバッグに威力を発揮する、らしい。
余談:どうして Netscape Communicator のバイナリにはシンボル情報が入っていないんだ〜。
- mule との混合使用
ほとんどの場合、gdbを単独で使うことはないだろう。
muleと組み合わせて使用し、muleをデバッガの環境(ソースビューアなど)として使用することになる。
毎回 mule の中から M-x gdb として、デバッグするファイル名をタイプするのも面倒なので、私の場合は以下のような関数を ~/.bashrc 内部に定義している。
#
# debugger fork with mule (for bash)
#
gdbfork () {
tmpfile=`echo gdb.$$.el`
opts=""
diropts=""
# get command line options
for i in $*
do
case $1 in
-d)
shift
diropts=$1
;;
*)
opts="$opts $1"
;;
esac
shift
done
echo "(gdb \"gdb $opts\")" > $tmpfile
if [ x"$diropts"x != x""x ] ; then
echo "(split-window-vertically)" >> $tmpfile
echo "(dired \"$diropts\")" >> $tmpfile
echo "(other-window 1)" >> $tmpfile
fi
mule -l $tmpfile
rm $tmpfile
この関数の使用方法は gdbfork [filename] [corefile] -d [dired-dir] とする。
これで、新しく起動したmuleの内部でgdbが起動している状態になる。
- 動作中のプロセスに強制的にcoreを吐かせて終了させる
kill -11 [pid] または kill -SIGSEGV [pid] すれば、実行中のプロセスに強制的にcoreを吐かせることができる。
そのあと、上に示したgdbforkなんかが使えるだろう。
- 動作中のプロセスを停止させずにcoreを吐かせる
gcore -s [pid] とすると、動作中のプロセスを一時停止してcoreを作成させ、その後に実行再開させることができる。
動作中の様子のスナップショットをとりたい場合などに便利かも知れない。