打印
[其他ST产品]

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

[复制链接]
楼主: 大鹏2365
手机看帖
扫描二维码
随时随地手机跟帖
41
大鹏2365|  楼主 | 2023-1-15 19:23 | 只看该作者 |只看大图 回帖奖励 |倒序浏览
听起来这一切都很简单是不是?但是想写好一个开源库却比想象中难。

使用特权

评论回复
42
大鹏2365|  楼主 | 2023-1-15 19:24 | 只看该作者
代码分析

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

首先看main函数,和CmBacktrace相关的初始化就一个函数:

使用特权

评论回复
43
大鹏2365|  楼主 | 2023-1-15 19:24 | 只看该作者

使用特权

评论回复
44
大鹏2365|  楼主 | 2023-1-15 19:26 | 只看该作者
而这个函数里面很简单,仅仅是赋值了一些变量:

使用特权

评论回复
45
大鹏2365|  楼主 | 2023-1-15 19:27 | 只看该作者
这些变量定义如下:

使用特权

评论回复
46
大鹏2365|  楼主 | 2023-1-15 19:28 | 只看该作者
这里你需要知道一些MDK的知识。在MDK中,使用 AREA 关键字创建的数据段,通常在段名后加$$Base表示起始地址,加$$Limit表示结束地址,比如这里的STACK:

使用特权

评论回复
47
大鹏2365|  楼主 | 2023-1-15 19:29 | 只看该作者
以及:

使用特权

评论回复
48
大鹏2365|  楼主 | 2023-1-15 19:29 | 只看该作者
所以这里的这些宏定义起始就是为了取得其中两个段:

使用特权

评论回复
49
大鹏2365|  楼主 | 2023-1-15 19:30 | 只看该作者

使用特权

评论回复
50
大鹏2365|  楼主 | 2023-1-15 19:31 | 只看该作者
由最开始的解析我们知道,这里查找函数调用的思路就是从栈区找到属于代码段范围的地址。这也就是为什么我们一开始要知道栈区范围和代码段范围。初始化就这么简单就完成了,主要工作都在错误中断中:

使用特权

评论回复
51
大鹏2365|  楼主 | 2023-1-15 19:31 | 只看该作者

使用特权

评论回复
52
大鹏2365|  楼主 | 2023-1-15 19:32 | 只看该作者
这里就是我上一章讲到的函数调用规则,当汇编调用C函数时,需要遵守这个规则。

使用特权

评论回复
53
大鹏2365|  楼主 | 2023-1-15 19:32 | 只看该作者
现在进入到关键函数cm_backtrace_fault里:

使用特权

评论回复
54
大鹏2365|  楼主 | 2023-1-15 19:33 | 只看该作者
上述代码都是一些简单的判断与打印,不再详细展开, 看一下下面的打印栈区:

使用特权

评论回复
55
大鹏2365|  楼主 | 2023-1-15 19:34 | 只看该作者
这里如果有堆栈溢出,且上层函数栈顶已经超过栈区最大地址,那什么也不会打印,具体打印数据逻辑如下:

使用特权

评论回复
56
大鹏2365|  楼主 | 2023-1-15 19:34 | 只看该作者
这里的相关打印,我再贴一下:

使用特权

评论回复
57
大鹏2365|  楼主 | 2023-1-15 19:35 | 只看该作者
这和前文中原理分析相关内容,可以一一对应着去看。 下面则是打印的硬件压栈的那些寄存器数据:

使用特权

评论回复
58
大鹏2365|  楼主 | 2023-1-15 19:35 | 只看该作者
实际串口打印如下:

使用特权

评论回复
59
大鹏2365|  楼主 | 2023-1-15 19:36 | 只看该作者
接下去就是我说的,通过查找寄存器对应的每个位,来判断当前故障的类型:

使用特权

评论回复
60
大鹏2365|  楼主 | 2023-1-15 19:36 | 只看该作者
具体不再分析,想要知道细节的可以查看《Cortex-M3权威指南》表D.17之后的几个表。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则