【干货】Linux编程时遇到“Oops”提示该如何排查?

ZLG致远电子
关注

第二步

分析出错函数的出错语句

那么根据第3步PC指针,得到regulator_set_current_limit的汇编代码,如下:

函数入口地址为c02f186c

在第3步PC指针指出偏移地址为“PC is at regulator_set_current_limit+0xc”。

PC = 0xc02f1878 = 0xc02f186c + 0xc,符合汇编代码地址。

第三步

找到出错函数的C语言代码

这步可以说是最困难的,因为内核代码层次多,同名函数也可能存在许多份,可能几份编译进内核(static声明的局部函数),也可能没编译进内核,如何从众多的代码中分析出具体哪段呢?

小编就使用了一些小手段,首先给每个同名函数的入口加段乱码,让编译器筛选出编译进内核的文件(因为乱码,所以编译会报错),然后给剩下的函数加打印语句,通常经过第一步之后,可选的目标就两三个,通过打印进一步确认代码即可。

以下为筛选出来的C语言代码:

看到这好像是定位了函数,但对于不熟悉汇编的人来说,C与汇编还是没有关联起来,好像进入了死胡同,但先别气馁,从上面的汇编代码中我们知道,函数名即为函数的首地址,那么调用子函数即需要让CPU知道子函数名,那么汇编如何调用子函数呢?使用bl指令,bl+子函数名。既然汇编有这么一个特性,那么我们看汇编代码。

上面582734行为“bl  c0493104

那么结果显而易见,不可能定义个变量都报错吧,所以唯一可能错误的语句就是struct regulator_dev *rdev = regulator->rdev,同理,这句的前半部也只是定义一个rdev的变量,再结合内核给出来的提示——空指针,所以错误就是regulator->rdev是一个空指针。

最终的问题就归结于,为什么regulatar->rdev为空指针。这部分的查阅代码以及推理需要更深层次地挖掘,工作量也非本文能说清的,故作者在这里就大胆地推测与上面的A->B->C模型类似。所以我们就需要在这个资源存在的时刻,调用它之前给它赋值。

这时侯,我们就需要拿出第8步函数执行的回溯关系图,既然知道这个图中最后的函数的输入参数regulator的rdev为空,那么我们就关心regulator结构体以及它的意义。从结构体的意义我们才能知道如何给它赋值。

在相关的代码文件中搜索关键字”regulator”或”regulator =”(建议搜这个,因为这种才是赋值语句)得到如下代码:

分析这个函数可知,regulator实际是pdata的一个成员,他需要data来初始化,那么接下来的事情就简单了,在回溯关系中找一个位置把data的数据塞入pdata中,刚好这段函数就是初始化的regulator的,那就直接拿去用吧。

把这段添加到probe函数内的这个位置,实现了在mxsbl_probe和mxsbl_do_probe之间赋值此变量。

这样重新编译后即可正常加载ko文件。

在上面我们运用了一些小手段去定位我们想要查看的代码,各位工程师还有什么办法去定位这样多同名的代码呢?欢迎在底部给我们留言分享。

声明: 本文由入驻OFweek维科号的作者撰写,观点仅代表作者本人,不代表OFweek立场。如有侵权或其他问题,请联系举报。
侵权投诉

下载OFweek,一手掌握高科技全行业资讯

还不是OFweek会员,马上注册
打开app,查看更多精彩资讯 >
  • 长按识别二维码
  • 进入OFweek阅读全文
长按图片进行保存