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

stack limit显示的大小为kstack内核选项指定的大小 。Stack 是栈开头部分的值 。
[867.148907] 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/0x28栈回溯信息,可以从中看出函数调用关系
[867.148972] Code: 95ca7426 d2800000 528102e1 72a32ec1 (b9000001)[867.148975] ---[ end trace 1983a52768236533 ]---Segmentation faultcode是错误发生时PC指向的地址处的开头20字节的代码,括号里的是出错的具体指令 。
如何根据OOPS找出bug确定出错位置在内核函数还是驱动System.map文件记录了所有符号的运行地址,这里的符号可以理解成函数名和变量 。
System.map一般在内核编译完成后,根目录下生成 。
0000000000000000 A __rela_size0000000000000000 A _kernel_flags_le_hi320000000000000000 A _kernel_offset_le_hi320000000000000000 A _kernel_size_le_hi32000000000000000a A _kernel_flags_le_lo320000000000000200 A PECOFF_FILE_ALIGNMENT0000000000080000 A _kernel_offset_le_lo32000000000159e638 A __rela_offset0000000001800000 A _kernel_size_le_lo32ffffff8008080000 t _headffffff8008080000 T _textffffff8008080800 T __exception_text_startffffff8008080800 T _stextffffff8008080800 T do_undefinstrffffff8008080a18 T do_sysinstrffffff8008080ab4 T do_mem_abortffffff8008080b60 T do_sp_pc_abortffffff8008080c34 T do_debug_exceptio.............ffffff8009879a48 b __key.30413ffffff8009879a48 b __key.30416ffffff8009879a48 b __key.48814ffffff8009879a48 b __key.48818ffffff8009879a48 b __key.48819ffffff8009879a48 b __key.48820ffffff8009879a48 b __key.48821ffffff800987a000 B idmap_pg_dirffffff800987d000 B swapper_pg_dirffffff800987f000 B tramp_pg_dirffffff8009880000 B _endSystem.map中内核函数的范围是:ffffff8008080000 ~ ffffff8009880000 。而PC出错的位置是ffffff8000ef0024
所以,可以判定不是内核函数出错引起的,而是某个驱动模块 。

如果把oops_module.ko直接编译进ko中,就是内核引起的错误了 。PC出错时的地址也会刚好在System.map中 。
反汇编驱动文件而OOPS信息也告诉我们,错误是出在了init_oopsdemo
[17981.657899] PC is at init_oopsdemo+0x24/0x38 [oops_module][17981.658385] LR is at init_oopsdemo+0x18/0x38 [oops_module]那如果OOPS没有打印出出错驱动的名字呢?
【如何解读Linux Kernel OOPS信息】我们可以使用 cat /proc/kallsyms > kallsyms.txt命令,在kallsyms.txt中找出与PC值接近的符号 。kallsyms.txt内容如下 。
ffffff8008080800 T do_undefinstrffffff8008080800 T _stextffffff8008080800 T __exception_text_startffffff8008080a18 T do_sysinstrffffff8008080ab4 T do_mem_abortffffff8008080b60 T do_sp_pc_abortffffff8008080c34 T do_debug_exception.........ffffff80094cfc0c T sparse_mem_map_populateffffff80094cfc64 T _einittext0000000000000000 a oops_module.c[oops_module]ffffff8000ef0000 t $x[oops_module]ffffff8000ef0000 t init_oopsdemo[oops_module]ffffff8000ef0030 t $d[oops_module]ffffff8000ef0038 t $x[oops_module]ffffff8000ef0038 t cleanup_oopsdemo[oops_module]ffffff8000ef0058 t $d[oops_module]ffffff800bee40c8 ? __UNIQUE_ID_license2 [oops_module]ffffff800bee40d4 ? __UNIQUE_ID_author1[oops_module]ffffff800bee40e3 ? __UNIQUE_ID_license0 [oops_module]ffffff800befb368 n $d[oops_module]0000000000000000 a oops_module.mod.c[oops_module]ffffff8000ef2000 d $d[oops_module]ffffff800bee40f8 ? $d[oops_module]ffffff800bee40f8 ? __module_depends[oops_module]ffffff800bee4101 ? __UNIQUE_ID_vermagic0[oops_module]ffffff8000ef2000 d __this_module[oops_module]ffffff8000ef0038 t cleanup_module[oops_module]ffffff8000ef0000 t init_module[oops_module]ffffff800818d0ac u printk[oops_module]ffffff800808e770 u _mcount[oops_module]

经验总结扩展阅读