attach
なんらかの理由で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.6gdbを起動したら,原則としてattachを含めて3つの手順を踏む.
- fileでシンボルファイルすなわちこれからattachするプロセスのシンボル情報を持っているファイルを指定する.
- directoryコマンドで読み込んだファイルのソースを検索できるように,ソースパスにソースのあるディレクトリを指定する.
- pidを指定して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に書き換えられた状態で処理を継続する.

