作为一个安卓驱动开发,在和工厂沟通过程中经常收到机器在开机后直接进sysdump的问题反馈。最开始碰到这种问题,自己也基本上是满脸问号。后来经过一些错误排查后逐渐有了处理经验。在这里做个简单的分享。
下面以一次实例来讲解:
第一步:了解清楚异常的详细情况并获取相关异常机器和sysdump日志
问题描述:出现一台机器在系统启动后不久就自己重启进入sysdump界面。再次开机后大概率会继续进入sysdump。
后面拿到了问题机器。
我们自己需要准备和异常机器使用固件版本对应的vmlinux,另外还要准备好crash分析工具,由于机器时基于ARM核心的,所以用的是crash_arm工具。
将sysdump文件和vmlinux还有crash_arm复制到一个文件夹中,方面后续操作:
第二步:解析sysdump日志
运行命令将sysdump信息解析出来:
1 cat sysdump.core.* > logcat
2 ./crash_arm vmlinux logcat
如果解析有异常,命令行里面会有提示。解析成功后如下图:
第三步:分析问题根本原因
到这里,我们可以看到显示这个sysdump的问题是发生了空指针异常:
PANIC: "Unable to handle kernel NULL pointer dereference at virtual address 00000104"
请大家记住最后的这个00000104,这对于最后确定问题点非常有帮助。
那现在知道了问题的原因,但是还不知道具体的问题点在哪里。这种问题属于解决难度适中的情况。
更简单下的情况下,sysdump解析出来的问题直接会指出问题出在哪个函数。而另外一种更麻烦的情况下,这里解析出的错误可能会显示为空,如果碰到这种情况就比较棘手。
回到这个问题本身,造成空指针异常的可能原因很多,因此我们需要进一步查找原因。这是我一般先会将sysdump的log信息导出来。使用如下命令:
导出后查看这个文件的内容。
我们在文件中搜索前面提到的问题原因:
从这里我们可以看到很多寄存器的信息。其中最重要的是PC寄存器的内容,
[ 36.094223] c0 PC is at unlink_anon_vmas+0x170/0x1a0
这行日志的意思是指发生异常时,CPU正在运行unlink_anon_vmas函数中代码位置位于0x170偏移处的代码,unlink_anon_vmas的代码在内存中总长度为0x1a0。
到这里我们思路就很清晰了,通过查看unlink_anon_vmas函数的汇编代码,找到其中位于0x170偏移地址的代码内容,就找到了问题的根本原因。
这时需要用到crash_arm工具,我们通过dis反汇编命令进行解析:
得到结果如下:
看到这密密麻麻的汇编代码不要怂,上去跟他刚。
由于解析出来的汇编代码偏移地址用的十进制,所以0x170就对应上图中最后红色箭头指出的这一行代码。
这行代码的意思是将r3寄存器中的值写入到r2+4这个内存地址中。结合前面提到问题原因是空指针异常,那么这里就知道问题应该出在r2这个寄存器的内容上。
为了验证这个猜测,我们需要知道当下r2寄存器的值。这里我们需要回到前面的这个图片:
从这里我们可以看到r2寄存器的内容为00000100,然后加上4,就得到了00000104。
这个数字是不是很眼熟,没错,这就是最开始解析sysdump时出现的空指针的具体内容。
那问题分析到这里,我们已经知道了问题点,但是还不清楚为什么会导致这个问题,下面还要接着分析:
现在就要结合问题点的代码上下文来进行进一步分析了,既然是r2寄存器的内容不对,那么我们需要查看r2寄存器的值的来源,通过汇编代码可以看出:
0xc011eb94 <unlink_anon_vmas+364>: ldr r2, [r4, #8]
0xc011eb98 <unlink_anon_vmas+368>: str r3, [r2, #4]
上面红色代码的意思是从内存地址r4+8的位置获取值并写入到寄存器r2中。
这说明CPU从内存中获取到的数据有问题。
分析到这里,可以初步判断机器问题是由于DDR异常导致的,后续进一步确认需要DDR硬件交叉实验进行验证。
非常感谢大家的耐心阅读。
欢迎大家关注我的个人公众号“四点能”
公众号里我会根据基础技术制作出有趣的东西,我们一起体会技术的乐趣