kgdbを用いたカーネルデバッグ環境の構築

kgdbはLinux 2.6.26 から統合されたカーネルデバッグ機能です。使った感じとしては、gdbサーバをカーネルが提供しているような雰囲気です。カーネルモジュールを書いていて厄介なバグに出会ったので、導入してみるに至りました。以下ではその導入方法について述べます。

おおまかな手順

おおかまな手順は以下の通りです。

  1. kgdbをサポートしているカーネルを用意する。
  2. boot時オプションでkgdbを使うように指示する。
  3. ターゲットのvmlinuxをgdbクライアントにコピーする
  4. リモートからターゲットにつないでみる
kgdbをサポートしているカーネルを用意する

kernel.orgなどから2.6.26以降のカーネルを落としてきて、make oldconfigした上でmake menuconfigし、Kernel hackingの項目を開き、kgdbをオンにしてカーネルをビルドします。多くの場合、以下のようなフローになるでしょう:

$ sudo cp /boot/config-`uname -r` /usr/src/linux-2.6.28.8/.config
$ cd /usr/src/linux-2.6.28.8
$ sudo make oldconfig
$ sudo make menuconfig

[Kernel Hacking] > [Kgdb] にチェックを入れて再コンパイルしてください。

boot時オプションでkgdbを使うように指示する

kernel行の末尾に、kgdbを使うようにオプションをつけます。

kernel ... kgdboc=ttyS0,115200 kgdbwait

再起動すると、kgdbの入力待ちとなります。

リモートからターゲットにつないでみる

ターゲットのvmlinuxを読み込み、$はプロンプトです。printkにブレークポイントをしかけて動作させてみましょう。

$ gdb 
(gdb) file vmlinux
(gdb) target remote /dev/ttyS0
接続応答メッセージ
(gdb) b printk
(gdb) c

初期メッセージが読み込まれる寸前でブレークするはずです。step実行するなり何なりして遊びましょう。

後で読み込まれるシンボルへのアクセス

kgdbでは、後に読み込まれたシンボルへのアクセスができるようです。仮に、最初

(gdb) b sample_module_init

としてブレークポイントを設定すると、「そんなシンボルはないけど共有ライブラリがロードされたときにブレークするように設定するかい?」と聞いてきます。yesとすると、そのシンボルを通過したときにブレークする...はず?*1

まとめ

カーネルデバッガというと、設定がとても難しそうなイメージがありますが、意外と簡単にできることがわかったかと思います。是非皆さんも挑戦してみてください:D

困ったこと
  1. Over Ethernet Debug は今のところ未実装。
  2. gdb server 側が ttyUSB0で待ち受けしてくれない。*2

Tips

カーネルソースコードのルートディレクトリで

 make mandocs && sudo make installmandocs

とすると、man 9 (カーネルAPI)をインストールすることができます。デバイスドライバを書いたり、やカーネルハックをする際には大変有用なドキュメントなので、是非導入しておくことをオススメします。

*1:未確認

*2:ドライバが異なるので、シリアルポートと見なしていない様子。