GDB+QEMU調試內核模塊(實踐篇)


調試內核模塊的方法有很多。最常用的,可能也是上手難度最低的就是使用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可以看到buildsource都鏈接到/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使用相同。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM