next up previous contents
Next: ネットワークを使う Up: プログラムを書く Previous: メイクを使う

デバッガーを使う

プログラムがだんだん大きくなるとデバッグも難しくなっていきます。ソース にデバッグのための出力文を書いたりする程度でできるデバッグもありますが、 デバッガーを使うほうがずっと効率的です。UNIXの標準デバッガーはdbxです。

dbxではCのソースコードレベルのデバッグができますが、プログラムが使って いるシンボル(変数名や関数名など)をdbxに教えてあげるために、コンパイル の時に特別の手当てが必要です。それは具体的にいうとccに-gオプションを付 けるということです。これまでに出てきた例ですと、

        % cc -g -c main.c

といった風にやります。makeを使うならば、CFLAGSに-gを加えておいてもよい でしょう。

実行可能形式のファイルができるとデバッグです。起動は

        % dbx test

でtestという実行可能ファイルをデバッグします。dbxだけでデバッガーに入っ て中で

        (dbx) debug test

でもできます。ここで(dbx)はdbxの出すプロンプトです。dbxは対話型プログ ラムでデバッグのための様々な機能を持っています。helpコマンドがdbxの中 で使えます。

dbxはモジュール単位のデバッグを行ないます。モジュールは個別にコンパイ ルされた各々です。よく使う命令をあげておきます。詳しくはman dbxやdbxの helpで見てください。

        debug   あらたなデバッグセッションの開始
        quit    dbxの終了
        run     実行
        rerun   再実行
        stop    実行中断場所や変数、条件の設定
        step    一行ずつ実行。関数呼び出しでその関数にはいる。
        next    一行ずつ実行。関数呼び出しでその関数に入らない。
        trace   一行ずつ表示しながら実行する。
        display 変数などをそのつど表示させる。
        print   変数の値を表示する。
        dump    すべての局所変数を表示する。
        modules デバッグ対象のモジュールのリストを表示。
        file    現在の対象ソースファイルの切り替え/表示。
        func    現在の対象関数の切り替え/表示。
        list    ソースファイルの内容を表示。
        help    ヘルプ
        where   現在のスタックの内容を表示
        up      スタックの内容に従って親の関数へ切り替え
        down    スタックの内容にしたがって子の関数へ切り替え

ほかにも色々命令が用意されていますが、これだけ知っているだけでも十分仕 事になると思います。デバッグしたい関数をfileやfuncで選んでlistして行番 号を見てstopでブレークポイントを設定してrunします。printなどで変数の内 容を確かめながらstepやnextでじわじわと進んでバグを見つけます。具体的に 見ていきましょう。まずdbxを起動します。

        % dbx a.out
        Reading symbolic information...
        Read 521 symbols
        (dbx)

ここでまずソースを表示させましょう。

        (dbx) list main
            14    int   argc;
            15    char  **argv;
            16    {
            17          int i;
            18
            19          for( i = 0; i < argc; i++ )
            20          {
        (dbx)

list mainは関数mainを表示します。多分途中までしか表示されません。続け てlistと入力します。次の行から表示されます。

            21                  ana_arg( *argv );
            22          argv++;
            23  }
            24    }
        (dbx)

デバッグが必要な関数はana_argです。表示させてみましょう。

        (dbx) list ana_arg
            26    int   ana_arg( a )
            27    char  *a;
            28    {
            29  int     i;
            30  char    *p;
            31  printf( "Argument = %s ", *a );

まずこのプログラムを実行して見ます。mainの19行目で止めます。

        (dbx) stop at 19
        (7) stop at "/home/iwashi/src/myprog.c":19

stop atでブレークポイントを設定しました。(7)はコマンドナンバーです。こ のstopに与えられました。statusで見てみましょう。

        (dbx) status
        (7) stop at "/home/iwashi/src/myprog.c":19
        (dbx) delete 7
        (dbx) status
        (dbx) stop at 19

コマンドナンバー7をdeleteで削除しました。その結果stautsは空になりまし た。ブレークポイントは解除されたことになります。話を続けるためにもう一 度stopしておきます。次にrunで実行します。ブレークポイントにたどり着い て止りました。ここで変数の中身を見てみましょう。

        (dbx) run
        Running: a.out
        stopped in main at line 19 in file "myprog.c"
            19          for( i = 0; i < argc; i++ )
        (dbx) print argc
        argc = 1
        (dbx)

ポインターの場合print *argvなどと指定します。cの参照がそのまま使えます。 次にここから一行ずつ順に実行させます。stepです。

        (dbx) step
        stopped in main at line 21 in file "myprog.c"
            21  ana_arg( *argv );
        (dbx) step

ここでもう一度stepすると関数ana_argに入ります。nextとすると関数に入ら ず次の行に進みます。contで実行再開します。rerunで再度走り直しします。 runやrerunには引数を渡せます。この例ではargcやargvに反映します。

ある程度デバッグが進んだプログラムを走らせていると、通常はうまく走って いるのだけれどたまに例えば次のようなメッセージを出力してこけてしまうこ とがあります。

        % badprg
        Arithmetic exception (core dumped)
        %

いわゆるコアを吐くというやつです。実際にcoreというファイルが出来ている はずです。演算例外が発生しました。ゼロで割り算をしたのかも知れません。 他にSegmentation fau ltなども起こります。Bus errorと表示される場合もあ ります。とんでもないところを参照した場合に発生します。このcoreとは大変 貴重なものです。あまり嫌わないでください。死後診断(postmortem debugging)がこのcoreファイルを使って出来ます。

        % dbx badprg core
        ...
        program terminated by signal FPE (integer diveide by zero)
        (dbx) where
        zero_divide( ) at 0xef77a89c
        sub3(), line 19 in "badprg.c"
        sub2(), line 12 in "badprg.c"
        sub1(), line 8 in "badprg.c"
        main( argc = 1, argv = -268436644), line 4 in "badprg.c"
        (dbx)

coreはプログラムの死体です。どこでどのように死んだかがわかります。 whereで現在のスタックの内容が表示されます。見たところbadprg.cファイル の19行目、sub3という関数の中でゼロによる割り算が起こったようです。まず funcコマンドでsub3にフォーカスします。

        (dbx) func sub3

printでsub3の中の変数を表示させてみましょう。色々な手掛かりが得られる はずです。

スタックの中を上に移動します。sub3はsub2から呼び出されているのでsub2に フォーカスが移ります。

        (dbx) up
        Current function is sub2
            12  sub3( );
        (dbx)

同じようにdownで下に下がります。

デバッグの必要によっては16進数表現で表示したい場合があります。整数は通 常10進数として出力されてしまいます。そこで

        (dbx) print i
        `myprog`ana_arg`i = 196608
        (dbx) &i/X
        0xeffffa5c:  0x00030000
        (dbx)

このようにprint iだと大きな数が表示されてよくわからない場合も16進でか くと「あらなんだ」ということもあります。上の例ではiのアドレスを&iで指 定してその内容を/Xで表示させました。/Oで8進数、/Fで浮動少数点数が同じ ように表示できます。



next up previous contents
Next: ネットワークを使う Up: プログラムを書く Previous: メイクを使う



Kinya Hibino
Wed Apr 26 21:42:06 JST 1995