- UID
- 1029342
- 性别
- 男
|
调试嵌入式程序时,你是否遇到过程序跑飞最终导致硬件异常中断的问题?遇到这种问题是否感觉比较难定位?不知道问题出在哪里,没有办法跟踪?尤其是当别人的程序踩了自己的内存,那就只能哭了
今天在论坛上看有同学求助这种问题,正好我还算有一点办法,就和大家分享一下。
解决办法非常非常简单,本文将以Aduc7026(ARM7内核)和LM3S8962(cortex内核,STM32也是cortex内核,同理)为例,讲讲解如何定位此种问题。
先说ARM7内核,cortex内核稍微有一点复杂,后面再说。
ARM7内核有多种工作模式,每种模式下有R0~R15以及CPSR共17个寄存器可以使用,有关这些寄存器的细节我就不详细介绍了,详细的介绍请参考“底层工作者手册之嵌入式操作系统内核”中的2.2~2.3节,这里只介绍与本文相关的寄存器。
其中R14又叫做LR寄存器,它被用来保存函数、中断调用时的返回地址,看到了吧,它保存了“返回地址”!这不就是我们需要的么?就这么简单,发生异常中断时,LR寄存器中保存的地址附近就会有导致异常的指令。
接下来我们再先了解一下相关的知识,然后再通过一个例子构造一个指令异常,然后再反推找到产生异常的这条指令,做一个实例演练!
当程序跑飞时,绝大部分情况都会触发硬件异常中断,硬件异常中断的中断服务函数在中断向量表中有定义,我们来看看ARM7的中断向量表,在keil开发环境里(以下例子是在keil环境下介绍的),这个文件一般叫startup.s,如下:
Vectors: LDR PC, Reset_Addr
LDR PC, Undef_Addr
LDR PC, SWI_Addr
LDR PC, PAbt_Addr
LDR PC, DAbt_Addr
NOP /* Reserved Vector */
LDR PC, IRQ_Addr
LDR PC, FIQ_Addr
Reset_Addr: .word Reset_Handler
Undef_Addr: .word ADI_UNDEF_Interrupt_Setup
SWI_Addr: .word ADI_SWI_Interrupt_Setup
PAbt_Addr: .word ADI_PABORT_Interrupt_Setup
DAbt_Addr: .word ADI_DABORT_Interrupt_Setup
IRQ_Addr: .word ADI_IRQ_Interrupt_Setup
FIQ_Addr: .word ADI_FIQ_Interrupt_Setup
ARM7的中断向量表比较简单,只有7种中断,它把所有正常的中断都放到了SWI、IRQ和FIQ中了,那么本文所介绍的异常情况将会触发Undef、PAbt或者DAbt异常中断,至于是哪种就需要看具体的原因了。
指令A //触发异常
指令B
比如说当指令A无法执行时,它就会触发异常中断,硬件就会自动将这条指令后面的指令的所在地址,也就是指令B的地址保存到LR寄存器中,然后就跳转到与这种异常相关的中断向量表中,假如指令A触发了Undef异常中断,那么硬件就会跳转到中断向量表的第二个中断向量Undef_Addr,从中断向量表可知,这个中断向量对应的中断服务函数就是ADI_UNDEF_Interrupt_Setup,这个函数一般是一个死循环,这样单板就死了,当我们停下程序时,就会发现程序停在了这个函数里面。
我们来看下面这个实例,我把定位过程的每一步都记录下来,一起来看下:
14 S32 main(void)
15 {
16 U8* pucAddr;
17
18 /* 初始化硬件 */
19 DEV_HardwareInit();
20
21 /* 创建任务 */
22 WLX_TaskInit(1, TEST_TestTask1, TEST_GetTaskInitSp(1));
23 WLX_TaskInit(2, TEST_TestTask2, TEST_GetTaskInitSp(2));
24
25 /**********此指令会触发异常中断**********/
26 pucAddr = (U8*)0;
27 *pucAddr = 0;
28 /****************************************/
29
30
31 /* 开始任务调度 */
32 WLX_TaskStart();
33
34 return 0;
35 }
上面这段测试代码是我在我写的一个小型嵌入式操作系统上改的(有兴趣的话可以访问我的博客O(∩_∩)O),只需要关注26和27行即可,其余的只是陪衬,以使这段程序看起来稍微复杂一些。这两行指令将0地址清0,0地址是中断向量表,向这个地址写数据会导致异常的,但——这正是我们所需要的。
然后,为了方便,我们在中断向量表里把上面的3个异常中断向量都修改一下,如下:
Vectors: LDR PC, Reset_Addr
LDR PC, FaultIsr
LDR PC, SWI_Addr
LDR PC, FaultIsr
LDR PC, FaultIsr
NOP /* Reserved Vector */
LDR PC, IRQ_Addr
LDR PC, FIQ_Addr |
|