使用虚拟机进行基于qemu和gdb的Linux内核调试
使用虚拟机进行基于qemu和gdb的Linux内核调试
虚拟机配置
至少分8个核心(不然编译速度很慢,亲测)
磁盘大小分50G(编译后的内核大小有20多个G!)
打开SSH
虚拟机中安装的是ubuntu22.04版本,默认没有安装和启用SSH服务
更新软件源
1 | sudo apt update && sudo apt upgrade -y |
安装SSH(OpenSSH)
1 | sudo apt install openssh-server -y |
启动SSH服务
1 | sudo systemctl enable --now ssh |
检查是否启动成功
1 | sudo systemctl status ssh |
内核编译
准备工作
1 | # 安装相关依赖 |
然后会在此文件夹下生成 ./config文件
进入该文件,并做以下2处修改
1 | vim ./.config |
安装dwarves软件包(编译报错得出结论)
1 | sudo apt-get install dwarves |
BTF报错解决
如果仅仅只进行了上边的配置,会报如下错误(我个人是这样)
1 | KSYMS .tmp_vmlinux.kallsyms1.S |
查阅资料后,有三种解决方案:https://devkernel.io/posts/pahole-error/
我使用的是第二种方法,对pahole软件包进行降级 :
查看pahole的版本,是1.25
1 | pahole --version |
查看pahole的所有可用安装版本
1 | sudo apt-cache policy pahole |
截图如下
我们发现只有两个版本,因此只能降级为 1.22-8
1 | sudo apt install pahole=1.22-8 |
编译
1 | make -j8 #8个线程并行编译, |
然后可能会弹出一个选择(1,2,3),直接选择1即可。等待一段时间,30分钟左右
是否成功
编译完成后,目录下会生成以下,那么就编译成功了
./vmLinux
./arch/x86/boot/bzImage
其中vmLinux为GDB所需的调试Map文件,bzImage为大内核文件
安装Qemu
qemu是一款完全软件模拟(Binary translation)的虚拟化软件,在虚拟化的实现中性能相对较差。但利用它在测试环境中gdb调试Linux内核代码,是熟悉Linux内核代码的一个好方法。
1 | #安装qemu |
安装编译busybox
安装busybox的目的是:借助BusyBox构建极简initramfs,提供基本的用户态可执行程序。
1 | wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2 # 去官网找最新版 |
在编译busybox之前,我们需要对其进行设置,执行make menuconfig
,如下
这里一定要选择静态编译,编译好的可执行文件busybox
不依赖动态链接库,可以独立运行,方便构建initramfs。
1 | make -j 8 |
构建initramfs根文件系统
1 | # 在busybox压缩包的下载目录下,创建的该文件夹,该文件夹下有 |
添加如下代码
1 |
|
1 | chmod a+x init 修改文件权限 |
打包initramfs
1 | find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../initramfs.cpio.gz |
启动Qemu调试内核
上述完成之后,就可以启动Qemu来调试内核了,启动代码如下(是一个指令)
1 | qemu-system-x86_64 -kernel ./arch/x86/boot/bzImage -initrd ../initramfs.cpio.gz -append "nokaslr console=ttyS0" -s -S -nographic |
qemu-system-x86_64
:指定是x86,64位;-kernel ./arch/x86/boot/bzImage
:指定启用的内核镜像;-initrd ../initramfs.cpio.gz
:指定启动的内存文件系统-append "nokaslr console=ttyS0"
:附加参数,其中nokaslr
参数必须添加进来,防止内核起始地址随机化,这样会导致 gdb 断点不能命中;-s
:监听在 gdb 1234 端口;-S
:表示启动后就挂起,等待 gdb 连接;-nographic
:不启动图形界面
开启另一个命令行窗口,输入gdb,即可开启调试
1 | (gdb) target remote localhost:1234 #连接qemu监听的端口 |