nanoを手探ってみる#2: デバッグ出力と操作画面の分離

前回はnanoのビルドが終わるところまでいきました。早速ソースコードで見つけた関数にブレイクポイントを設置して、gdbで処理を見てみます。ファイル読み込み機能に手を加えたいので、do_insertfile()という関数にブレイクポイントを張って実行します。

gdb ./nano
<略>
(gdb) b do_insertfile
Breakpoint 1 at 0x40a6f7: file files.c, line 1064.
(gdb) r

Ctrl+Rを押すとファイル読み込み機能が呼ばれて処理が止まるのですが…

f:id:meloidae:20161106121757p:plain

nanoのUI、デバッグ用のログ、gdbコマンドラインが混ざってすごいことになります。これでは出力が見づらくてデバッグがしにくいので、デバッグ出力と操作画面を分離させる方法を考えてみました。

gdb attachを使う

gdbにはattachという機能があり、この機能を使うと先に起動しておいたプログラムのプロセスに、あとからgdbの制御をかませることができます。使い方はgdbを起動してから

(gdb) attach [pid]

とするか、gdb起動時に-pオプションをつけて

gdb -p [pid]

とすればいいです。pidの値は

pgrep nano

とコマンドを打てば表示されます。attachの何が便利かというと、gdbをnanoとは別のターミナル画面で開くことができます。つまり、nanoのUIとgdbの制御画面を分離できるわけです。これだけだとまだnanoのUIとログ出力が混ざったままなので、nanoのstderr出力(デバッグのログはここから出ます)を適当なログファイルのリダイレクトします。さらにログファイルをtailすれば常にログを確認しながらデバッグができます。

まとめると、3つのターミナル画面を用意して1つめのターミナルでnanoを起動。このときstderr出力をlog.txtにリダイレクトする。

./nano 2> log.txt

2つめのターミナルでgdbをnanoにattachし、起動。(sudoがないとattachできません。)

sudo gdb -p $(pgrep nano) 

3つめのターミナルでlog.txtをtail。

tail -f log.txt

ログが見やすくなって解析が捗ります。(16.04になってますが、見本用に撮っただけなので気にしないでください。)

f:id:meloidae:20161106131315p:plain

ターミナルを複数起動するのが面倒という人にはtmuxなどのターミナルマルチプレクサもおすすめです。

#3に続きます。