Linux kernel module debug方案总结(QEMU VM版)

前言

最近为了做Linux kernel module开发,配置Linux kernel debug环境踩了好多坑,捡回好久不用的CSDN账号总结一下

方案总结

利用log日志(仅作记录):

  1. printk
  2. dump_stack()
  3. debugfs

利用gdb调试方案:

  1. qemu+busybox方案;
    优点:有利于kernel学习,可以从start_kernel开始断点
    缺点:不利于kernel模块的debug学习,busybox构建最小系统后,依赖项都需要自己映射,过于麻烦
  2. qemu调试方案(linux kernel官方方案总结);
    优点:简单有效,是需要修改kernel配置最少最简单的方案
    缺点:有的时候会莫名其妙闪退,可能是x86平台的原因,断点好像除了gdb强行ctrl+c之外没有其他的办法可以主动打断
  3. qemu+kgdb双机模拟方案;
    优点:可以主动打断
    缺点:配置麻烦一些,lx-symbol命令的速度比qemu直接-s调试要慢很多

我在这里选择方案2和方案3,方案1就不做配置了。

准备工作

qemu安装

见: linux qemu虚拟机安装

下载kernel源码

下面的repo是ubuntu默认版本,也可以使用其它的kernel版本

# 以下步骤均可以在host端完成
git clone git://git.launchpad.net/~ubuntu-kernel/ubuntu/+source/linux/+git/$(lsb_release -cs)
# 找到当前运行的Ubuntu的精确版本号:
cat /proc/version_signature 
# 输出:Ubuntu 5.15.0-60.66-generic 5.15.78
# 切换到对应的版本
git checkout Ubuntu-5.15.0-60.66
# 复制当前kernel版本的config文件
cp -v /boot/config-$(uname -r) .config
# 修改.config文件
禁用CONFIG_RANDOMIZE_BASE
开启CONFIG_GDB_SCRIPTS
开启CONFIG_DEBUG_INFO_REDUCED
开启CONFIG_FRAME_POINTER
# 编译
apt install flex bison openssl libssl-dev libelf-dev
make -j $(nproc)
# 如果这里编译失败,清空.config文件里CONFIG_SYSTEM_TRUSTED_KEYS和CONFIG_SYSTEM_REVOCATION_KEYS值的内容为空
# CONFIG_SYSTEM_TRUSTED_KEYS=""
# CONFIG_SYSTEM_REVOCATION_KEYS=""
# 在VM里打开共享文件夹,具体步骤见上面的链接,然后执行
# 安装必须开启INSTALL_MOD_STRIP,否则文件过大会导致无法启动。后续调试可以单独编译module
make INSTALL_MOD_STRIP=1 modules_install
make -j $(nproc) install
# 单独编译module的命令
make -C . M=module在kernel里的路径 modules

方案1 - linux kernel官方方案

启动qemu

# 注意自己改路径
qemu-system-x86_64 -m 2048 -enable-kvm -cpu host \
-smp cores=16,sockets=1 \
-drive file=ubuntu-22.04.img,if=virtio \
-nic user,hostfwd=tcp::5557-:22 \
-fsdev local,security_model=passthrough,id=fsdev0,path=/kernel_code_directory \
-device virtio-9p-pci,fsdev=fsdev0,mount_tag=kernelmake \
-S -s \
-vnc :1 -monitor stdio

-s:qemu开启gdb,默认端口1234
-S:会在系统开始的时候直接断点
-fsdev和-device …两行是为了共享kernel code文件夹,如果修改kernel代码的话方便直接debug测试,不需要进行文件传输,具体见 linux qemu虚拟机安装

启动gdb

# host
cd kernel_code_directory
gdb vmlinux
target remote :1234

如果映射成功的话,会触发exception断点,continue进入系统
注意:不要打断点在start_kernel上,打start_kernel断点再continue会失败,但不影响debug kernel module

映射kernel module到gdb

ssh进入vm之后,有两种方案
a. 加载该mod,然后

	cat /sys/module/{这个modulede的名字}/sections/.text
	cat /sys/module/{这个modulede的名字}/sections/.data
	cat /sys/module/{这个modulede的名字}/sections/.bss

获取三个地址,在gdb里输入

	add-symbol-file {这个module}.ko <text_addr> -s .data <data_addr> -s .bss <bss_addr>

b. 加载该mod,然后在gdb里输入lx-symbol,让gdb自动更新所有已经加载的符号表

测试

需要注意,module是动态加载的,rmmod之后module的代码段就不在当前内存空间内了,所以断点module init的函数是无法触发的,测试可以断点module_exit,然后rmmod,查看触发情况。

方案2 - qemu+kgdb双机模拟方案

VM kernel设置

  1. 需要开启KGDB选项,可以用menuconfig,或者.config文件里搜索,5.15版本默认是开启的。
  2. 修改grub,有两种方式:
    a. 在启动选项中,选择Advanced Options,在需要debug的kernel版本上按e,进入编辑内核启动项,加入kgdbwait kgdboc=ttyS0,115200 nokaslr,按F10启动
    b. 进入系统,在/etc/default/grub中修改启动命令行,加入kgdbwait kgdboc=ttyS0,115200 nokaslr,update-grub&&update-grub2,重启

qemu启动命令

在上述基础上,删去-S -s,加上
-serial tcp::1234,server,nowait
将串口映射到tcp端口1234上

启动gdb

  1. 同方案1,如果映射成功,断点会在kgdb_breakpoint函数的arch_kgdb_breakpoint()后面,确认没问题continue进入系统,剩下的步骤都与方案1一致
  2. 断点触发方式:
    vm console输入echo g > /proc/sysrq-trigger,会将控制权交给gdb

Reference

  1. https://www.binss.me/blog/how-to-debug-linux-kernel/
  2. https://docs.kernel.org/translations/zh_CN/dev-tools/gdb-kernel-debugging.html
  3. https://www.cnblogs.com/haiyonghao/p/14440777.html
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值