调用栈和fault analyzers(快速找到bug)
1.错误类型
一般来说 错误类型就是以下四种 而最常见的是:Hardfault

在 ARM Cortex-M 系列处理器(如 STM32 芯片)中,Hardfault是一种严重的系统故障异常,当处理器检测到无法被其他异常(如总线故障、用法故障)处理的错误时,会触发该异常。以下是关于 Hardfault 的关键信息:
一、触发原因
Hardfault 的触发场景非常广泛,典型原因包括:
- 内存访问错误
- 数组越界(如int arr[5]; arr[10] = 0;);
- 空指针 / 野指针解引用(如int *p = NULL; *p = 10;);
- 栈溢出(局部变量过大、函数递归过深导致栈空间耗尽)。
- 指令异常
- 执行未定义的指令(如非法汇编指令、代码段被意外改写);
- 特权级违规(如用户模式下访问特权寄存器)。
- 硬件故障
- 总线访问失败(如外设地址配置错误,访问不存在的硬件资源);
- 外设异常(如 ADC、SPI 等外设配置冲突)。
- 中断配置错误
- 中断优先级配置非法(超出0~15范围);
- 中断向量表未正确初始化(如向量地址无效)。
2. ARM Cortex-M 系列处理器寄存器


1.sp寄存器
- SP_main(主堆栈指针,MSP):是默认的堆栈指针,用于异常服务例程(如中断、系统调用)、OS 内核以及需要特权访问的代码。系统复位后默认使用该堆栈。
- SP_process(进程堆栈指针,PSP):用于线程模式下的普通应用程序代码(非异常场景)。在嵌入式操作系统中,不同任务可通过它维护独立堆栈,实现任务隔离。(在freertos下会用到)
2.LR与PC寄存器
- R14(连接寄存器,LR)
- 核心功能:主要用于保存函数调用、异常(中断、异常服务例程)发生时的返回地址。
- 当执行函数调用指令(如BL)时,LR 会自动存储调用指令的下一条指令的地址,函数执行完毕后可通过BX LR指令返回调用点。
- 在异常(如中断、Hardfault)发生时,LR 会存储异常返回时需要恢复的指令地址,保障程序在异常处理完成后能正确回到原执行流程。
- 特殊场景:在多任务操作系统中,任务切换时也会涉及 LR 的保存与恢复,以确保任务上下文的完整性。
- R15(程序计数器,PC)
- 核心功能:用于存储当前正在执行或即将执行的指令的地址,是处理器 “知道下一步该执行哪条指令” 的关键。
- 处理器会不断从 PC 指向的地址中取出指令并执行,执行完一条指令后,PC 会自动更新为下一条指令的地址(对于 ARM 指令集,通常是PC += 4;对于 Thumb 指令集,通常是PC += 2)。
- 在分支、跳转指令(如B、BL、BX)执行时,PC 会被修改为目标地址,从而改变程序的执行流程。
3.异常发生后的处理

这张图展示的是 ARM Cortex-M 系列处理器中 ** 异常返回机制(EXC_RETURN)** 的关键参数,用于定义异常处理完成后处理器的返回行为,核心含义如下:
-
什么是EXC_RETURN?
当处理器进入异常处理(如中断、HardFault 等)时,链接寄存器(LR)会被自动加载一个特殊值,这个值就是EXC_RETURN。它的作用是指示处理器在异常处理完成后,以何种模式、使用哪个堆栈返回原执行流程。
- 各数值的功能解析

-
补充说明的逻辑
- 当 “主程序在线程模式下用 MSP” 被中断时,异常服务例程的LR会被自动设为0xFFFF_FFF9(原 LR 已被压栈),确保返回后回到 “线程模式 + MSP” 的原流程。
- 当 “主程序在线程模式下用 PSP” 被中断时,异常服务例程的LR会被自动设为0xFFFF_FFFD,确保返回后回到 “线程模式 + PSP” 的原流程。
- ,MSP(主堆栈指针)在错误发生前指向的是当前活跃的主堆栈区域;当错误(如异常、Hardfault)发生时,处理器会自动将上下文寄存器(R0-R3、R12、LR、PC、xPSR 等)压入 MSP 指向的栈中,因此错误发生后,MSP 指向的是 “错误发生前的栈 + 刚压入的上下文数据” 的栈区域。
简言之,EXC_RETURN是 Cortex-M 处理器异常返回的 “控制码”,通过不同数值编码,精准控制返回后的执行模式(线程 /handler)和堆栈选择(MSP/PSP),保障系统在异常处理后能正确恢复执行流程。
4.案例分析
在有错误的时候,我们看寄存器
看lr寄存器的值与上面的错误分析,去寻找msp(主栈堆)
- 找到msp对应的地址(此时已经压栈)

从左往右依次对应寄存器 找到LR对应的值

可以通过 MSP(主堆栈指针)定位到发生错误的函数,核心依据是异常发生时处理器会自动将关键寄存器(包括错误发生时的指令地址)压入 MSP 指向的堆栈
原理:异常时的堆栈自动压入机制
当错误(如 HardFault、中断等异常)发生时,Cortex-M 处理器会触发 “硬件自动压栈”:将当前执行上下文的关键寄存器按固定顺序压入当前活跃的堆栈(如果此时使用 MSP,则压入 MSP 指向的主堆栈),压栈顺序为:R0 → R1 → R2 → R3 → R12 → LR(返回地址) → PC(错误发生时的指令地址) → xPSR(程序状态寄存器)
其中,PC(程序计数器)的值就是错误发生时正在执行的指令地址,通过这个地址可以直接定位到对应的函数。
.在本次案例中 我们不查看pc寄存器而是查看lr寄存器
指示 “被中断函数的返回目标”,追溯函数调用链
当程序正常运行时,LR的作用是保存 “当前函数执行完毕后要返回的下一条指令地址”(即调用者的地址)。例如:
- 函数 A 调用函数 B(执行BL B指令),此时 B 的LR会被设置为 A 中 “调用 B 之后的下一条指令地址”(即 B 执行完后要返回 A 的位置)。
- 若 B 执行时发生异常,处理器会将 B 的LR值压入栈中。此时栈里的LR就记录了 “B 原本要返回 A 的地址”。
通过这个LR值,可以反向追溯:错误发生在哪个函数(B)中,而这个函数是被哪个函数(A)调用的,从而还原错误发生时的函数调用链(如 A→B→错误点)。
补充
![]()
再上面这里 20000008是pc最后的指向 而08000f6c是发生错误前正在指向的代码翻译成机器码后的储存位置
具体详情看
06 调用栈和fault analyzers
