嵌入式中变量被意外修改的调试方法

问题描述

在移植公司的实时操作系统到一款国产 RISC-V 架构芯片时,为了测试 systick 中断是否有效,在此中断 isr 中对一个静态变量加一,打断点观察变量的变化来确定中断是否正确执行了!

中断 isr 的主要内容如下:

	isr_handler(void) 
	{
		...
		static int i = 0;
		i++;
		clear_interrupt_flag();
		...
	}

在调试的过程中发现,进入到这个函数后确实给变量加 1 了,但是下一次再进入时变量值又会变为 0,调试了下汇编没发现问题。多执行几次发现效果相同,问题能够不断【复现】。

调试方法

变量的值被意外修改这样的问题之前也已经遇到过,直接的方法就是 watch 这个变量的地址,在修改的时候程序会停下来,这样就能看到哪里进行了非法操作。

可是在此款芯片上上面的方法却不太适用。虽然可以 watch 一个变量的地址,但是 watch 之后程序执行非常非常慢,可能要等非常久才能定位到问题,而我有不能减少中间执行的过程,这是一个常识性的问题,因此这中方式只能弃之不用。

有没有更好的方式呢?

我仔细的想了想,立刻就想到了一种非常简单的方式。我可以把这个变量设置为常量,常量一般都存储在代码段,而在我使用的这个芯片上,代码段是放在 flash 上面的,要通过普通的访存指令修改 flash 上面的数据会进入异常,这样我只需要查看异常发生的位置就能够成功定位到出问题的地方。

这样的方式果然好用,我立刻就发现了问题,可是让我不解的是它指向了一个不在代码区域内的位置,这可出乎我的意料了。

进一步的分析

当我发现问题发生的地方是一段程序区域外的位置,我觉得可能在中断处理流程中栈帧被修改了,这样恢复的时候才恢复到了一个错误的地址,这样的怀疑比较合理。我再回去看了看中断处理的汇编代码,发现我在中断中切换到了系统栈,将需要保存的现场存储到了系统栈中,而我的用户程序也使用了系统栈,这样旧的栈帧就被中断处理过程破坏了,恢复之后就表现出了一个异常的行为。

其实我切换栈指针这样的设计是正确的,只是我不应该在非任务环境下测试它。当第一个任务调度运行之后,中断打断的任务与系统栈有不同的栈指针,在这种条件下切换栈指针是正确的。我按照这样的思路创建了任务,启动实时操作系统,再次测试便没有问题了!

总结

在实际的测试中,对一些必要条件的忽略可能会造成严重的问题,我们不仅要关注程序执行的流程,更要关注程序执行的环境及程序执行对这一环境带来的改变

你可能感兴趣的:(嵌入式学习,策略)