栈回溯就是发生Hardfault异常时硬件会自动保存栈帧,
栈回溯的步骤:
(1)第一步
根据那个sp地址,在内存中可以找到 PC
在.dis中搜索这个地址,如果找到了,那就找到了出错的位置。
(2)第二步
如果这个PC在dis中找不到,说明被破坏了;还有一种虽然能找到,但是是凑巧的,pc被破坏了,但是变成了另一个语句的地址,其实这种莫名的跳转已经能说明pc被破坏的问题了。
PC用不了,那就用LR,被调用的函数一开始会把LR入栈。
所以找到这个LR就知道是谁调用了。
这个LR的值要减1,然后在.dis中搜索
出错后的栈指向栈帧,栈帧后面是函数的栈,从这里面可以知道是谁调用了它。
理清调用关系,从出错的位置从后往前推,
调用者下面的栈一定是当前正在调用还未返回的被调用函数的栈
ARM 异常处理流程
异常处理的两个原则:
发生异常瞬间、处理完异常后,所有寄存器的值保存不变
Cortex M3/M4 的异常处理函数可以是 C 函数,C 函数能保证 R4-R11 不被改变,其它的 R0-R3、R12、LR、PC、xPSR 这8个寄存器由硬件自动保存。
流程:
发生异常
硬件自动保存寄存器:R0-R3、R12、LR、PC、xPSR,这些称为栈帧
调用异常处理函数
硬件恢复寄存器

如果使用了FPU:
硬件恢复寄存器是怎么触发的呢?
异常处理函数执行完后,会跳转到LR的地址执行,在硬件保存栈帧的时候,硬件修改了LR的值为一个特殊的值,当跳转的时候便会触发硬件恢复。此时这个PC值是还没有执行的语句,程序便自然继续执行。
异常演示
代码被打断有两种情况:
硬件错误:跳转到 Hardfault 异常处理函数,此时 PC 指向为出错的语句。
硬件中断:
当程序进入Hardfault 异常处理函数,就是靠PC来定位出错的语句。
错误
异常
对于一般的错误,Keil中能看到调用关系的
但是如果看不到调用关系