作为内核开发工程师,使用 qemu + gdb 调试 Linux 内核是开发流程中的“瑞士军刀”,其核心价值在于将复杂内核调试转化为可编程、可复现、低风险的高效操作,可以帮助开发人员调试和分析内核的行为。下面将详细介绍如何设置和使用 QEMU 和 GDB 来调试 Linux 内核。
1、环境准备
Ubuntu 18.04.6虚拟机
aarch64-poky-linux-gcc (GCC) 9.2.0
aarch64-poky-linux-gdb --version
GNU gdb (GDB) 8.3.1
2、安装 QEMU
apt install qemu qemu-utils qemu-kvm virt-manager libvirt-daemon-system libvirt-clients bridge-utils
3、内核源码与编译
(1)使用RK3568 SDK的内核源,内核版本:
Linux rk3568 4.19.206
(2)打开内核调试配置
内核编译时需要启用调试符号 (.config 文件CONFIG_DEBUG_INFO=y)。
(3)编译
然后再编译内核,会生成bzImage、vmlinux、dtb文件,在启动qumu时会用到。
dtb:设备树二进制文件,路径:kernel/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-linux.dtb
vmlinux: 一个包含调试符号的未压缩内核映像,GDB 调试时会用到它,路径:kernel/vmlinux
Image: 编译后的镜像 Image, 路径: kernel/arch/arm64/boot/Image
4、启动QEMU调试内核
(1)确保准备好以下文件
内核dtb
内核Image
内核vmliunx
rootfs.img:内核启动时加载的文件系统,自行编译使用。
(2)启动QEMU
qemu-system-aarch64 -machine virt -cpu cortex-a53 -m 1024 -nographic -kernel Image -dtb rk3568-evb1-ddr4-v10-linux.dtb -append “console=ttyS0 root=/dev/ram0” -initrd rootfs.img -s -S
参数说明:
-machine virt: 选择虚拟平台。
-cpu cortex-a53: 使用ARM Cortex-A53 CPU(RK3568基于ARMv8-A架构,可以选择合适的CPU类型)。
-m 1024: 分配1GB内存。
-nographic: 禁用图形界面,通过控制台输出。
-kernel: 指定编译好的内核镜像(zImage)。
-dtb: 指定设备树文件(rk3568.dtb)。
-append: 指定内核启动参数。
-initrd: 使用内存盘文件。
QEMU 的 -s 和 -S 参数用于设置 GDB 远程调试的端口和暂停启动。
5、使用gdb调试内核
在另一个终端中启动 GDB,加载 vmlinux 文件(未压缩的内核映像),以便使用调试符号。
aarch64-poky-linux-gdb vmlinux
在 GDB 中,使用 target remote 命令连接到 QEMU 提供的 GDB 服务器:
(gdb) target remote :1234
此时,GDB 已经连接到 QEMU,并可以控制虚拟机的执行。可以在内核的特定位置设置断点,并开始调试。例如,可以设置断点在 start_kernel 函数:
(gdb) b start_kernel
然后使用 continue 命令继续运行内核:
(gdb) c
当内核运行到 start_kernel 时,GDB 会暂停并命中断点,接下来你可以逐步执行代码 (step 或 next 命令),查看变量的值等。
至此,达成了gdb调试内核的目的,可以模拟问题环境使用gdb调试内核,也可以使用这种方法gdb跟踪内核,方便阅读内核源码。