ファイヤープロジェクト
スタック
2003-07-20T15:13+09:00   matsu
JavaのExceptionクラスのprintStackTrace()は重宝する.で,gdbを使用するとCでもそれができる.
ここで言うスタックとは関数の呼び出しスタックのことである.このスタックの各要素はスタックフレームと呼ばれ,関数のアドレスや引数などが格納されている.そして関数呼び出し時に作成され,関数が返るときに削除される.ということで,スタックとスタックフレームの情報からデバッグに便利な情報が取得できる.ではサンプル.
ではサンプルを使用してスタックフレームの情報を表示してみる.まず起動して9行目にbreakポイントを設定してrunしてstepし,関数hogeに入る.
$ gdb a.out 
(gdb) break 9
Breakpoint 1 at 0x80483f6: file stack.c, line 9.
(gdb) run
Starting program: /home/hoge/programing/c/learn-gdb/stack/a.out 

Breakpoint 1, main () at stack.c:9
9         hoge(1);
(gdb) s
hoge (i=1) at stack.c:15
15        fuga(i);
この時点で関数hogeの先頭にいる.ここでフレームの詳細情報を表示する.
(gdb) info frame
Stack level 0, frame at 0xbffff67c:
 eip = 0x804841a in hoge (stack.c:15); saved eip 0x8048400
 called by frame at 0xbffff69c
 source language c.
 Arglist at 0xbffff67c, args: i=1
 Locals at 0xbffff67c, Previous frame's sp is 0x0
 Saved registers:
  ebp at 0xbffff67c, eip at 0xbffff680
次に引数を表示してみる.
(gdb) info args
i = 1
そしてローカル変数を表示してみる.
(gdb) info locals
No locals.
あとcatch(このソースはCだからありあないか)を表示してみる.
(gdb) info catch
No catches.
そして終了.
(gdb) c
Continuing.

Program exited normally.
サンプルでは関数hogeとfugaで同じ名前の変数iがある.関数hogeでiの値は1である.
$ gdb a.out 
(gdb) break 9
Breakpoint 1 at 0x80483f6: file stack.c, line 9.
(gdb) run
Starting program: /home/hoge/programing/c/learn-gdb/stack/a.out 

Breakpoint 1, main () at stack.c:9
9         hoge(1);
(gdb) s
hoge (i=1) at stack.c:15
15        fuga(i);
(gdb) print i
$1 = 1
関数fugaの冒頭でiの値は0である.
(gdb) s
fuga (val=1) at stack.c:21
21        int i = 0;
(gdb) s
22        for(;val > 0; val--){
(gdb) print i
$2 = 0
ここで,関数hogeのiの値を見るには,スタックフレームを変更する必要がある.現在のフレームは,
(gdb) frame
#0  fuga (val=1) at stack.c:22
22        for(;val > 0; val--){
である.関数hogeにスタックフレームを変更するには,
(gdb) frame 1
#1  0x08048426 in hoge (i=1) at stack.c:15
15        fuga(i);
とする.frameは引数がなければ現在のスタックフレームを表示する.引数に整数をいれると該当するスタックフレームを選択する.スタックフレームの番号は現在の番号を0としてその呼び出し元にいくほど1ずつ増える.これはbacktraceで確認できる.
(gdb) backtrace 
#0  fuga (val=1) at stack.c:22
#1  0x08048426 in hoge (i=1) at stack.c:15
#2  0x08048400 in main () at stack.c:9
一番左の#つきの番号がスタックフレームの番号である.backtraceはプログラムが停止したのがどの関数でどうやって呼び出されたのかを追跡するのに重宝する.backtraceも引数nを取る.正の整数だと#0〜#n-1まで,負の整数だと#max+n+1〜#maxのスタックフレームを表示する.
(gdb) backtrace 2
#0  fuga (val=1) at stack.c:21
#1  0x08048426 in hoge (i=1) at stack.c:15
(More stack frames follow...)
(gdb) backtrace -2
#1  0x08048426 in hoge (i=1) at stack.c:15
#2  0x08048400 in main () at stack.c:9
frameの引数にスタックフレームの番号を指定すると,該当するフレームを選択できる.フレーム選択にはさらにupとdownがある.upは現在選択中のフレームから引数分外側(呼び出し側)のフレームを選択する.
$ gdb a.out 
(gdb) break fuga
Breakpoint 1 at 0x804843a: file stack.c, line 21.
(gdb) run
Starting program: /home/hoge/programing/c/learn-gdb/stack/a.out 

Breakpoint 1, fuga (val=1) at stack.c:21
21        int i = 0;
(gdb) up 1
#1  0x08048426 in hoge (i=1) at stack.c:15
15        fuga(i);
そしてdownはupの逆である.
(gdb) down 1
#0  fuga (val=1) at stack.c:21
21        int i = 0;
matsu(C)
Since 2002
Mail to matsu