文章目录
- 一、前置条件:编译开启调试符号(-g)
-
- [1.1 核心编译配置](#1.1 核心编译配置)
- [1.2 编译产物要求](#1.2 编译产物要求)
- [二、崩溃现场:提取 Oops 关键信息](#二、崩溃现场:提取 Oops 关键信息)
-
- [示例 Oops 日志](#示例 Oops 日志)
- 关键信息提取
- [三、核心工具 1:addr2line 地址转源码行](#三、核心工具 1:addr2line 地址转源码行)
-
- [3.1 命令格式](#3.1 命令格式)
- [3.2 实操示例](#3.2 实操示例)
- [3.3 输出结果](#3.3 输出结果)
- [四、兜底工具 2:objdump 反汇编验证](#四、兜底工具 2:objdump 反汇编验证)
-
- [4.1 反汇编命令](#4.1 反汇编命令)
- [4.2 查找崩溃位置](#4.2 查找崩溃位置)
- 五、完整标准化流程(总结)
- 六、常用命令速查表
- 七、注意事项
一、前置条件:编译开启调试符号(-g)
1.1 核心编译配置
编译内核或内核模块时,必须添加 GCC 调试参数,生成符号表和行号信息:
makefile
# Makefile 中添加编译参数
CFLAGS += -g # 生成调试信息(必备)
CFLAGS += -O0 # 关闭编译器优化(推荐,避免行号错位)
1.2 编译产物要求
必须保留带调试符号的文件:
- 内核:vmlinux(不可压缩的内核镜像,非bzImage)
- 驱动模块:xxx.ko(未 strip 的原始模块)
二、崩溃现场:提取 Oops 关键信息
系统触发 Oops 后,从 dmesg / 串口日志中获取崩溃地址,核心关注 RIP 字段:
示例 Oops 日志
log
RIP: 0010:test_func+0x28/0x80 [my_drv]
关键信息提取
| 字段 | 含义 |
|---|---|
| test_func | 崩溃函数名 |
| 0x28 | 函数内偏移量(核心) |
| 0x80 | 函数总大小 |
| my_drv | 崩溃所在模块 |
三、核心工具 1:addr2line 地址转源码行
addr2line 是最快捷的定位工具,直接将偏移量转换为源码文件 + 行号。
3.1 命令格式
bash
# 内核崩溃:使用 vmlinux
addr2line -e vmlinux [偏移地址]
# 模块崩溃:使用 xxx.ko
addr2line -e 模块名.ko [偏移地址]
3.2 实操示例
bash
# 定位 my_drv.ko 中 相对 test_func(可以看objdump或者编译出的map文件)假如为 0xfffffe80 偏移 0x28 的代码
addr2line -e my_drv.ko 0xfffffe80 + 0x28
3.3 输出结果
plaintext
/home/test/drv/my_drv.c:125
✅ 直接定位:my_drv.c 文件 第 125 行 为崩溃代码。
四、兜底工具 2:objdump 反汇编验证
当 addr2line 定位不准时,通过 objdump 反汇编,结合汇编 + 源码交叉验证。
4.1 反汇编命令
bash
# 反汇编(带源码混合显示),输出到文件
objdump -dS my_drv.ko > drv_dump.txt
-d:反汇编代码段-S:混合显示源码(依赖-g调试符号)
4.2 查找崩溃位置
- 打开 drv_dump.txt
- 搜索崩溃函数名(test_func)
- 找到偏移 0x28 对应的汇编 / 源码行
- 直接锁定崩溃逻辑
五、完整标准化流程(总结)
- 编译:内核 / 模块添加 -g -O0,保留调试符号;
- 抓日志:获取 Oops 日志,提取 函数+偏移量;
- 快速定位:使用 addr2line 直接映射源码行;
- 深度验证:使用 objdump 反汇编,确认汇编与源码对应关系;
- 修复问题:根据定位的代码行分析空指针、内存越界等崩溃根因。
六、常用命令速查表
| 操作场景 | 命令示例 |
|---|---|
| 模块地址转行号 | addr2line -e test.ko 0x28 |
| 内核地址转行号 | addr2line -e vmlinux 0xffffffff86123456 |
| 模块反汇编(带源码) | objdump -dS test.ko > dump.log |
| 查看 Oops 日志 | `dmesg -T |
七、注意事项
- 必须使用未 strip 的 vmlinux/.ko 文件,strip 会删除调试符号;
- 编译优化(-O1/-O2)会导致行号错乱,调试时建议用 -O0;
- 偏移量直接使用 Oops 日志中的数值,无需额外计算