如何灵活运用keil工具进行问题分析(2)— 定位FreeRTOS的栈溢出导致hardfault问题

news2024/11/19 13:20:18

前言

(1)如果有嵌入式企业需要招聘湖南区域日常实习生,任何区域的暑假Linux驱动实习岗位,可C站直接私聊,或者邮件:zhangyixu02@gmail.com,此消息至2025年1月1日前均有效
(2)之前我发表过一篇关于如何利用keil工具解决程序卡死问题的博客。但是依旧有朋友遇到hardfault问题还是不能够灵活解决。其实hardfault问题和我之前说的程序卡死的排查流程基本是一样的。就只有细微的不同点。但是为了做保姆级教程,因此再写一篇博客赘述一下。

问题复现

(1)首先看一下网友的问题:
<1>他说程序运行不到1分钟就进入hardFault。这个代码量很少,所以能够很快定位到问题,但是如果程序大了,如何定位问题。
<2>他说可以尝试通过查看R0–R15寄存器是否可以找出问题。
(2)首先回答第一个问题,对于程序的问题定位,肯定是一个复杂而又漫长的过程,经常能够遇到一些玄学问题因此我们要学会掌握技巧,下面的方法就是技巧之一。其次是第二个问题,这明显就是没搞明白寄存器的作用分别是干嘛的,完全是胡乱看寄存器。
(3)问题如下:

在这里插入图片描述

排查流程

栈回溯分析

(1)既然知道了问题是什么了,那么就开始排查,根据前面的介绍,我们可以通过keildebug工具中的Call Stack进行栈回溯。分析程序卡死之前被哪些函数调用,然后逐步分析这些函数可能的问题。
(2)但是,不幸的是,我们会发现Call Stack中只有一个HardFault_Handler。那么明显说明Call Stack工具现在是用不了的。

在这里插入图片描述

CM3和CM4异常返回值

(1)之前那篇博客,是介绍的普通的程序卡死如何进行排查,然后栈回溯调试。而这里有些许的不同,在于是hardfault错误,因此只有这个地方会不同。
(2)前文我介绍了,程序卡死一般是看R14(LR)寄存器,因为这个寄存器存放返回值信息,通俗来说就是C语言的return根据这个寄存器进行函数返回。
注:下图摘抄自CM3权威指南3.1寄存器组章节

在这里插入图片描述

(3)那么现在我们看一下R14(LR)寄存器值是什么。我们会发现里面居然是0xFFFFFFFD!很明显,我函数返回不可能是返回到一个0xFFFFFFFD,因为程序一般都是存储在0x08开头的位置。那么这个时候我们就需要来了解一下CM3CM4的异常返回值的知识了。

在这里插入图片描述

(4)我们在看上面的寄存器介绍的时候,有没有发现一个问题,R13怎么有两个寄存器,一个MSP,一个是PSP?因为MSP用于内核和异常处理,而PSP用于进程的堆栈。这使得Cortex-M3处理器可以轻松实现多任务操作系统。
(5)上述这些,如果想详细了解的个人建议直接看这篇博客,介绍的非常的好:RTOS系列文章(6):Cortex-M3/4之SP,MSP,PSP,Thread模式、Handler模式、内核态、用户态
(6)但是,这部分知识跟我们问题定位关系不大。我们只需要了解,如果R14(LR)如果是0xFFFFFFFD,那么就看PSP寄存器。如果R14(LR)0xFFFFFFF9,那么就看MSP寄存器。
注:下图摘抄自CM3权威指南9.6异常返回值章节

在这里插入图片描述

手动栈回溯

(1)很好,既然我们有上述知识了之后。因为R14(LR),我们就知道现在要看PSP寄存器的值了,之后内存信息知道堆栈数据,然后手动栈回溯了解HardFault_Handler之前是卡死在哪里。
(2)现在我们看PSP寄存器,知道堆栈寄存器存储的是0x00000020。那么就打开Memory工具,查看当前芯片内部的存储信息。
这里需要注意,PSP的堆栈寄存器,不是PC或者LR寄存器,因此是看的Memory工具而不是Disassembly工具。

在这里插入图片描述

(3)根据堆栈指针寄存器,我们知道了当前堆栈指向位置存储的信息。那么如何根据这些信息进行问题的排查呢?这个时候我们就需要了解一下CM3/CM4的中断/异常的入栈知识了。CM3/CM4的中断响应时候,硬件是会自动进行入栈的,他的栈存储位置如下。
注:下图摘抄自CM3权威指南9.1.1入栈章节

在这里插入图片描述

(4)之后我们就可以根据上面这个知识点,进行分析。可以得知,如果程序现在正常运行,那么应该是运行到0x08000145位置。

在这里插入图片描述

(5)于是我们根据0x08000145找到程序实际卡死的地方。发现是卡死在port.c文件中,而这个文件又是FreeRTOS的官方源码,出错概率很低。

在这里插入图片描述

解决思路

定位可能的原因

(1)有了上述的分析,其实问题就已经解决一大半了。现在我们知道程序是卡死在0x08000145位置,于是我们可以在这个位置进行打断点。然后复位程序重新跑,此时Call Stack能够帮助我们进行栈回溯了。
注意:程序需要多按几次全速跑,一直等到进入HardFault_Handler的前一刻停止。因为我们不清楚到底是什么时候卡死在这个断点处的。

在这里插入图片描述

(2)然后我们就开始分析Call Stack的内容,发现除了TaskGenericFunction()其他的要么是FreeRTOS官方程序,要么是C库程序。于是我们直接看TaskGenericFunction()程序到底发生了什么。跳转过去之后,我们发现这个任务中只有一个printf()打印。我尝试逐步注释printf(),发现可以解决问题,然后就错误的认为这是和printf()线程安全有关导致的bug。但是后面发现,这并不问题的关键。

在这里插入图片描述

(3)如何发现真正的问题是什么?我们可以看TaskGenericFunction()函数的Location/Value,会发现这里居然是0x00000000!我们都知道STM32 的内存管理起始就是对0X0800 0000 开始的Flash部分和0x2000 0000 开始的SRAM部分使用管理。因此,这个地方毫无疑问是有问题的。出现这种问题,基本就可以知道是栈溢出的问题了。

在这里插入图片描述

FreeRTOS的uxTaskGetStackHighWaterMark()函数

(1)既然我们知道了是栈溢出的问题,那么如何知道是那个地方栈溢出了呢?此时就不得不是使用到FreeRTOSuxTaskGetStackHighWaterMark()函数了。这个函数可以监控任务使用的栈空间历史使用剩余值的最小值。使用方法如下:这里需要注意,需要在FreeRTOSConfig.h中将INCLUDE_uxTaskGetStackHighWaterMark设置为1,才可以使用这个函数。

/**
 * @brief   查看任务使用的栈空间大小
 *
 * @param   xTask 任务句柄
 *
 * @return 任务堆栈可用的最小值,单位word(4字节)
 */
UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask );

/* === 使用方法 === */
void StartCubemxTask(void *argument)
{
  /* USER CODE BEGIN StartCubemxTask */
	char *CubemxTaskPrintf = (char *)argument;
	UBaseType_t Cubemx_Stack;
  /* Infinite loop */
  for(;;)
  {
		printf(CubemxTaskPrintf);
		Cubemx_Stack = uxTaskGetStackHighWaterMark(keilTaskHandle);
		printf("CubemxTask is %ld\r\n",Cubemx_Stack);		
  }
  /* USER CODE END StartCubemxTask */
}

(2)了解了这个函数之后,那么我们尝试在每个任务中加入一个uxTaskGetStackHighWaterMark()监控栈使用情况,并且都打上断点。

在这里插入图片描述

(3)按照如下办法,之后开始查看他们的栈使用情况。

在这里插入图片描述

(4)我们一点一点的开始测试,最终发现是能够找到栈空间被榨干的地方了。

在这里插入图片描述

(5)现在我们思考一下为什么这个地方栈空间会被榨干。我们知道,起始是执行了下面这个for循环之后,栈空间就为空了。因此我们再看一下任务分配的时候任务栈空间是多少,能够发现是100 word,也就是400字节。而这里的buf[]就有500字节了。于是问题就成功发现了,此时我们可以尝试调小buf[]或者是增大任务栈空间。

for ( i = 0; i < 500; i++)
	buf[i] = 0;

在这里插入图片描述

总结

(1)ARM的M系列控制器hardfault问题调试步骤,应该基本都是这样的。所以说我们要多练习,程序出故障的可能性很多,栈溢出,逻辑错误,硬件bug都是有可能的。
(2)题外话:说实话,比起调程序bug,猜女孩子的心思才是最难的。硬件有问题,我有万用表,逻辑分析仪,示波器。软件问题,我有编译器,调试器,debug工具,栈回溯。女生发脾气,怎么也不知道到底哪里得罪姑奶奶了,最恶心的是bug不可复现。哭死

参考

(1)RTOS系列文章(6):Cortex-M3/4之SP,MSP,PSP,Thread模式、Handler模式、内核态、用户态
(2)STM32的内存管理相关(内存架构,内存管理,map文件分析)
(3)hardfault问题分析解决及记一次ucosIII环境下的hardfault解决

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1838435.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

防火墙中的NAT

防火墙的NAT NAT分类 源NAT 基于源IP地址进行转换。 我们之前接触过的静态NAT&#xff0c;动态NAT&#xff0c;NAPT都属于源NAT&#xff0c;都是针对源IP地址进行转换的。源NAT主要目的是为了保证内网用户可以访问公网。 先执行安全策略&#xff0c;后执行NAT 目标NAT 基于…

【归档】工作流审批初体验

title: 工作流审批初体验 typora-root-url: 工作流审批初体验 date: 2023-05-09 17:00:39 tags: 项目插件 文章目录 参考文档工作流审批 flowable设置工作流模型绑定用户 设计表单绑定表单 用户发起流程上传查看流程范围流程可视化 请假流程与OA流程子集关系 参考文档 迁移文…

Termius for Mac/Win:跨平台多协议远程管理利器

Termius for Mac/Win是一款备受瞩目的跨平台多协议远程管理软件&#xff0c;以其卓越的性能、丰富的功能和便捷的操作体验&#xff0c;赢得了广大用户的青睐。无论是在企业IT管理、系统维护&#xff0c;还是个人远程连接、文件传输等方面&#xff0c;Termius都展现出了出色的实…

webpack5入门,根据官方文档简单学习,简单总结

c.**loader加载器&#xff1a;**webpack 只能理解 JS文件和 JSON 文件&#xff0c;loader 让 webpack 能够去处理其他类型的文件&#xff0c;并将它们转换为有效 模块&#xff0c;以供应用程序使用&#xff0c;以及被添加到依赖图中。&#xff08;比如css&#xff0c;less&…

从理论到实践掌握UML

统一建模语言&#xff08;UML&#xff09;是软件工程师用来设计软件系统的一种工具&#xff0c;就像是一套图形化的说明书。它让开发团队能够以图形化的方式来理解、设计和开发软件系统&#xff0c;比起用文字来描述&#xff0c;更加直观易懂。本文通过UML实例化的理论和实践相…

小米HyperOS 澎湃os机型免答题 免社区等级 秒接bl锁操作步骤解析【二】

前面两期博文; 小米HyperOS 澎湃os机型免答题 免社区等级 秒接bl锁操作步骤解析 小米机型解锁bl 绕过社区等级5才可以解锁的限制的教程_没有五级社区怎么解锁bl-CSDN博客 小米对米粉解锁bl是越来越苛刻了。目前社区等级 答题 审核等等步骤越来越繁琐。而且通过率很低。知名开…

04 Pytorch tensor

一&#xff1a;老版本的 variable 二&#xff1a;新版 tensor 曾经&#xff1a;求导相关 如今&#xff1a;数据相关 –dtype: 张量的数据类型&#xff0c;三大类&#xff0c;共9种。torch.FloatTensor, torch.cuda.FloatTensor –shape: 张量的形状。如&#xff1a;&#x…

PTP简介及Linux phy ptp驱动实现

1、PTP简介 PTP(precision time protocol)精确时间协议&#xff0c;是一种时间同步的协议&#xff0c;对应 IEEE 1588 标准&#xff0c;是基于网络数据包的一种时间同步协议&#xff0c;1588v2的同步精度可以达到ns级&#xff0c;但1588协议对硬件有依赖。 2、PTP原理 时间同…

手把手!从头构建LLaMA3大模型(Python)

1. 前期准备 让我们先来想一想大概需要做什么。 首先是模型架构的选择。原工作用的是 GPT Neo 架构&#xff08;可以看他们的 config&#xff09;&#xff0c;这个算是很老的模型了&#xff0c;最初是 EleutherAI 用来复现追踪 GPT-3 的工作的&#xff0c;现在用的也比较少了…

java入门1.4.0

前言&#xff1a; 在1.4.0版本中&#xff0c;更新了对语言三大要素的理解 红字为更新&#xff0c;绿字为迭代 这时我们目前拥有的知识 正片&#xff1a; 有了这些内容&#xff0c;我们就可以顺利进入到Spring Boot阶段了 Q&#xff1a;有人就会问&#xff0c;面向对象的特性…

瑞典农业科学大学《Nature Geoscience》(IF=18)!揭示北方森林碳汇对干旱的响应机制!

本文首发于“生态学者”微信公众号&#xff01; 北方森林覆盖了地球陆地面积的11%&#xff0c;储存了全球陆地碳储量的约三分之一。因此&#xff0c;它们被认为是减缓气候变化政策的一个重要因素。然而&#xff0c;环极寒带地区是气候变化速度最快的地区。这包括更频繁和更严重…

谷粒商城实战(042集群学习-mysql集群-主从同步)

Java项目《谷粒商城》架构师级Java项目实战&#xff0c;对标阿里P6-P7&#xff0c;全网最强 总时长 104:45:00 共408P 此文章包含第361p-第p363的内容 集群 集群的基础形式 MySQL集群 MMM机制 这里使用了vip虚拟ip方式&#xff08;如192.168.0.101&#xff0c;192.168.0.102&…

换位置(C++)

问题描述 体育课上&#xff0c;有一个班级的同学站成了一队&#xff0c;体育老师请最高的和最矮的两位同学调换一下位置&#xff0c;其余的同学不要动&#xff0c;请编程实现&#xff01;&#xff08;假设所有人的高矮都是不一样的&#xff09; 输入 第一行有一个整数 &…

【html】爱心跳动动画:CSS魔法背后的故事

效果展示&#xff1a; 代码介绍&#xff1a; 爱心跳动动画&#xff1a;CSS魔法背后的故事 在前端开发中&#xff0c;CSS不仅仅是一种用于控制网页样式的工具&#xff0c;它也是一种表达创意和想象力的艺术手段。今天&#xff0c;我要为大家介绍一段使用CSS实现的爱心跳动动画…

【TB作品】MSP430G2553,单片机,口袋板, 交通灯控制系统

题8 交通灯控制系统 十字路口交通灯由红、绿两色LED显示器&#xff08;两位8段LED显示器&#xff09;组成&#xff0c;LED显示器显示切换倒计时&#xff0c;以秒为单位&#xff0c;每秒更新一次&#xff1b;为确保安全&#xff0c;绿LED计数到0转红&#xff0c;经5秒延时&#…

深度解析:河南资信预评价乙级资质人员专业背景要求

深度解析&#xff1a;河南资信预评价乙级资质人员专业背景要求 河南资信预评价乙级资质对人员的专业背景有着明确的要求&#xff0c;这些要求旨在确保工程咨询单位具备足够的专业能力和技术水平。以下是对这些专业背景要求的深度解析&#xff1a; 一、咨询工程师&#xff08;投…

基于IDEA的Maven(依赖介绍和引用)

如何通过一个坐标信息&#xff08;依赖&#xff09;去引用 &#xff0c;某个"jar 包" 会在这篇博客进行学习。 目录 一、学习开始 &#xff08;0&#xff09;项目的结构组成和 "pom.xml" 文件内容。 &#xff08;1&#xff09;首先需要一个标签&#xf…

Open3D点云处理学习

Color ICP Colored point cloud registration — Open3D 0.11.0 documentation Colored point cloud registration - Open3D 0.18.0 documentation 展示了使用color-icp结果 对比gicp错误处理结果 intel自己的论文 Colored Point Cloud Registration Revisited 优化方程 参…

计算机行业的现状与未来之2024

年年都说编程好&#xff0c;编程工资涨不了。 人家骑车送外卖&#xff0c;月入两万好不好。 一、计算机专业的背景与现状 在过去几十年里&#xff0c;计算机科学相关专业一直是高考考生的热门选择。无论是计算机科学与技术、软件工程&#xff0c;还是人工智能与大数据&#xff…

vue项目首页优化问题(前后端都要优化)

2.1 config/index.js 开启productionGzip 将其productionGzip 配置成true 2.2 配置Gzip的 插件配置 打开webpack.prod.config.js 配置一下这段代码 代码如下 if (config.build.productionGzip) { const CompressionWebpackPlugin require(‘compression-webpack-plugin’)…