踩栈排故,流水账
排故小结
1、过程
产品故障描述:在单板上全速运行时发现系统在某产品测试用例里读取事件后系统复位,问题能够复现
首先确定OS软件中不会操作CPU复位,因此复位原因肯定是未进行喂狗,因此建议产品将狗关闭,并在IDE上进行单步追踪。
产品回复:感觉是调用事件读接口后进入死循环
我:查看事件读接口,我认为在任务读函数中不可能有死循环,根据现象那么就有两种可能一在事件读接口里非法访问进入异常,另一种可能就是读事件发生任务阻塞
从而产生任务调度,那么要么任务切换过程中异常,要么在任务运行过程业务代码异常。让产品暂停运行,发现pc指向os异常处理的尾巴(死循环),从而确认确实发生异常。
让产品注册异常钩子,打印异常信息发现属于5号异常总线读异常,再看异常时的pc指针却为非代码段地址,因此确定是取指异常。正常情况下,pc是硬件自动压栈的不会出现错误,
那错误的可能有两种一是硬件故障,而是踩内存。首先排除硬件故障,因为下载原先版本的代码运行正常。那就剩下踩内存。
接下来我的思路是进行打数据断点补获非任务切换时由哪条指令导致压栈的pc值被改,在分析哪里越界访问导致了踩内存。
产品:做了两件事,一发生异常时将内存全部打出根据任务栈顶魔术字查看所有申请的任务栈情况,二将申请的任务栈扩大问题不在复现。此时产品认为问题与任务栈大小有关,
其次由于很多任务栈顶附件的内存被改,存在踩内存的风险。接下就查找什么情况下栈顶附近的内存被修改。
我:第一反应是根据之前的异常查看异常栈的情况,发现lr的指向是taskdelay函数,现在想想这一信息没有多大用,因为必然是栈中pc值被修改后,
调用taskdelay函数时切换任务过程中导致的异常。
后面就顺着产品的思路查看栈顶附近内存被改的原因进行查看。
首先通过数据断点发现是在一个打印安全函数中修改了栈顶附近的内存,当时我的第一映像是os内部只有在发送错误时才会进行打印函数的调用因此我觉得os出错的问题很小(当然我不敢保证os在其他地方是否有打印)。
接下来,我的思路放在查找哪个任务中哪条函数里造成了栈顶附近的内存被修改。接下来,我了解产品任务创建的机制,分析了产品几十个任务的调度关系和顺序。由于任务太多即使通过打断点快速运行的方式也很难迅速定位,
因此我建议产品将所有业务代码屏蔽,只跑空的任务调度,这样确认是否是业务代码踩了内存,还是os函数中踩了内存。最后发现,任务栈顶附近内存依旧被修改,这样就确认跟产品业务代码无太多关系。
此时,没有太多思路,1、ut用例都过了没有问题,2、确实不清楚os内部哪里调用的打印安全函数。3、我一直任务安全函数就是根据用户提供的内存地址、长度进行操作(认知上根本就没意识到安全函数还会开栈)。
求助专家,最终发现在数据断点处也就是安全打印函数内有个相对非常大的开栈操作(超过业务设置的任务站大小的一半),因此找到之前踩栈以及栈顶附近内存被修改的原因。
这样也解释了为什么原版本没有问题现在的版本有问题的原因,安全库更换了。
还有几个疑问1、os中哪里调用的打印函数。

浙公网安备 33010602011771号