一个计算机系统和一个人类社会其实是差不多的,系统在运行中碰到的各种bug相当于人类社会中的各种案件:user space发生的bug危害性一般,可能就相当于一般的民事案件;kernel层面发生bug引起系统死机复位,属于性质特别恶劣后果特别严重的刑事案件。
既然bug相当于案件,那么我们定位bug的过程和破案是差不多的。一般过程如下:
1. 首先我们要保留案发现场。
只要bug发生的时候cpu还能执行,大部分的软件bug最后都会落入到cpu的陷阱之中。arm准备了3大陷阱来捕获最后的案发现场:undefine instruction、prefetch abort、data abort。不管程序前面发生了什么错误,最后的出错都会掉到这3大陷阱中去。类似人类社会中最后看到了刑事案件,大家会拨打110报警。
内核态的代码,只要掉入到了这3大陷阱之中,最后的结果都会触发oops然后panic()复位重启系统。在oops信息中,会打出bug的pc指针、cpu r0-r15寄存器和堆栈信息等最后的案发现场信息。
1.1 oops信息详解:
这里使用“echo “1 2” > /proc/aed/generate-oops”在mtk平台上生成一个kernel NULL pointer类型的oops,来阐释oops信息。
从上图的解析,通过oops的信息我们可以得到几个重要数据:最后出错的PC指针、函数调用关系、r0-r15寄存器的值、r0-r15指向内存的值、一些重要标志。
当然因为一些软件错误(踩堆栈)、硬件错误(内存跳变),我们最后得到的oops信息其中一项或者几项是已经出错没有了参考价值的,我们需要利用信息之间的相互关系来排插出更多的线索。
1.2 从oops信息反查源代码:
我们从oops信息中得到最后的pc值和符号信息,最终的目的还是需要和源代码联系起来。有以下方法:
(1)、addr2line:
arm-linux-androideabi-addr2line -e vmlinux addr,会打印出addr对应的源代码行号。
上图通过addr2line工具,找到最后的异常PC指针0xc04e6ffc对应源代码ade-debug.c文件的252行。
(2)、gdb: