ファイヤープロジェクト
attach
2003-11-29T21:00+09:00   matsu
なんらかの理由でgdbからいきなり起動できないプログラムや,今運用環境で動いているプログラムをデバッグしたい場合などには,動いているプロセスにattachしてデバッグすることができる.
attachは以下のような場合に重宝するのではないだろうか.
  • 起動手順が複雑で,起動用のスクリプトなどを使用しないと(現実的に)起動できないプロセス.
  • 運用中のプロセスのコアを取りたい.
  • 運用中のバグが出たが該当プロセスだけど止めることができない.
では以下のサンプルプログラムを起動し,実際にattachしてみる.
説明のために,ソースとバイナリを以下のディレクトリ構成で配置する.
/home/HOGE/attach/a.out
/home/HOGE/attach/src/attach-sample.c
そして
/home/HOGE/attach
でa.outを起動し,
/home/HOGE/
からデバッガを起動する.
ではやってみる.まずプロセスを起動する.
cd /home/HOGE/
./a.out 3
すると3秒おきにsleepする秒数が出力される.次にpsなどでa.outのpidを調べておいて,別コンソールでgdbを起動してattachしてみる.
> gdb
(gdb) file attach/a.out 
Reading symbols from attach/a.out...done.
(gdb) directory attach/src/
Source directories searched: /home/HOGE/attach/src:$cdir:$cwd
(gdb) attach 2707
Attaching to program: /home/HOGE/attach/a.out, process 2707
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
0x400bede1 in nanosleep () from /lib/libc.so.6
gdbを起動したら,原則としてattachを含めて3つの手順を踏む.
  1. fileでシンボルファイルすなわちこれからattachするプロセスのシンボル情報を持っているファイルを指定する.
  2. directoryコマンドで読み込んだファイルのソースを検索できるように,ソースパスにソースのあるディレクトリを指定する.
  3. pidを指定してattachする.
以上でattachが成功するはずである.
当然ながら,attachしたタイミングによってプロセスの状態は異なる.attachすると,そのプロセスはattachされた状態で停止している.まず現状を把握するためにbt(backtrace)でもやっとく.
(gdb) bt
#0  0x400bede1 in nanosleep () from /lib/libc.so.6
#1  0x400bed78 in sleep () from /lib/libc.so.6
#2  0x080484e4 in main (argc=2, argv=0xbffff6c4) at src/attach-sample.c:21
今回は(たまたま)libcのnanosleepのところにいるようだ.で,libcのソースはないし,libcは今回のデバッグ対象ではないので,デバッグ対象のattach-sample.cまで出たい.break&jumpでもよいが,今回はf(finish)を使用してみた.
(gdb) finish 
Run till exit from #0  0x400bede1 in nanosleep () from /lib/libc.so.6
0x400bed78 in sleep () from /lib/libc.so.6
(gdb) finish 
Run till exit from #0  0x400bed78 in sleep () from /lib/libc.so.6
0x080484e4 in main (argc=2, argv=0xbffff6c4) at src/attach-sample.c:21
21            sleep(sleepSecond);
これでデバッグ対象のソースまで上がれた.あとはステップ実行するなりjumpするなり存分にデバッグできる.例として変数sleepSecondを1にしてみる.
(gdb) set variable sleepSecond = 1
(gdb) n
22          }
(gdb) n
20            printf("sleep %ds\n", sleepSecond);
(gdb) n
21            sleep(sleepSecond);
(gdb) n
22          }
(gdb) 
20            printf("sleep %ds\n", sleepSecond);
(gdb) 
21            sleep(sleepSecond);
(gdb) 
22          }
a.outを実行したコンソールでは,
...
sleep 3s
sleep 3s
sleep 3s
sleep 3s
sleep 1s
sleep 1s
となっている.最後にattachしたらdetachする.
(gdb) detach 
Detaching from program: /home/HOGE/attach/a.out, process 2707
当然ながらプロセスはsleepSecondを1に書き換えられた状態で処理を継続する.
matsu(C)
Since 2002
Mail to matsu