3. 编译可调试内核:获取Linux内核源码、配置内核开启kgdb支持、编译内核与设备树

本章是实战流程的基石。要使用QEMU进行kgdb远程调试,必须拥有一份开启了调试符号且配置了kgdb支持的Linux内核镜像。我们将从获取源码开始,逐步完成配置、编译,并生成QEMU启动所需的设备树文件。

3.1 获取Linux内核源码

推荐从kernel.org获取长期支持(LTS)版本,稳定性与社区支持最佳。本课程以v6.1.y系列为例。

🔍 版本选择建议:LTS版本(如6.1.x、5.15.x)拥有更长的维护周期,且QEMU与kgdb的兼容性问题较少。避免使用最新的rc候选版或EOL版本。
# 下载指定版本源码包
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.1.76.tar.xz

# 解压
tar -xf linux-6.1.76.tar.xz
cd linux-6.1.76

解压后,源码目录结构如下表所示:

目录/文件 说明
arch/ 体系结构相关代码(x86、arm64、riscv等)
kernel/ 核心内核代码(调度、进程管理、kgdb核心)
drivers/ 设备驱动
scripts/ 编译与配置脚本
Makefile 顶层构建文件
Kconfig 内核配置系统入口

3.2 配置内核:开启kgdb与调试支持

内核配置是决定调试能力的关键步骤。必须显式开启KGDB、调试符号以及串口控制台支持。

3.2.1 配置流程

  1. 生成默认配置:基于目标架构(x86_64)生成基础配置。
  2. 手动调整:使用menuconfig图形界面或直接修改.config文件。
  3. 验证关键选项:确保以下配置项已启用。
# 生成x86_64默认配置
make defconfig

# 进入图形化配置界面
make menuconfig

3.2.2 必须开启的配置项

以下配置项缺一不可,否则kgdb无法正常工作:

配置项 路径 说明
CONFIG_KGDB Kernel hacking → KGDB kgdb核心支持
CONFIG_KGDB_SERIAL_CONSOLE Kernel hacking → KGDB: KGDB serial console 通过串口进行kgdb I/O
CONFIG_DEBUG_INFO Kernel hacking → Compile-time checks → Debug information 生成DWARF调试符号(vmlinux必备)
CONFIG_DEBUG_INFO_DWARF4 Kernel hacking → DWARF version 推荐使用DWARF4格式,gdb兼容性好
CONFIG_MAGIC_SYSRQ Kernel hacking → Magic SysRq key 用于触发kgdb断点(SysRq+g)
CONFIG_SERIAL_8250_CONSOLE Device Drivers → Character devices → Serial → 8250/16550 console 串口控制台,kgdb通信依赖此驱动
💡 快速验证:配置完成后,执行 grep -E "CONFIG_KGDB|CONFIG_DEBUG_INFO|CONFIG_MAGIC_SYSRQ" .config 确认所有选项均为 =y。

3.2.3 配置关系流程图

下图展示了内核配置中kgdb相关模块的依赖关系:

kgdb 内核配置依赖关系 CONFIG_KGDB CONFIG_KGDB_SERIAL_CONSOLE CONFIG_DEBUG_INFO CONFIG_MAGIC_SYSRQ SERIAL_8250_CONSOLE CONFIG_DEBUG_INFO_DWARF4 SysRq+g 触发断点

3.3 编译内核与设备树

配置完成后,进入编译阶段。对于QEMU调试场景,我们主要关注vmlinux(未压缩的内核映像,包含完整调试符号)和设备树(用于描述硬件拓扑)。

3.3.1 编译内核

使用make命令并行编译。建议开启-j参数利用多核加速。

# 编译内核与模块(-jN 中N为CPU核心数+1)
make -j$(nproc)

# 编译完成后,关键产出物位于:
# arch/x86/boot/bzImage   —— 压缩后的内核镜像(QEMU启动用)
# vmlinux                 —— 未压缩内核(包含调试符号,gdb连接用)
⚠️ 常见错误:如果编译过程中出现 undefined reference to `kgdb_... 错误,请返回 menuconfig 检查 CONFIG_KGDB 及其子选项是否已正确开启。缺少 CONFIG_KGDB_SERIAL_CONSOLE 是导致链接失败的最常见原因。

3.3.2 编译设备树

设备树(Device Tree)用于向内核描述非可枚举的硬件信息。在x86平台上,QEMU通常使用ACPI,但为了调试与学习,我们也可以生成并加载设备树。对于ARM64或RISC-V平台,设备树是必需的。

以下以ARM64为例展示设备树编译过程(x86平台可跳过此步,直接使用QEMU默认的ACPI):

# 设置交叉编译环境(ARM64示例)
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-

# 生成设备树二进制文件(.dtb)
make defconfig
make -j$(nproc) dtbs

# 产出物位于 arch/arm64/boot/dts/ 目录下
# 例如:arch/arm64/boot/dts/qemu/virt.dtb

3.3.3 编译产物清单

编译完成后,请确认以下文件已生成:

文件 路径 用途
bzImage arch/x86/boot/bzImage QEMU -kernel 参数加载的内核镜像
vmlinux 源码根目录 GDB file 命令加载的调试符号文件
virt.dtb (ARM64) arch/arm64/boot/dts/qemu/virt.dtb QEMU -dtb 参数加载的设备树
System.map 源码根目录 内核符号表,辅助地址查找

3.4 编译流程总览

下图总结了从源码获取到产出物生成的完整编译流程:

内核编译与设备树生成流程 获取源码 配置内核 编译内核 编译设备树 验证产出物 准备QEMU启动

3.5 本章小结

  • 源码获取:选择LTS版本,解压后进入源码根目录。
  • 配置要点:CONFIG_KGDB、CONFIG_KGDB_SERIAL_CONSOLE、CONFIG_DEBUG_INFO 三项必须同时开启。
  • 编译产出:bzImage 用于QEMU启动,vmlinux 用于GDB加载调试符号。
  • 设备树:ARM64/RISC-V平台需额外编译.dtb文件;x86平台通常使用ACPI,可跳过。