[其他ST产品] (GCC)STM32进阶详解之栈回溯

[复制链接]
 楼主| 大鹏2365 发表于 2023-1-15 19:23 | 显示全部楼层
听起来这一切都很简单是不是?但是想写好一个开源库却比想象中难。
 楼主| 大鹏2365 发表于 2023-1-15 19:24 | 显示全部楼层
代码分析

就以上文中demo里不使用OS的情况为例,分析整个代码流程。

首先看main函数,和CmBacktrace相关的初始化就一个函数:
 楼主| 大鹏2365 发表于 2023-1-15 19:24 | 显示全部楼层
 楼主| 大鹏2365 发表于 2023-1-15 19:26 | 显示全部楼层
而这个函数里面很简单,仅仅是赋值了一些变量:
7267463c3e2d0ac66e.png
 楼主| 大鹏2365 发表于 2023-1-15 19:27 | 显示全部楼层
这些变量定义如下:
6251263c3e3034470c.png
 楼主| 大鹏2365 发表于 2023-1-15 19:28 | 显示全部楼层
这里你需要知道一些MDK的知识。在MDK中,使用 AREA 关键字创建的数据段,通常在段名后加$$Base表示起始地址,加$$Limit表示结束地址,比如这里的STACK:
1926363c3e34da04ed.png
 楼主| 大鹏2365 发表于 2023-1-15 19:29 | 显示全部楼层
以及:
3491563c3e3723c14c.png
5586963c3e37a9703a.png
 楼主| 大鹏2365 发表于 2023-1-15 19:29 | 显示全部楼层
所以这里的这些宏定义起始就是为了取得其中两个段:
4805063c3e3948b71e.png
 楼主| 大鹏2365 发表于 2023-1-15 19:30 | 显示全部楼层
 楼主| 大鹏2365 发表于 2023-1-15 19:31 | 显示全部楼层
由最开始的解析我们知道,这里查找函数调用的思路就是从栈区找到属于代码段范围的地址。这也就是为什么我们一开始要知道栈区范围和代码段范围。初始化就这么简单就完成了,主要工作都在错误中断中:

7810063c3e3edba494.png
 楼主| 大鹏2365 发表于 2023-1-15 19:31 | 显示全部楼层
 楼主| 大鹏2365 发表于 2023-1-15 19:32 | 显示全部楼层
这里就是我上一章讲到的函数调用规则,当汇编调用C函数时,需要遵守这个规则。
 楼主| 大鹏2365 发表于 2023-1-15 19:32 | 显示全部楼层
现在进入到关键函数cm_backtrace_fault里:

3944363c3e451e2c40.png
 楼主| 大鹏2365 发表于 2023-1-15 19:33 | 显示全部楼层
上述代码都是一些简单的判断与打印,不再详细展开, 看一下下面的打印栈区:
4662863c3e47095e14.png
 楼主| 大鹏2365 发表于 2023-1-15 19:34 | 显示全部楼层
这里如果有堆栈溢出,且上层函数栈顶已经超过栈区最大地址,那什么也不会打印,具体打印数据逻辑如下:
1812463c3e4927f0e6.png
 楼主| 大鹏2365 发表于 2023-1-15 19:34 | 显示全部楼层
这里的相关打印,我再贴一下:
8689763c3e4b15781d.png
 楼主| 大鹏2365 发表于 2023-1-15 19:35 | 显示全部楼层
这和前文中原理分析相关内容,可以一一对应着去看。 下面则是打印的硬件压栈的那些寄存器数据:
404163c3e4d10217e.png
 楼主| 大鹏2365 发表于 2023-1-15 19:35 | 显示全部楼层
实际串口打印如下:
8892263c3e4f3e0fc6.png
 楼主| 大鹏2365 发表于 2023-1-15 19:36 | 显示全部楼层
接下去就是我说的,通过查找寄存器对应的每个位,来判断当前故障的类型:
4926063c3e5140270f.png
 楼主| 大鹏2365 发表于 2023-1-15 19:36 | 显示全部楼层
具体不再分析,想要知道细节的可以查看《Cortex-M3权威指南》表D.17之后的几个表。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部