经过前面的流程,走到了die()函数,该函数主要输出便于调试的寄存器信息/堆栈信息等重要资料,我们通过log分析KE就是分析这些资料,因此要知道整个流程。die() => panic()的大致流程如下:
在学习这些流程时,建议结合代码和KE的log一起看,你就知道log里那些信息在代码哪处打印出来的了。
die()总流程
先从die()入手,看下die()总流程:
走到debug_locks_off()就有log输出了,如下:
如果这个异常是代码里调用BUG()/BUG_ON()引起,那么有额外log说明:
输出的log大致如下:
__die()流程
绝大部分的关键信息是由__die()函数输出的,流程如下:
异常类型信息
开始印出异常类型等信息,看一份kernel log有没有oops,直接搜索关键字Internal error就可以了:
输出的信息大致如下:
module信息
接下来是module信息,不过我们不建议使用module,这边也不打算介绍了。
CPU寄存器信息
然后是重要的CPU寄存器信息(32bit的代码,64bit类同):
输出的信息大致如下:
寄存器附近的内存
有助于我们分析问题的内存信息,问题很可能就出在里面。
输出的信息大致如下:
调用栈
有时问题可以直接从调用栈看出来,由此可见调用栈是多么重要。
输出的信息大致如下:
PC附近指令
可以看到PC附近的指令:
输出的信息大致如下:
分析log
到这里die()函数就完成了它的使命,将重要信息输出来了。接下来你要如何调试呢?这个就看个人的功力了,你可以:
- 通过PC指向的函数,用addr2line(后面的GNU tools有介绍)定位到哪只文件的哪一行,大致可以知道发生了什么,如果无法一下子定位,也可以通过结合printk()多次观察KE时的log排查。如果是由BUG()/BUG_ON()引起的KE,则就可以着手修复问题了。
- 查看调用栈,有些时候调用栈可以说明流程,看看代码是否有按预期跑,如果没有,可以结合printk()定位问题。
- 如果你想看函数参数或全局变量信息,那么你需要用《进阶篇: ramdump分析》的知识调试了