做VxWorks的时候经常会碰到任务异常的问题,有时很难定位,下面是根据网上的一些资料整理出来的。不正确的地方请指出,谢谢!
指令异常:系统打印program异常或instruction access异常
访问非法地址异常,串口打印data access异常,如:
data access
Exception current instruction address:0x00187d4c
Machine Status Register:0x00009030
Data Access Register: 0x8003435c
Condition Register:0x48000080
Data storage interrupt Register:0x0000000b
Task:0xc844f0 "XXX"
中断处理中产生的异常
2、可能的原因
1、
堆栈写越界,主要是数组写越界,导致前面声明的变量(因为堆栈是从下往上增长的)或者函数的参数或者函数返回的地址被改写为无效值。
2、
堆栈溢出,堆栈声明过小,而函数又声明了大数组,超出堆栈的容量
3、
内存改写,这是最通常出现的原因。包括,指针没有初始化,导致访问随机地址;访问空指针;内存操作范围越界,例如在使用
memcpy/memset等函数 使用的长度超过所分配,导致改写了其他的指针。因此在定位异常问题过程中,可以通过内存
管理先查看一下先前是否有内存写越界的记录,但是 内存写越界只有在释放该内存区时才能检查到,如果该内存
没有被释放,则即使写越界也是不知道的。
4、
系统调用不当。(
在中断中可以调用msgQSend的,而其它一些不允许的调用本身也是直接返回失败,一般不会直接导致
异常;之所以异常往往是调 用了semTake返回就以为成功了,直接访问被信号量保护的资源)
5、
增量编译引起的问题,Tornado增量编译有时会出现问题,导致古怪的异常,重新全量编译后,肯呢个会解决问题
6、
多任务抢占引起的问题,当多个任务共同访问一个或者多个变量时,如果互斥不当,可能会产生同步或互斥的问题,
比较典型的是:任务A和B都使用一个变量指针P;而A和B的优先级不同(即存在任务抢占),则他们在释放或者修改这个变量
指针的时候,可能会出现随机的异常访问问题。
3、处理策略
1、如果有理由怀疑是增量编译引起的,则首先尝试全量编译一下工程
2、分析异常出现时的调用栈信息:以data access异常为例;
如果在系统出现异常时接了串口,则可以直接看到类似以下列信息;如果出现异常时没有接串口,则定位问题时可首先接
上串口或者Tornado,然后使用“ti”命令也可以看到如下的异常信息:
data access
Exception current instruction address:0x00187d4c--
通过这个地址通常
可以通过符号表知道异常出现时系统正在运行哪个函数, l 0x00187d4c和lkaddr 0x00187d4c
Machine Status Register:0x00009030
Data Access Register: 0x8003435c
Condition Register:0x48000080
Data storage interrupt Register:0x0000000b
Task:0xc844f0 "XXX"
--
通过这个参数,可以知道是哪个任务出现的异常
具体定位提示:
1、可以使用
“checkStack”命令看是否产生了堆栈溢出:如果是XXX任务的队战溢出,则在checkStack的打印中,
XXX的堆栈状态会显示成“overflow”
2、可以使用
tt命令查看任务调用栈,通过分析调用栈的每一层函数,尝试找原因,参照上面的可能的原因部分
3、分析函数调用序列中所访问的全局变量(尤其是指针和数组),看是否存在任务抢占而导致全局指针被修改或者访问无效指针的问题。
3、重现问题,如果通过上述步骤无法直接找到原因,那么恭喜你,你已经遇到恐怖的随机内存改写问题,这类问题通常难
以重现,而且通过分析单个任务的运行轨迹很难找到原因,这类问题很可能的情况是:虽然任务A在运行函数FuncA时产生的
异常,但真正的内存改写代码很可能是在任务X或函数FuncX中,解决这类问题的关键是如何重现问题,一旦问题可以比较容易
的重现,那么可以说问题已经解决了一半。
重现问题的办法:
1、回忆先前的操作步骤,一步一步地重做一遍,看问题是否可以重现
2、如果是任务A产生的异常,则人工制造一些条件,使任务A不断的运行,以重现问题,通过脚本或者打桩,不断地发一些消息触发
任务A的运行,这是最常用的方法,如果A是周期运行,则缩短周期,加快运行
3、逆向分析,通过分析代码,可能怀疑一些代码有问题,这时候,可以针对性的创造各种人为条件来重现问题,例如怀疑某个定时
器可能存在重复进入和重复删除,则可以人为修改代码流程,使之进入定时器重复进入/重复删除流程,或者用脚本不断地创建和
删除定时器,以加快问题出现的频率
4、手动调整任务优先级,分析任务抢占相关的问题,在基本确定任务异常可能和任务抢占相关的情况下,可以尝试以各种组合,将几个
相关的任务优先级调整成相同的优先级(这样,这几个任务就不会再产生任务抢占了)。在此基础上尝试重现问题;如果在优先级相
同的情况下异常不再出现,则说明这几个任务之间所共享的变量存在互斥问题;否则说明该问题很可能和互斥无关,或者根据需要把
某些优先级调高,某些调低,以重现任务抢占的问题。
4、解决问题
1、如果找到料问题所在,则直接修改问题
2、如果通过多日的重现和定位,都无法找到真正的原因,那么没有办法的办法就是:直接修改代码,把怀疑有问题的地方全部改掉,
然后再测试看问题是否解决。
1、任务异常的一般表现
异常是分类型的,而且不同的CPU系统上是有区别的。常见的有PPC,DSI,还有ISI和Program等,具体看CPU的手册
2、可能的原因
memcpy/memset等函数 使用的长度超过所分配,导致改写了其他的指针。因此在定位异常问题过程中,可以通过内存
管理先查看一下先前是否有内存写越界的记录,但是 内存写越界只有在释放该内存区时才能检查到,如果该内存
没有被释放,则即使写越界也是不知道的。
异常;之所以异常往往是调 用了semTake返回就以为成功了,直接访问被信号量保护的资源)
比较典型的是:任务A和B都使用一个变量指针P;而A和B的优先级不同(即存在任务抢占),则他们在释放或者修改这个变量
指针的时候,可能会出现随机的异常访问问题。
3、处理策略
上串口或者Tornado,然后使用“ti”命令也可以看到如下的异常信息:
可以通过符号表知道异常出现时系统正在运行哪个函数, l 0x00187d4c和lkaddr 0x00187d4c
具体定位提示:
XXX的堆栈状态会显示成“overflow”
3、重现问题,如果通过上述步骤无法直接找到原因,那么恭喜你,你已经遇到恐怖的随机内存改写问题,这类问题通常难
以重现,而且通过分析单个任务的运行轨迹很难找到原因,这类问题很可能的情况是:虽然任务A在运行函数FuncA时产生的
异常,但真正的内存改写代码很可能是在任务X或函数FuncX中,解决这类问题的关键是如何重现问题,一旦问题可以比较容易
的重现,那么可以说问题已经解决了一半。
重现问题的办法:
任务A的运行,这是最常用的方法,如果A是周期运行,则缩短周期,加快运行
器可能存在重复进入和重复删除,则可以人为修改代码流程,使之进入定时器重复进入/重复删除流程,或者用脚本不断地创建和
删除定时器,以加快问题出现的频率
相关的任务优先级调整成相同的优先级(这样,这几个任务就不会再产生任务抢占了)。在此基础上尝试重现问题;如果在优先级相
同的情况下异常不再出现,则说明这几个任务之间所共享的变量存在互斥问题;否则说明该问题很可能和互斥无关,或者根据需要把
某些优先级调高,某些调低,以重现任务抢占的问题。
4、解决问题
然后再测试看问题是否解决。