转载时请注明出处和作者联系方式:
http://blog.youkuaiyun.com/mimepp
ARM系统中, 当crash发生时的back trace调试输出
作者:余涛(yut616_at_sohu.com)
关键字:一般保护错
back trace
在ARM target board上, 如果发生异常,如内存访问越界等情况,有时会非常难debug到底是哪里出错,近来看了一下back trace回溯的功能及实现,在这里做个笔记。
首先,back trace要涉及到一堆寄存器, 不过不用担心, 实际上没你想象的那么难。
在linux kernel的代码中可以看到关于ARM寄存器的定义,在这里列一下:
linux / include / asm - arm / proc - armv / ptrace.h
linux / include / asm - arm / proc - armv / ptrace.h























这里比较重要的几个寄存器是fp,lr,sp,继续往后讨论。
我们可以先想象一个情景,某个调用过程
A(…)
{
…;
B(…);
printf("aaa ");
{
…;
B(…);
printf("aaa ");
}
在A调B的时候,大体的过程会是A在执行,执行到B,进入B执行,B执行完后,在A中的B下面的部分继续执行。
这样的话,在转到B去执行的时候,要准备好一些东西,来保证B完成时还回到A里来继续往下执行。
怎么来保证上面的这个问题呢,那就是要用到lr寄存器来存A处的信息,这个是link register链接寄存器的缩写,它就好比一个链条一样,把一堆调用给串起来。
所以上面的过程就会是,要执行到B时,把B的地址放入pc中,这样下面就要执行B了。Pc是指令计数器,放在其中的地址就将被执行。这个时候还要保存刚才我们提到的A的信息,把需要返回的值放在lr中。
在ARM的过程调用中,有个结构叫回溯结构,还有两个概念叫帧和栈,它们的关系是:
回溯结构
|-----------|------------------------------| 帧
栈
… 帧
… 帧
回溯结构在帧的高端,通过这个回溯结构,就可以把一个一个的帧连接成栈。
帧指针fp,frame pointer就是指向把栈给串起来的一个一个回溯结构所组成的列表中的最后一个结构。这样就可以通过这个fp来追溯函数的调用顺序,在系统崩溃时就可以得到最后调用的函数都是哪些。








从上面的内容,我们只要循环打印上面lr中的值就可以得到我们想要的一系列的地址了。












上面的current->mm->start_code是当前进程的数据段基地址,再减4,就能得到返回处前面的地址。打印出来的内容也就是调用函数的地址。
如:
call address:
0x2849cc
call address:
0x3b8b70
call address:
0x2c270
call address:
0x2c5ec
call address:
0x2b298
call address:
0x283934
call address:
0x3c41a8








你可以用objdump得到你的执行文件的sym文件,如:
arm-elf-objdump -SD test.gdb > /tmp/test.gdb.sym
然后就可以拿这个循环打印出来的地址,来搜索出错的位置了。
上面的代码只是一个参考,具体还要看你的系统实际的情况。
另外还看到一个start_thread,列一下做个记载。















