2011/10/17

LinuxでLoadable Moduleをデバッグする

Linux のloadable moduleをデバッグしたときのメモ。
元ネタはO'Reillyの"Linuxデバイスドライバ"。
static linkしたモジュールはgdbでvmlinuxを読み込めばシンボル情報が読み込まれるが、loadable moduleは一手間かけないとシンボルが見えない。

ここでは uvcvideo モジュールをデバッグ対象とする。
まず、ターゲットとなるモジュールの.text, .bss, .dataのアドレスを得る。

# cat /sys/module/uvcvideo/sections/.{text,bss,data}
0xf86c6000
0xf86d4560
0xf86d3000


続いてデバッガでシンボルを追加する。カレントディレクトリはLinuxカーネルソースのディレクトリ。

(gdb) add-symbol-file drivers/media/video/uvc/uvcvideo.ko 0xf86c6000 -s .bss 0xf86d4560 -s .data 0xf86d3000


これで関数名を指定してブレークポイントを置いたり、ソースを追いながらステップ実行できるようになる。
もう少し楽にやる方法はないかと思う。

なお、.ko にデバッグ情報を残すにはモジュールのソースディレクトリにある Makefile に、

EXTRA_CFLAGS += -O0 -g


などと記述しておけば良い。

ついでにモジュールのみのビルド方法は、カーネルソースのトップディレクトリにおいて、"make M=[モジュールのディレクトリ]"。

2011/10/15

カーネルをデバッグするためのGRUB2設定

Ubuntu 11.04でカーネルデバッグをしたときの設定です。
VMWare同士でシリアルポートを接続する方法で、baudrate 115200で接続。

* デバッグ対象のOS

- /boot/grub/grub.cfg のデバッグしたいカーネルの menuentry をコピーして、新しい menuentry を追加する。
- 追加した menuentry の "linux" のパラメータに "kgdboc=ttyS0,115200 kgdbwait" を追加する。以下は一例。


menuentry 'Ubuntu, with Linux 2.6.38.8 (debug)' --class ubuntu --class gnu-linux --class gnu --class os {
    recordfail
    set gfxpayload=$linux_gfx_mode
    insmod part_msdos
    insmod ext2
    set root='(hd0,msdos1)'
    search --no-floppy --fs-uuid --set=root ba000129-5c3a-403c-9107-3d7649a4d051
    linux    /boot/vmlinuz-2.6.38.8 root=UUID=ba000129-5c3a-403c-9107-3d7649a4d051 ro kgdboc=ttyS0,115200 kgdbwait
    initrd    /boot/initrd.img-2.6.38.8
}



- 再起動時にSHIFTキーを押し続けてブートメニューを表示し、追加した menuentry に対応する項目を選ぶ。

* デバッガを起動するOS

GRUBとは関係ないが、ついでにデバッガ側の作業も記述しておく。
カーネルをビルドしたディレクトリに移動して、gdbを起動。以下のコマンドを入力。.gdbinit に記述しておいても良い。


(gdb) file ./vmlinux
(gdb) set remotebaud 115200
(gdb) target remote /dev/ttyS0



# GRUB2とはバージョン1.9以降を指すそうだ。ややこしい...。