内核崩溃调试中如何用crash工具获取源码行号
问题描述
我正在使用一篇教程分析内核崩溃生成的dump文件,已成功生成dump文件并可通过crash工具访问。
内核模块代码如下:
/* Code for the kernel module */ #include<linux/module.h> #include<linux/kernel.h> #include<linux/types.h> static s32 __init testmoduleinit(void) { s8 *ptr = NULL; pr_info("%s:module loaded.\n", __func__); *ptr = 100; // generate oops return 0; } static void __exit testmoduledeinit(void) { pr_info("%s:module un-loaded.\n", __func__); } module_init(testmoduleinit); module_exit(testmoduledeinit); MODULE_LICENSE("GPL");
crash日志(回溯输出)如下:
crash> bt PID: 3401 TASK: ffff9d6928b3af00 CPU: 2 COMMAND: "insmod" #0 [ffffb2bd846478c8] machine_kexec at ffffffff9246fe83 #1 [ffffb2bd84647928] __crash_kexec at ffffffff9255a152 #2 [ffffb2bd846479f8] crash_kexec at ffffffff9255aff1 #3 [ffffb2bd84647a18] oops_end at ffffffff9243633d #4 [ffffb2bd84647a40] no_context at ffffffff924803c9 #5 [ffffb2bd84647ab0] __bad_area_nosemaphore at ffffffff924807c0 #6 [ffffb2bd84647af8] bad_area_nosemaphore at ffffffff92480976 #7 [ffffb2bd84647b08] __do_page_fault at ffffffff9248133d #8 [ffffb2bd84647b70] do_page_fault at ffffffff9248162c #9 [ffffb2bd84647ba0] page_fault at ffffffff93001284 [exception RIP: _MODULE_INIT_START_gencrash+44] RIP: ffffffffc062b02c RSP: ffffb2bd84647c58 RFLAGS: 00010282 RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000 RDX: 0000000000000000 RSI: ffff9d6935c9c8c8 RDI: ffff9d6935c9c8c8 RBP: ffffb2bd84647c60 R8: 0000000000000722 R9: 0000000000000004 R10: ffff9d693219f730 R11: 0000000000000001 R12: ffffffffc062b000 R13: ffff9d693219f730 R14: ffffb2bd84647e68 R15: ffffffffc0628000 ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 #10 [ffffb2bd84647c68] do_one_initcall at ffffffff9240389a #11 [ffffb2bd84647ce0] do_init_module at ffffffff92edd493 #12 [ffffb2bd84647d08] load_module at ffffffff92556e1b #13 [ffffb2bd84647e48] __do_sys_finit_module at ffffffff9255773c #14 [ffffb2bd84647f20] __x64_sys_finit_module at ffffffff9255777a #15 [ffffb2bd84647f30] do_syscall_64 at ffffffff92405207 #16 [ffffb2bd84647f50] entry_SYSCALL_64_after_hwframe at ffffffff9300008c RIP: 00007f7f2613c539 RSP: 00007fff5ba4f6a8 RFLAGS: 00000246 RAX: ffffffffffffffda RBX: 000056442b32d7c0 RCX: 00007f7f2613c539 RDX: 0000000000000000 RSI: 0000564429214d2e RDI: 0000000000000003 RBP: 0000564429214d2e R8: 0000000000000000 R9: 00007f7f2640f000 R10: 0000000000000003 R11: 0000000000000246 R12: 0000000000000000 R13: 000056442b32d760 R14: 0000000000000000 R15: 0000000000000000 ORIG_RAX: 0000000000000139 CS: 0033 SS: 002b
bt日志显示页错误发生在地址ffffffffc062b02c,但执行以下命令后:
crash> mod -s test_module ./test_module.o crash> sym ffffffffc062b02c
无法看到触发崩溃的源码行号,请问是否有办法获取导致oops的内核模块源码行号?
解决方案
要获取内核模块触发oops的源码行号,需遵循以下步骤:
1. 确保编译模块时保留完整调试信息
编译模块必须添加-g参数生成调试符号,且不能用strip剥离符号。修改模块的Makefile,确保CFLAGS包含调试参数:
obj-m += test_module.o CFLAGS_test_module.o := -g all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
2. 正确加载模块符号到crash工具
使用.ko文件而非.o文件加载符号,因为.ko包含完整的模块元数据和调试信息:
crash> mod -s test_module ./test_module.ko
3. 定位源码行号的两种方法
方法一:使用crash内置命令
加载符号后,执行以下命令之一:
- 查看带源码行的完整回溯:
crash> bt -f - 直接解析出错地址:
crash> sym -l ffffffffc062b02c
方法二:使用addr2line工具
如果crash工具解析失败,可借助addr2line(binutils包提供):
- 计算出错地址相对于模块基址的偏移:从crash日志R12字段可知模块基址为
fffffffc062b000,偏移为ffffffffc062b02c - ffffffffc062b000 = 0x2c - 执行解析命令:
addr2line -e ./test_module.ko -f 0x2c
关键注意事项
- 编译模块的内核版本必须与生成dump文件的内核版本完全一致,否则符号会不匹配。
- 调试符号必须在编译时生成,无法事后添加。
内容的提问来源于stack exchange,提问作者akumar
相关产品推荐
相关产品推荐

