第一章:调试环境搭建
调试环境搭建,说白了就是给你的内核开发配一套趁手的兵器。我见过太多人上来就写驱动,出了问题两眼一抹黑,连个打印都加不进去。嗯,今天我们就把这套环境彻底搞定。
1.1 Linux内核调试环境配置
先说说内核编译。你想想看,调试内核和调试普通程序完全是两码事。普通程序崩了,gdb上去就能看。内核崩了?那叫panic,系统直接挂了。
我个人习惯用Ubuntu 22.04 LTS,内核版本选5.15 LTS。为什么?因为LTS版本稳定,社区支持好,踩过的坑网上都有答案。
核心配置项:
- CONFIG_DEBUG_INFO=y — 生成调试符号
- CONFIG_GDB_SCRIPTS=y — 加载内核gdb脚本
- CONFIG_KGDB=y — 开启KGDB支持
- CONFIG_KGDB_SERIAL_CONSOLE=y — 串口KGDB
- CONFIG_FRAME_POINTER=y — 栈回溯支持
# 我的常用编译配置
make menuconfig
# Kernel hacking → Compile-time checks →
# Compile the kernel with debug info
# Kernel hacking → KGDB →
# KGDB: kernel debugger
make -j$(nproc)
make modules_install
make install
我在项目中遇到过一个问题:编译时忘了开CONFIG_DEBUG_INFO,结果内核崩溃了连个符号都看不到。那叫一个痛苦,全靠printk一行行猜。后来我写了个脚本,每次编译前自动检查这些配置项。
我的小技巧:把常用配置写进kernel/configs/debug.config,然后make defconfig debug.config一键搞定。
1.2 QEMU虚拟机搭建
QEMU是我最推荐的调试平台。为什么?因为它不会搞坏你的物理机。我曾经在真机上调试一个PCIe驱动,一个写操作把整个总线搞挂了,机器直接变砖。从那以后,我所有的新驱动都在QEMU上先跑通。
# 安装QEMU
apt install qemu-system-x86 qemu-utils
# 创建磁盘镜像
qemu-img create -f qcow2 disk.qcow2 10G
# 启动虚拟机(调试模式)
qemu-system-x86_64 \
-kernel bzImage \
-initrd initrd.img \
-append "console=ttyS0 nokaslr" \
-serial stdio \
-s -S # -s: gdb端口1234, -S: 暂停等待调试器
这里有个关键点:nokaslr参数。KASLR(内核地址空间布局随机化)会让内核每次启动地址都不一样,调试器根本没法设断点。我第一次用KGDB时就被这个坑了,断点设了根本触发不了。
注意:生产环境一定要开KASLR,这是安全机制。调试环境关掉它,调试完记得改回来。
1.3 KGDB双机调试
KGDB双机调试,说白了就是一台机器跑内核,另一台机器用gdb连上去调试。我习惯用串口连接,简单可靠。
目标机配置:
# 内核启动参数添加
kgdboc=ttyS0,115200 kgdbwait
# 进入KGDB
echo g > /proc/sysrq-trigger
调试机操作:
# 启动gdb
gdb vmlinux
# 连接目标机
(gdb) target remote /dev/ttyUSB0
# 设置断点
(gdb) b do_fork
(gdb) c
我曾经调试一个调度器bug,用KGDB在do_fork处设断点,观察进程创建流程。嗯,这个场景用printk根本做不到,因为printk本身就可能触发调度。
经验之谈:KGDB调试时,建议用两台独立的机器。虚拟机嵌套也可以,但串口模拟容易出问题。我踩过这个坑,虚拟串口丢数据导致gdb连接不稳定。
1.4 JTAG调试器入门
JTAG调试器,这是硬件调试的终极武器。它不依赖操作系统,可以直接访问CPU寄存器、内存、外设。说白了,就是硬件级别的gdb。
常用的JTAG调试器:
| 调试器型号 | 适用平台 | 价格区间 | 我的评价 |
|---|---|---|---|
| J-Link | ARM | ¥500-5000 | 稳定可靠,首选 |
| OpenOCD + FT2232 | 多种架构 | ¥50-200 | 开源方案,性价比高 |
| Lauterbach | 全平台 | ¥50000+ | 专业级,功能强大 |
OpenOCD配置示例:
# openocd.cfg
source [find interface/ftdi/ft2232.cfg]
source [find target/stm32f4x.cfg]
# 启动OpenOCD
openocd -f openocd.cfg
# 另一个终端连接gdb
arm-none-eabi-gdb vmlinux
(gdb) target remote localhost:3333
(gdb) monitor reset halt
(gdb) load vmlinux
(gdb) continue
我记得第一次用JTAG调试内核启动流程,那种感觉就像开了上帝视角。你能看到CPU从reset vector开始,一步步执行到start_kernel。每个寄存器的变化都尽收眼底。
硬件警告:JTAG连接时,一定要确认电压匹配。3.3V的调试器接到1.8V的芯片上,可能直接烧掉。我同事就干过这事,一块开发板就这么废了。
知识体系总览
下面这张图是我整理的调试环境搭建知识体系,你可以看到各个组件之间的关系:
调试环境搭建,说白了就是给自己铺路。路铺好了,后面调试起来才能得心应手。我个人建议:先从QEMU开始,熟悉了再上KGDB,最后才是JTAG。一步一个脚印,别想一口吃成胖子。
本章核心要点:
- 内核调试必须开启DEBUG_INFO和KGDB相关配置
- QEMU是最安全的调试平台,适合新手入门
- KGDB双机调试适合复杂场景,注意串口稳定性
- JTAG是终极武器,但成本高、操作复杂
- 调试环境搭建是基本功,值得花时间彻底搞定
我的建议:把调试环境配置写成脚本,一键部署。这样换机器、重装系统时,几分钟就能恢复工作环境。我自己的脚本已经迭代了十几个版本,现在换到任何机器上都能秒级进入调试状态。
可可精品资料库