153、【Nuttx】【OS】【启动】回归!继续 Nuttx 探索(Stack Monitor)

【声明】本博客所有内容均为个人业余时间创作,所述技术案例均来自公开开源项目(如Github,Apache基金会),不涉及任何企业机密或未公开技术,如有侵权请联系删除

背景

之前搞一些别的内容去了,感兴趣的可以看专栏 【Ubuntu】【工具类】

下面继续回归 Nuttx 探索,回顾了下,之前大致分析完了 Esbonio 服务器的搭建,OK,搭建完这个文档服务器后,用户就可以随心所欲的访问自己构建出来的帮助说明文档了

当然,这文档和官方的也没啥太大差异,主要图的就是一个方便!自己构建出来的文档在性能和速度上会非常快!

然后关于启动部分也稍微回顾了下,大致分析了 arch/arm/src/stm32/stm32_start.c 文件中的栈溢出保护部分

下面继续

新建仓库说明

新建了个 Gitee 仓库
https://gitee.com/hitweston/nuttx

存放 Nuttx 源仓库备份镜像,目标是每个月更新一次源仓库的内容,尽量保持内容最新

有需要的可以自取,刚新增,内容还是很多的,方便考古

栈溢出检测

OK,先回到这个配置项 ARMV7M_STACKCHECK,这里最后再回顾下栈溢出检测,在帮助文档中搜索,可以找到相关内容如下

里面内容如下,这是个整体的功能介绍:在 ARMv7-M 架构上运行时动态进行栈溢出检测

下面来详细看下,这里提到,Nuttx 有两种方法来检测栈溢出,先看第一种 Stack Monitor 栈监视器

The Stack Monitor

该功能可以通过 CONFIG_STACK_COLORATION 配置项打开,Stack Monitor 开启后,系统会在创建任务栈(包括空闲任务 idle task 和中断栈)时,用一个已知的固定值来填充整个栈空间,这个固定值叫做 STACK_COLOR,比如在 ARM 架构中,这个固定值是 0xdeadbeef

这个填充过程叫做 stack coloring 栈着色,比如一个 1024 字节的栈,在初始化时会全部写成 0xdeadbeef

对于系统启动时就存在的栈(比如 idle 任务和中断栈),这个填色操作是在复位后,系统初始化早期完成的

栈着色之后,系统会提供函数 up_check_stack() 来扫描栈内存,该函数会从栈底(最低地址)开始向上查找,找到最后一个仍保持 STACK_COLOR 值的位置,由此就可以推断当前栈的最大使用深度 = 栈顶 - 最后一个未被覆盖的颜色位置,这样就可以知道某任务到底使用了多少栈空间

OK,接下来是 Stack Monitor 守护进程

如果再开启 CONFIG_SYSTEM_STACKMONITOR,系统就会启动一个后台守护任务 daemon,这个 daemon 会定期遍历所有任务,并调用 up_check_stack() 检查每个任务的栈使用情况,可用于

  • 调试阶段:帮助开发者合理设置任务栈大小
  • 运行时监控:观察是否有任务接近栈溢出

OK,虽然 Stack Monitor 很有用,但也有其局限性,比如这种模式无法可靠检测出某些类型的栈溢出

举个例子,某个函数内部声明了一个很大的局部数组(比如 char buf[2000]),导致栈指针 SP 一下就跳到远低于栈底的位置,也就是超出了分配的栈空间,过程如下

  • 被染色
  • 内部申请了很大的数组,导致 SP 指针跳过了染色区域

OK,可以看到,函数会在这个非法的区域读写数据,破坏掉其他的内存,比如里面可能有别的任务的数据,或内核结构,但函数返回前,栈指针又被恢复(因为 ARM 使用 LR 返回,不依赖栈空间去保存返回地址),所以栈底部的 STACK_COLOR 标记根本没有被覆盖,那么 Stack Monitor 机制就扫描不到任何异常,然后还以为栈在正常使用,但此时内存已经实际上被悄悄破坏掉了!

所以最后这里 Nuttx 引入了第二种栈检查机制 Per function Call

这种机制可以在每次函数调用时,实时检查栈指针是否越界,从而捕获这类跳跃式栈溢出,

最后总结一下 Stack Monitor:通过填色 + 扫描估算栈使用情况,适合调试和优化栈空间布局,但问题是无法检测那些瞬间跳过栈底,破坏内存后,又恢复栈指针的隐蔽式栈溢出,因此需要配合更严格的运行时检查机制进行使用

关于 Per function Call,其实之前 blog 【OS】【Nuttx】【启动】栈溢出保护:配置项添加 隐约说了一些,下面就技术文档再详细看下

这里详细描述了 Per function Call 机制的原理,其基本就是利用编译器进行函数插桩 profiler hook(性能分析钩子)

当启用 CONFIG_ARMV7M_STACKCHECK 后,系统会保留 R10 寄存器,专门用来保存当前任务栈的底部地址,也叫做 rBS(register Base of Stack),值域为什么选 R10 寄存器,之前 blog 【OS】【Nuttx】【启动】栈溢出保护:r10 寄存器 已经分析过


OK,本篇先到这里,如有疑问,欢迎评论区留言讨论,祝各位功力大涨,技术更上一层楼!!!更多内容见下篇 blog
【Nuttx】【工具】Esbonio 更新后无法使用(二)

相关推荐
啊阿狸不会拉杆20 天前
《计算机操作系统》第十章 - 多处理机操作系统
c++·算法·计算机组成原理·os·计算机操作系统
啊阿狸不会拉杆20 天前
《计算机操作系统》 第十一章 -多媒体操作系统
开发语言·c++·人工智能·os·计算机操作系统
啊阿狸不会拉杆20 天前
《计算机操作系统》 - 第九章 操作系统接口
人工智能·算法·计算机组成原理·os·计算机操作系统
啊阿狸不会拉杆22 天前
《计算机操作系统》第七章 - 文件管理
开发语言·c++·算法·计算机组成原理·os·计算机操作系统
啊阿狸不会拉杆22 天前
《计算机操作系统》第六章-输入输出系统
java·开发语言·c++·人工智能·嵌入式硬件·os·计算机操作系统
啊阿狸不会拉杆22 天前
《计算机操作系统》第四章-存储器管理
人工智能·算法·计算机组成原理·os·计算机操作系统
LiRuiJie1 个月前
从OS层面深入剖析JVM如何实现多线程与同步互斥
java·jvm·os·底层
a不是橘子1 个月前
03在Ubuntu中验证PV操作
笔记·ubuntu·操作系统·虚拟机·os·pv操作
崎岖Qiu1 个月前
【OS笔记44】:磁盘存储管理
笔记·操作系统·os