一、 简介
C语言里面最强大的莫过于指针了。它创造了程序思想的无限可能。但同时指针用过头就像脱缰的野马,让程序员死的心都有。
指针即指向一个地址的变量。当指向这个地址的变量是非法的,那这个指针就变成野指针了。而野指针是很难找出问题的,特别是一些很隐蔽性的野指针往往程序要运行数天才会出故障。
Cortex-M3当指针用法错误时,例如指针指向一个只读区域,但对该区域进行写操作,会产生BusFaultException的异常,如果我们利用好这个异常就会比较容易的找到出错的代码位置。再通过寄存器的上下文就比较容易判断出野指针产生的原因。
二、 Cortex-M3 中断
Cortex-M3中断时依次把xPSR, PC, LR, R12以及R3-R0由硬件自动压入适当的堆栈中:如果当响应异常时,当前的代码正在使用PSP,则压入PSP,也就是使用进程堆栈;否则就压入MSP,使用主堆栈。
而这些入栈的寄存器就是野指针出事的事故现场。特别是LR寄存器就是野指针程序执行错误的内存地址。
通过获取SP的地址,然后逆向查找内存数据,就能找到事故发生的地方。
三、 举例
使用一个定时器,他的数据结构包含
typedef struct __TMR{
INT8U tmrEn;
。。。
}TMR ;
定义一个野指针:
TMR *tmr = 0;
产生异常:
tmr->tmrEn = 1;
我们来看一下Keil MDK调试的实际界面:
其中BusFaultException()就是野指针事故后进入的异常。我们可以看到当前SP指针指向:0x20001760的地址,而图中1所示的内存内容和左侧的1表示的当前寄存器值是一致的。依次是R0,R1,R2,R3,R12。
从2的内存中可以看书,事故现场在0x0800614F位置,我们可以看到tmr->TmrEn = 1代码是在0x0800614E处。相差一是Cortex-M3运行在thumb2模式下的原因。可以看出只要能够读到LR的值就可以找到事故地址。
可以看到入栈的PC指针为0x8006158和LR还是有区别的,这是Cortex-M3响应中断最小有6个周期的延迟的原因。
四、 BusFaultException实现举例
示例中只打印出了LR和PC的值,异常时获取MSP的值,然后通过入栈顺序,通过偏移量找到LR和PC,然后用上一篇中提到的lcd_debug程序打印出这两个值。