カーネルデバッグのヒント


このテキストはFreeBSD Press No.12 特集「BSDで動かそう 後編」のNetBSD関連記事のコラムとして掲載されたものです。Webでの公開にあたり投げやりなhtml化を含め一部の表記は見直していますが、記事の内容は当時のままであり、最新のNetBSDバージョンにおける変更には追従していません。記事の内容に関わるような大きな変更は入っていませんが……。

本テキストの著作権は筒井泉が有しています。obsoleteな不正確な情報が拡散するのもあまりよろしくないので、転載は控えて下さい。


デバイスドライバ作成時に限らずカーネルのデバッグというとなにか特別な手法が必要な気がするかもしれないが、実際には単純な手法でも十分役に立つ。それらのいくつかについて紹介する。

基本は printf() とシリアルコンソール?

カーネルデバッグのツールとしては内蔵デバッガのDDBやgdbによるcrash dump解析などもあるが、もっと単純にひたすらprintf()を使って値を見たりどこまで動いているか確認するという手法でも(面倒だが)それなりに役に立つ。[脚注1]

しかし、やたらとprintf()を入れてしまうと通常のディスプレーをコンソールとしている場合には各メッセージがあっという間にスクロールの彼方に消えてしまうため、上記のようなprintfデバッグをする際にはシリアルコンソールを使うことが必須である。[脚注2]

デバッグテスト用マシン設定

デバッグの際にはたいてい何十回何百回とtry and errorを繰り返すはめになる。それを根気よく続けていくためには「ソース変更→カーネルコンパイル→カーネル起動→動作確認→動かなくてリセット」のサイクルにかかる労力を極力少なくしておかなければならない。

このためには、カーネルの変更やコンパイルを行うマシンと実際にデバイスを装着して動作確認を行うマシンは別々に用意すべきである。この状態で上記のようにシリアルコンソールを使用すれば、見るべき画面は一つで済むし手も一つのキーボードと動作確認用マシンのリセットボタンを操作するだけで済む。

また、動作確認用マシンに求められることとしてリセットからカーネル読み込み開始までの時間が短いということも挙げられる。新しいカーネルを起動する時やハングアップから復帰する時にいちいち何十秒も待たされるのではやってられない。その点ではいわゆる自作のPCはなにかと起動後の初期化に時間がかかるのでテストマシンには向いていない。

上記のような理由から筆者はPCIデバイスのドライバのデバッグの際はいつもmacppc(の互換機)を使っている。すべてのmacppcにあてはまるのかどうかはわからないが、筆者のマシンはOpenFirmwareでシリアルコンソールの設定が簡単にできるし、キーボードによるハードウェアリセットからOpenFirmwareのプロンプトが出るまでの時間も3秒以下で言うことなしである。

panicしたら

panicメッセージが出て止まってしまうと憂鬱になるかもしれないが、黙ってハングアップされるのと比べれば何倍もマシである。DDBが有効であればプロンプトに対してとりあえず "tr" と打てばスタックトレースが表示されるのでどういう経緯で落ちているのかはだいたい見当がつく。

条件によってはパニックした直後にハングアップしてDDBが使えなかったり関数のシンボルが表示されなかったりする場合もあるが、そういう場合は落ちている場所を関数名やアドレスから地道に調べる必要がある。このための手法はいくつかあるが、単純な方法としてはカーネルのコンパイルディレクトリで "nm *.o" などとしてシンボルを検索するとか "objdump --disassemble netbsd" などとしてカーネルを逆アセンブルして該当アドレスを調べるといったやり方がある。

デバイスドライバ作成というとなにやら難しいことのような気がするが、本来ハードウェアが設計時に意図されていたような操作をしてやればそのとおり動くのはある意味必然であるので、ハードウェアの仕様さえわかっていればあとは地道に検証していくだけである。[脚注3]


[脚注1] プログラムに慣れている人ならばデバッグのコードを書くのも造作ないことなのかもしれないが、筆者のような素人にとっては余計なコードを書く労力を割くよりはとにかく動かすための手法に走ってしまいがちである。もっとも、デバイスドライバは割り込み処理のようにカーネル下位層部分の操作が含まれるため、printf()以外に有効なデバッグ手段が使えない場合も多い。

[脚注2] NetBSD/i386の場合にはbootloaderによってシリアルコンソールの設定が可能である。詳細はmanの boot(8)boot_console(8) を参照。

[脚注3] 往々にしてマニュアルに嘘があったりハードウェアにバグがあったり、そもそもマニュアルすらなかったりして困るのであるが……


NetBSDのページに戻る
tsutsui@ceres.dti.ne.jp