You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

内核崩溃调试中如何用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包提供):

  1. 计算出错地址相对于模块基址的偏移:从crash日志R12字段可知模块基址为fffffffc062b000,偏移为ffffffffc062b02c - ffffffffc062b000 = 0x2c
  2. 执行解析命令:
    addr2line -e ./test_module.ko -f 0x2c
    

关键注意事项

  • 编译模块的内核版本必须与生成dump文件的内核版本完全一致,否则符号会不匹配。
  • 调试符号必须在编译时生成,无法事后添加。

内容的提问来源于stack exchange,提问作者akumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 10:25:39