没志青年
发布于 2025-10-10 / 21 阅读
0

调试技巧03 - 栈回溯

栈回溯就是发生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个寄存器由硬件自动保存。

流程:

  1. 发生异常

  2. 硬件自动保存寄存器:R0-R3、R12、LR、PC、xPSR,这些称为栈帧

  3. 调用异常处理函数

  4. 硬件恢复寄存器

如果使用了FPU:

硬件恢复寄存器是怎么触发的呢?

异常处理函数执行完后,会跳转到LR的地址执行,在硬件保存栈帧的时候,硬件修改了LR的值为一个特殊的值,当跳转的时候便会触发硬件恢复。此时这个PC值是还没有执行的语句,程序便自然继续执行。

异常演示

代码被打断有两种情况:

  • 硬件错误:跳转到 Hardfault 异常处理函数,此时 PC 指向为出错的语句。

  • 硬件中断:

当程序进入Hardfault 异常处理函数,就是靠PC来定位出错的语句。

错误

异常

对于一般的错误,Keil中能看到调用关系的

但是如果看不到调用关系