調試內核模塊的方法有很多。最常用的,可能也是上手難度最低的就是使用prinfk打印出相關的調試信息,但是總給人的感覺不夠geeek,所以這里描述一種能夠使用gdb+qemu來調試內核的方法。
啟動虛擬機
/data/bin/qemu-system-x86_64 -m 6144 -M accel=kvm -cpu host -smp 4 -nographic \
-kernel /root/code/linux-4.18.2/arch/x86/boot/bzImage \
-device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x6,drive=drive-virtio-disk1,id=virtio-disk0,disable-modern=off,disable-legacy=on \
-drive format=raw,if=none,id=drive-virtio-disk1,cache=directsync,file=/data/rootfs.img,aio=native \
-netdev tap,id=tap0,ifname=virbr0-nic,vhost=no,script=no \
-device virtio-net-pci,netdev=tap0 \
-append "root=/dev/vda rw console=ttyS0 nokaslr" -enable-kvm -S -gdb tcp::8889
當進入到虛擬機之后,啟動相關的網卡,可以方便的向虛擬機中拷貝相關需要的文件,方便調試。
內核模塊實例
使用以下鏈接 中內核模塊,作為調試示例。
如果調試的目標虛擬機是Ubuntu16.04,使用如下分支:
git clone -b build-for-ubuntu16046 https://github.com/caisan/simplefs
如果是centos7 作為調試的目標虛擬機主機,使用如下分支:
git clone -b build-for-centos7 https://github.com/caisan/simplefs
為了能在Guest中編譯simplefs文件系統,需要在Guest中編譯下Linux-kernel 4.18.2,但是不是完全編譯,只需要編譯所需要的kernel headers,module依賴。
進入到Guest中:
cd linux-4.18.2
make menuconfig
make modules - j4
make modules_install -j4
上述編譯結束后,到Guest 的路徑下:/lib/modules/4.18.2下確認下,不出意外用ls -al可以看到build和source都鏈接到/root/linux-4.18.2,如下:

然后再進入到simplefs, 執行編譯此simplefs模塊:
make
隨后加載該simplefs.ko模塊。注意如果是在centos7上加載此模塊,需要先加載jbd2,即就是:modprobe jbd2
調試的虛擬機我選的Ubuntu 16.04.6,內核版本是
如下:
insmod ./simplefs.ko
cat /sys/module/simplefs/sections/.text
0xffffffffc098f000
cat /sys/module/simplefs/sections/.data
0xffffffffc0992000
cat /sys/module/simplefs/sections/.bss
0xffffffffc0992580
以上通過.text, .data, .bss定位到了模塊的加載地址,可以使用這三個信息開始我們的調試。
在Host上調試內核。
以上將基於QEMU+kvm中的Guest安裝好了,現在在Host上進行調試工作。這里說在Host上其實不太准確,調試的目標是Guest kernel上的模塊,Host上執行相當於是GDB遠程調試,whatever,意會這個意思就可以了。但是請務必將Host上調試的kernel代碼和Guest上的版本保持一致。
以我為例,我Host上kernel代碼路徑是在/root/code/linux-4.18.2
因此可以在~/.gdbinit 中添加如下內容:
add-auto-load-safe-path /root/code/linux-4.18.2/scripts/gdb/vmlinux-gdb.py
target remote:8889
(這里要強調的是,Host上的kernel同樣是經過編譯過后的)
進入到已經編譯好的kernel源碼目錄:
gdb ./vmlinux
此時進入到了gdb中,由於我們調試的simplefs.ko模塊,因此還要在gdb中加載這個模塊,注意:這里的加載和使用insmod加載有區別,兩者都要做。
將Guest中網絡設置好之后,可以將在Guest中編譯好的simplefs.ko模塊拷貝出來,下面.text``.data``.bss相關的地址和在Guest中保持一致。
(gdb) add-symbol-file ./simplefs.ko 0xffffffffc098f000 -s .data 0xffffffffc0992000 -s .bss 0xffffffffc0992580
加載好之后就可以調試了。
觸發調試。
這里以調試mount的操作為例,在Guest中執行常規的掛載mount 操作,如下:
dd bs=4096 count=100 if=/dev/zero of=image
./mkfs-simplefs image
mount -o loop -t simplefs image /root/simplefs/mount/
或者采用以下方式設置掛載:
fallocate -l 1G disk.img
losetup -f /root/disk.img
取消掛載:
losetup -D
然后在Host的gdb中設置斷點:
(gdb) b simplefs_fill_super
(gdb) c
等待觸發到breakpoint。調試命令和gdb使用相同。
