如何解读Linux Kernel OOPS信息( 七 )


?oops_module aarch64-linux-gnu-addr2line -e ./oops_module.ko -p -f 0x24init_oopsdemo at /home/zhongyi/code/module/oops_module/oops_module.c:10?oops_module cat /home/zhongyi/code/module/oops_module/oops_module.c | tail -n+5 | head -n 10MODULE_AUTHOR("ZHONGYI");staticint init_oopsdemo(void){printk("oops module init! \n");*((int*)0x00) = 0x19760817;return 0;}module_init(init_oopsdemo);decodecode在linux内核里面有很多脚本工具,位于linux/scripts/,里面有一个decodecode工具可以用来转换机器码,decodecode脚本可以在没有源代码或符号表的情况下,将oops异常的log作为输入就可以解析出错误位置的汇编代码 。
oops_log.txt内容如下
call trace:[867.148911] Exception stack(0xffffffc00a4ffa70 to 0xffffffc00a4ffba0)[867.148913] fa60:ffffff8000ef0000 0000008000000000[867.148916] fa80: ffffffc00a4ffc40 ffffff8000ef0024 ffffff80097c02f8 0000000000000002[867.148918] faa0: ffffffc00a4ffac0 000000020001b57c 0000000000000000 0000000100000000[867.148921] fac0: ffffffc00a4ffb60 ffffff800810d674 ffffffc00a4ffbc0 ffffff8000ef1024[867.148924] fae0: ffffffc0cdce10c0 ffffff80095b7860 0000000000000000 ffffff8000ef2050[867.148927] fb00: 0000000000000001 ffffffc0cde6e880 0000000000000000 0000000019760817[867.148929] fb20: 0000000000000007 0000000000000007 0000000000000001 ffffffc0f7f24b38[867.148932] fb40: 0000000000000022 ffffff80096280b0 ffffff8008463c3c 0000000005f5e0ff[867.148935] fb60: ffffff80097bfa9f 00000000fffffffe 0000000000000030 000000000000000a[867.148937] fb80: 00000000000224d6 0000000000000000 ffffff800813b204 0000007fb096c8a0[867.148944] [<ffffff8000ef0024>] init_oopsdemo+0x24/0x38 [oops_module][867.148953] [<ffffff80080830f8>] do_one_initcall+0x78/0x194[867.148958] [<ffffff800818d2d0>] do_init_module+0x64/0x1c0[867.148962] [<ffffff800813ab5c>] load_module+0x199c/0x1ed0[867.148964] [<ffffff800813b2b4>] SyS_finit_module+0xb0/0xbc[867.148968] [<ffffff8008082f70>] el0_svc_naked+0x24/0x2$ ARCH=arm64 CROSS_COMPILE=/home/zhongyi/code/rk3399_linux_release_v2.5.1_20210301/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu- ./scripts/decodecode < /home/zhongyi/code/module/oops_module/oops_log.txtCode: 95ca7426 d2800000 528102e1 72a32ec1 (b9000001)All code========0:95ca7426.word0x95ca74264:d2800000.word0xd28000008:528102e1.word0x528102e1c:72a32ec1.word0x72a32ec110:*b9000001.word0xb9000001<-- trapping instructionCode starting with the faulting instruction===========================================0:b9000001.word0xb9000001执行脚本后,就可以得到出错的汇编代码 。trapping instruction指出了出错的地址 。根据oop_module.ko的反汇编可以知道出错的位置24:b9000001strw1, [x0]

注意:脚本认为该机器码是跟host结构相同的原生机器码,想要跨架构翻译要指定架构和交叉工具链 。
faddr2line内核开发者为了方便问题的排查,也经常需要根据内核栈,快速定位导致问题发生的代码位置 。所以,Linux 内核维护了一个 faddr2line 脚本,根据函数名+偏移量输出源码文件名和行号 。
在使用这个脚本之前,还需要注意两个前提条件:
  • 第一,带有调试信息的内核文件,一般名字为 vmlinux(注意,/boot 目录下面的 vmlinz 是压缩后的内核,不可以直接拿来使用) 。
  • 第二,系统中需要安装 awk、readelf、addr2line、size、nm 等命令 。
    对于第二个条件,这些命令都包含在 binutils 软件包中,只需要执行 apt 或者 dnf 命令安装即可 。
而对第一个条件中的内核调试信息,各个主要的发行版也都提供了相应的软件仓库,你可以根据文档进行安装 。比如,对于 Ubuntu 来说,你可以执行下面的命令安装调试信息:

经验总结扩展阅读