目录
- 一、概述
- 二、方法一:Call Stack Locals
- 三、方法二:Show Code at Address
-
- 3.1 需要通过LR判断SP?
-
- 3.1.1 关于MSP和PSP
- 3.1.2 为什么LR可以去判断
- 3.2 定位的原因 -- 入栈
- 四、遇到的hardfault情况
-
- 4.1 地址不对齐hardfault
- 4.2 访问地址越界
一、概述
调试过程中难免会遇到各种异常,hardfault这是一个更常见的类型。当我第一次学习的时候,我曾经非常害怕这种情况,不知道如何定位,不知道是哪里导致了问题,都依赖于猜测。互联网上有很多定位hardfault问题教程基本不差,方法就那些。 我最近整理了一点时间。本章主要记录了我实践过的内容hardfault定位方法。后续会议hardfault本文还补充了相关问题,方便自己查阅。 主要参考文件为《CM3权威指南CnR2.pdf》。
二、方法一:Call Stack Locals
我认为这种方法是最简单的,只需要分:
- 进入模拟后,全速运行,进入hardfault后,在Call Stack Locals窗口,找到HardFault Handler,右键选择Show Caller Code:
- 程序会自动跳转到有问题的代码,重点分析上下文。
三、方法二:Show Code at Address
这是搜索到的教程里,描述最多的方法。就是通过SP指针找到PC指针,然后跳转,也只需要三步:
- 也是仿真进入hardfault异常,此时重点关注寄存器部分。将SP指针放到memory在窗户中,由于寄存器是32位,调整为long型号显示看起来更方便,截图时忘记调整。依次是R0~R3、R12、LR、PC、XPRS 对比寄存器的值Keil也可以看到左侧寄存器的值STM32是小端模式。所以找到第六个,也就是PC寄存器值:
- 拿到了PC寄存器值,在Disassembly窗口,右键选择Show Disassembly at Address:
- 在弹出的框中输入PC然后,寄存器的值Go To,程序就会跳转到出现异常的位置。其实应该输入PC值-1(忘记在哪里看到,找出补充的原因):
参考链接:添加链接描述,添加链接描述。
3.1 需要通过LR判断SP?
大索到的教程大多不直接使用SP寄存器的值。都是先通过的R14(LR)判断将是值MSP(R14(LR) = 0xFFFFFFE9)或PSP(R14(LR) = 0xFFFFFFFD)的值作为SP但在权威指南中: 既然可以通过LR判断表明寄存器已更新并直接使用SP指针不好吗?()
3.1.1 关于MSP和PSP
MSP和PSP都是堆栈指针: 那么如何控制使用MSP还是PSP呢?再看: 这里的CONTROL[1]是指CONTROL寄存器,在Keil它也可以在左侧的寄存器中找到: CONTROL选择使用寄存器MSP/PSP,异常发生时,通过R14(LR)在判断异常之前使用MSP还是PSP。
3.1.2 为什么LR可以去判断
在《权威指南》中给出以下解释: 从这里可以看出,在线教程是基于0xFFFFFFE9和0xFFFFFFFD判断使用MSP还是PSP基础。实际上是基础bit2判断,所以有人留言说他既不是0xFFFFFFE9也不是0xFFFFFFFD,取哪个指针?
3.2 定位的原因 – 入栈
先说为什么通过SP去找PC定位能实现吗?Keil左边的寄存器本身就有一个PC了呀?R14寄存器描述如下: 可以从黄色高亮的注释语句中得出,Keil左侧的PC是hardfault函数地址对定位没有帮助。
顺便记录一下STM32.栈是向下增长的:
四、遇到的hardfault情况
4.1 地址不对齐hardfault
做IAP升级功能,发现只要写flash,跳转函数直接进入hardfault。最后发现是传参,buf没有四字节对齐: keil默认情况下,4字节本身是对齐的,模拟检查最初输入的参数指针也是4字节对齐的。搜索后,在串口分析数据后,删除了7个字节的包头并输入data部分导致地址不对齐。在使用前定义函数中的局部变量:
4.2 访问地址越界
划分64K片上flash空间,最后2K作为参数存储区。填写参数起始地址时,直接写成64K(0x0801000)hardfault。