gdbの利用例(その2)

もう少し複雑なプログラムとして,sample/gdb/sample2.cを考え る.このプログラムは,実行するとSegmentation faultで停止してしまう.この 原因をgdbを利用して発見しよう.
   % gcc -g -o sample2 sample2.c
   % ./sample2
   a = 456, b = 123
   Segmentation fault

先程と同様,gdbを起動してrunすると,例えば以下のようになる.

   % gdb sample2
   ...
   (gdb) run
   Starting program: .../sample2
   a = 456, b = 123

   Program received signal SIGSEGV, Segmentation fault.
   0x0000000100000e89 in swap (i=0x7fff5fbff96c, j=0x0) at sample2.c:6
   6     *i = *j;
   (gdb)
このメッセージから,swap関数の6行目で停止していることがわかる. また,このときswap関数に与えられている引数が(i=0x7fff5fbff96c, j=0x0)であることもわかる.そこで,停止地点での 変数jの値を確認すると,
   (gdb) print j
   $1 = (int *) 0x0
0x0 すなわち NULLであり,このNULLポインタを*jで参 照しようとしたことが直接の原因であることがわかる.

問題は,swap関数の第二引数にj=0x0NULLが渡されていると ころにある.では,この関数呼出がどこで起こったものかを探そう.停止地点ま での関数呼出しの履歴は,backtraceコマンドで表示できる.

   (gdb) backtrace
   #0  0x0000000100000e89 in swap (i=0x7fff5fbff96c, j=0x0) at sample2.c:6
   #1  0x0000000100000f08 in f () at sample2.c:20
   #2  0x0000000100000f44 in main () at sample2.c:25
これによって,いま呼び出されているswapは,関数f ()の20行目 (swap(&a, c);)で呼出されており,さらにこのf ()は,関数 main ()の25行目(f();)で呼出されていることがわかる.

では,swapが呼び出された時点での変数の値などを調べてみよう.しかし, 停止している地点はswap関数が呼び出された後なので,このままではf中の局所変数acを調べることができない.この場合,frameまたはupコマンドで,フレーム[*]を移動することによって,swapが呼び 出された直前の状態を確認することができる.

   (gdb) frame 1     (または up)
   #1  0x0000000100000f08 in f () at sample2.c:20
   20     swap(&a, c);
frameコマンドの引数は,backtraceコマンドで一番左に表示される 番号である.今回の場合,現在呼び出されている関数を呼び出した地点に移動す る(一つ「上がる」)だけなので,upコマンドを利用しても同じである. ここで,swapの第二引数cを調べると,
   (gdb) print c
   $2 = (int *) 0x0
確かにNULLが渡されていることがわかる.

NAKAZAWA Koji
2014-09-30