目录

  • 一、概述
  • 二、方法一: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 访问地址越界
  • 五、方法三:使用addr2line工具
    • 5.1 工具简介
    • 5.2 移植
    • 5.3 使用案例

一、概述

调试过程中难免会遇到各种异常,hardfault算是比较常见的一种。在最开始学习的时候,一度很害怕这种情况,不知道怎么定位,摸不清是哪里导致了问题,全靠猜测。网上有很多定位hardfault问题的教程,基本大差不差,方法就那些。
最近有点时间,我也整理下。本章主要记录下我实践过的hardfault定位办法。后续遇到hardfault相关问题,也一并补充到本文中,方便自己查阅。
主要参考的文档为《CM3权威指南CnR2.pdf》。

二、方法一:Call Stack + Locals

这种方法我认为是最简单的,只需要分两步:

  1. 进入仿真后全速运行,进入hardfault后,在Call Stack + Locals窗口,找到HardFault Handler,右键选择Show Caller Code:
  2. 程序会自动跳转到出问题的代码,重点分析上下文即可。

三、方法二:Show Code at Address

这是搜索到的教程里,描述最多的方法。就是通过SP指针找到PC指针,然后去跳转,也只需要三步即可:

  1. 同样是仿真进入hardfault异常,此时重点关注寄存器部分。将SP指针放到memory窗口中,因为寄存器是32位,调整成long型显示看起来更方便,截图时忘记调了。依次是R0~R3、R12、LR、PC、XPRS 寄存器的值,对比Keil左侧寄存器的值,也可以看出来STM32是小端模式。所以找到第六个,即PC寄存器的值:
  2. 拿到了PC寄存器的值,在Disassembly窗口,右键选择Show Disassembly at Address:
  3. 在弹出的框中输入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(0x08010000),结果读取参数进入hardfault。

五、方法三:使用addr2line工具

5.1 工具简介

addr2line (它是标准的 GNU Binutils 中的一部分)是一个可以将指令的地址和可执行映像转换成文件名、函数名和源代码行数的工具(点击进入)。

搜索addr2line

在cmd中直接测试 addr2line --help

-a --addresses:在函数名、文件和行号信息之前,显示地址,以十六进制形式。
-b --target=:指定目标文件的格式为bfdname。
-e --exe=:指定需要转换地址的可执行文件名。
-i --inlines : 如果需要转换的地址是一个内联函数,则输出的信息包括其最近范围内的一个非内联函数的信息。
-j --section=:给出的地址代表指定section的偏移,而非绝对地址。
-p --pretty-print:使得该函数的输出信息更加人性化:每一个地址的信息占一行。
-s --basenames:仅仅显示每个文件名的基址(即不显示文件的具体路径,只显示文件名)。
-f --functions:在显示文件名、行号输出信息的同时显示函数名信息。
-C --demangle[=style]:将低级别的符号名解码为用户级别的名字。
-h --help:输出帮助信息。
-v --version:输出版本号。
addr2line工具是一个可以将指令的地址和可执行映像转换为文件名、函数名和源代码行数的工具。(点击进入原文)

5.2 移植

需要在程序中加入cm_backtrace(点击进入)。

原理:(GCC)STM32进阶详解之栈回溯

5.3 使用案例

下图是一个log:

我这个问题出现的比较凑巧,hardfault前正好出现了 type2 error ,大致运行位置:

结合应用逻辑,大概率是没有考虑tpye2为0,导致了dev没有赋值。但是具体在哪里出现的问题呢?

addr2line -e gateway.axf -a -f 000000fa 08026282 08012738 08017720 psr: 0x61000000


提示没有axf文件,需要切换到工程目录下,axf存放的那个文件夹。再次运行:

按住ctrl + shitf,鼠标右键,直接在PowerShell中运行:

重点分析给出的几个函数和文件位置。

Keil环境下STM32定位hardfault位置方法(addr2line工具)和遇到的情况相关推荐

  1. keil环境下stm32下载和擦除程序对Flash的影响

    一.烧录两个程序,读取FLASH(实测结果:两个区域都有程序,跟烧录的顺序没有关系) 1.首先 烧录0x08004000开始的程序 读取FLASH:只有0x08004000处有数据 2.烧写0x080 ...

  2. Keil环境下完成一个基于STM32汇编程序的编写

    本文内容:\color{red}{本文内容:}本文内容: 1)记录build生成的 hex文件各段的大小,了解Hex文件格式及其前8个字节内容含义: 2)学习在没有硬件条件下进行仿真调试的方法,观察A ...

  3. Keil环境下用STM32汇编语言工程分析HEX文件内容

    一.创建工程 1创建工程,点击Project,选择第一项创建新工程.并保存文件的地址和文件名. 2 配置环境 ①选择STM32F103RC芯片,点击OK. 然后在CMSIS下选择CORE:Device ...

  4. 基于keil环境下mm32f327单片机rtthread的移植

    基于keil环境下mm32f327单片机rtthread的移植 文章目录 基于keil环境下mm32f327单片机rtthread的移植 前言 一.所需资源 二.创建工程目录 三.复制所需文件到相应文 ...

  5. oracle数据库配置环境,win7环境下配置oracle数据库的方法

    前些日子在在Win7下安装了oracle 11g,不过PL/SQL却没法用,在实验的过程中,遇到了很多问题,下面就教您win7环境下配置oracle数据库的方法,供您参考. 环境:Windows 7( ...

  6. 对抗环境下的多无人机编队方法和队形变换研究

    对抗环境下的多无人机编队方法和队形变换研究 肖雁冰 张迎周(导)南京邮电大学 标签(空格分隔): 论文阅读 摘要   在无人机功能有限的今天,面对日趋复杂的作战任务.无法预测的作战环境,单一无人机所拥 ...

  7. python连接opencv库_python环境下安装opencv库的方法

    注意:安装opencv之前需要先安装numpy,matplotlib等 一.安装方法 方法一.在线安装 1.先安装opencv-python pip install opencv-python --u ...

  8. Python TimedRotatingFileHandler 多进程环境下的问题和解决方法

    Python TimedRotatingFileHandler 多进程环境下的问题和解决方法 原文:https://my.oschina.net/lionets/blog/796438 Python ...

  9. python的opencv库_python环境下安装opencv库的方法

    注意:安装opencv之前需要先安装numpy,matplotlib等 一.安装方法 方法一.在线安装 1.先安装opencv-python pip install opencv-python --u ...

最新文章

  1. CTFshow 文件上传 web157
  2. 转 性能分析工具汇总
  3. 应用上线前的“体检”,你知道需要检测哪些指标吗?
  4. BCB6.0里没有TCppWebBrowser
  5. window7 MySql Cluster数据库集群配置
  6. 操作系统存储器管理实验报告_献上膝盖!华为工程师抛出一份堪称“举世无双”操作系统笔记...
  7. 思科CCIE认证知识点之IPv6地址
  8. SQL--Chapter8--Working with Triggers and Transactions
  9. 201506230818_《JavaScript权威指南(第六版)——callee和caller、对象属性用作实参、自定义函数属性》(P175-180)...
  10. Arduino笔记-温度传感器的使用
  11. 集合框架(用LinkedList实现栈结构的集合代码)
  12. cad字体hztxt用什么代替_为什么CAD的字体库相同但打开图纸的效果却不同?
  13. 安卓iccid_Android 获取双卡手机IMEI,IMSI,ICCID
  14. C++--第8课 - 类中的封装
  15. R语言使用dplyr包计算dataframe分组聚合样本独特值个数、计数个数、四分位距IQR
  16. frameworks/base/core/res/res/values/symbols.xml:3915: error: no definition for declared symbol解决办法
  17. linux panic 和 bug_on
  18. 宏定义问题记录day2
  19. 提高IT项目沟通技巧
  20. win7 64 位系统焦点丢失解决方案

热门文章

  1. 清晰搞懂Spring Security的登录认证
  2. Web杀毒v3.3.1
  3. C# 创建可填充Word表单
  4. linux系统获取root权限
  5. 炫酷大屏demo_20套大屏模板,教你3分钟制作出酷炫的可视化大屏
  6. Android 系统各个版本市场占有率 官方统计地址
  7. 基于Java语言的网上订餐系统(附:源码 课件)
  8. android开发游记:仿支付宝余额数字累加滚动效果的实现
  9. 微信小程序如何实现将数据导出生成excel
  10. Linux NTFS 碎片整理,提高系统性能方法:NTFS文件格式、碎片整理和NTFS压缩