ti-rtos 异常解密

cc2640r2f,mcu 2019-09-05 3602 次浏览 次点赞


ti-rtos 异常解密

详细介绍基于ti-rtos高级调试组件rov用以cc1310/cc2640 等sdk异常主动调试。

I. 异常现象

正常的,程序会进入IDLE模式,程序会停留在(0x10001486),也就是IDLE模式;

通常的,在我们完成我们程序功能时候,不可避免会遇到程序运行至一个死循环。如下图所示:

这个时候,我们要考虑程序异常了。

II. 解密异常

提示:更多可以参考如下。
  • swcu117d-CC13xx, CC26xx SimpleLink Wireless MCU Technical Reference Manual.pdf
  • swru393c-CC2640 and CC2650 SimpleLink Bluetoothlow energy Software Stack 2.2.0.pdf ->Chapter 9.8 Deciphering CPU Exceptions Page.157
  • http://docs.leconiot.com/cc2640r2f/debugging

导致异常的原因可以在 View->Registers CFSR寄存器的CPU_SCS 组中确定。最常见的异常有以下几个原因:

  • 栈溢出;
  • NULL 空指针被写操作应用;
  • 外设模块在没有供电的情况下操作;

对于任务栈溢出,我们可以通过TI-RTOS->Task->Detailed 分析任务栈使用情况。但是IAR这里报错了。

ROV detected errors in scan of 'Detailed' tab for module ti.sysbios.knl.Task.

通过TI-RTOS->BIOS->scan for errors...

不难看出这里有个任务异常了,有两个任务堆栈溢出了。
通过 TI-RTOS->Task->Basic 确定这两个任务为优先级7和3。

也就是程序中的

    UartTaskCreate(3);
    Task_Handle radioHandle = RadioTaskCreate(7); 

我们尝试将这两个任务的任务堆栈给增加;
再次通过TI-RTOS->Task->Detailed 查看任务细节,我们能够清楚分析每个任务的堆栈使用情况,同时可以通过以此来优化任务堆栈,多退少补。

符号意义
address任务Handle 地址;
lable任务标号,用以区分任务
priority任务优先级
mode任务当前运行状态 blocked阻塞,通过后面blockOn 对应阻塞于哪个事件、信号等;
fxn任务运行函数
arg0任务函数参数0
arg1任务函数参数1
stackpeckpeak(山峰,最高点),这里stackpeak表示当前任务堆栈的最大使用情况,可以依据该值对任务堆栈 stacksize进行优化,多退少补,已达到最佳优化效果。
stackSize程序分配的任务堆栈大小
stacBase任务堆栈的基地址、首地址
curCoreId
affinityaffinity-密切关系,姻亲关系 The core which this task is to run on. Default is Task_AFFINITY_NONE
blockedOnblock对应,表示当前任务阻塞状态下的阻塞事件。

III. 主动调试

借助IAR CSPY和CCS ROV控件 这里尝试调试这些异常,我们在Main函数完成实现以下代码,不难发现这里直接对NULL指针进行操作,那么程序发生什么现象呢?,IDE又会告诉我们什么信息呢?

    int * a=NULL;
    *a =100;

TI_ROS->Hwi->Exception


从上面的ROV 信息显示来看,在Main函数里发生了IMPRECISERR异常错误,而该错误正是我们的NULL指针被操作以前的。

IV. 异常记录

Undefined HWI 20

10/4/2016 10:27:39 AM
今天发现Undefined HWI 20 是由于任务数量超过4引起的。

  • 尝试更改系统堆栈
define symbol __ICFEDIT_size_cstack__ = 0x1000;
define symbol __ICFEDIT_size_heap__   = 0x1000;
  • 尝试更改cfg 有关于number的配置参数,其中包括
/*
 * Reduce the number of swi priorities from the default of 16.
 * Decreasing the number of swi priorities yields memory savings.
 */
Swi.numPriorities = 16;

终于确定现象了,但是还需要进一步分析具体原因,我们得先从RAM的存储结构说起

  .bss                    zero     0x20003eda     0x1  TxWorkerTask.o [1]
  .bss                    zero     0x20003edb     0x1  driverlib_release.o [7]
                                 - 0x20003edc  0x3234

"A4":                                          0x1000
  CSTACK                           0x20004000  0x1000  <Block>
    CSTACK                uninit   0x20004000  0x1000  <Block tail>
                                 - 0x20005000  0x1000

以上是编译后存储map文件。大概结构图如下:

RAM备注
固定地址用以存放固定地址的变量
data已初始化的变量
bss未初始化变量
未知区域就是这个未知的大小引起程序跑飞
castak栈空间大小

在以上图示的未知区域,前面是程序中变量大小决定,后面CStack栈空间大小是有编译器配置。但是现在看来中间必须保留一个余量用以其他用途,否则这里会出现运行时程序异常。从IAR的存储空间来观察,这里用以一个 “??PageIndex”

尝试将以上未知区域尽可能放大,上电发现这部分占用 0x200040BC-0x20004300=578 也就是我们RAM占用不能超过 20*1024-578=19902 实际测试这部分在

  46 187 bytes of readonly  code memory
   8 002 bytes of readonly  data memory
  19 605 bytes of readwrite data memory
  46 187 bytes of readonly  code memory
   8 004 bytes of readonly  data memory
  19 613 bytes of readwrite data memory

空闲在20480-19605 =875
从IAR上面来看,这里是存放一部分代码,具体功能暂时还不知道。
代码解析
10/4/2016 7:01:45 PM
又要新发现,凡是HWI类型异常可以通过IAR TI-RTOS->Hwi->Detailed确定当前激活的中断;

Decoded : Hard Fault:FORCED:BUSFAULT:PERECISERR.Data Access Error.ADdress =0xc27101fa

10/4/2016 7:20:36 PM

Hard Fault:FORCED:BUSFAULT:PERECISERR.Data Access Error.ADdress =0xc27101fa 
threadType:Hwi
threadHandle:unkonwn


激活中断为

Hard Fault:FORCED:BUSFAULT:IMPRECISERR

12/22/2016 3:13:20 PM


ThreadType 为Task
ThreadStack 表示异常任务的基地址,对应

Decoded : Hard Fault: FORCED:BUSAULT:PRECISERR.Data Access Error.Address =0x20005000

12/23/2016 4:40:58 PM

Decoded : Hard Fault: FORCED: BUSAULT:PRECISERR.Data Access Error.Address =0x20005000
threadType:Task
threadHandle:0x20003ae0

确定为Scif_task.c,然后通过断点确定在SPI 打开的时候异常。

//SPI_open - CY15B104Q_Init in CY15B104Q.c (g:\mycode\...\board)  Line 156
spiHandler=SPI_open(Board_SPI0,&spiParams);

这里基本已经知道优化内存的时候把SPI相关变量spiCC26XXDMAHWAttrsSPI_configCC1310DK_7XD给注释掉了,以为用不上SPI。但是我再确定是否还能够从TI-RTOS ROV组件获取更多信息。

Decoded :Hard Fault:FORCED:BUSFAULT:PERECISERR.Data Access Error.Address =0xa0760000

1/3/2017 10:11:42 AM

threadType : swi
threadStack: 0x20002f4c
threadStateSize : 0xc04

最后确定这里是数组操作越界

Decoded :Hard Fault:FORCED:BUSFAULT:PERECISERR.Data Access Error.Address =0xbebebebe

threadType : Task
threadStack: 0x20003c30
threadStateSize : 0x300

今天又有新发现,异常的时候可以通过PC指针确定异常代码的位置,比如该错误,通过TI-RTOS->hwi->Exception 我们能够知道 当前PC指针值;

R0 : 0xbebebebe
PC : 0x1001c5f8 

分析这个位置代码:

xdc_runtime_Core_assignParams__I:
   0x1001c5ec: 0xe92d 0x43f8  PUSH.W    {R3-R9, LR}
   0x1001c5f0: 0x4604         MOV       R4, R0
   0x1001c5f2: 0xf8d1 0x800c  LDR.W     R8, [R1, #0xc]
   0x1001c5f6: 0x6808         LDR       R0, [R1]
   0x1001c5f8: 0xf8d8 0x6000  LDR.W     R6, [R8]
   0x1001c5fc: 0x461d         MOV       R5, R3
   0x1001c5fe: 0x4617         MOV       R7, R2
   0x1001c600: 0xeba7 0x0905  SUB.W     R9, R7, R5
   0x1001c604: 0x464a         MOV       R2, R9
   0x1001c606: 0x1b80         SUBS      R0, R0, R6
   0x1001c608: 0x4282         CMP       R2, R0

我们不难猜出,这里在对一个参数进行校验,而此时的R0寄存器值正好为我们的异常地址值0xbebebebe。因为以上汇编代码为ROM空间代码,所以我们怎么通过他定位到出错位置的我们应用层代码呢?
我们再通过TI-RTOS->hwi->Exception SP指针分析出错前的压栈值;

SP : 0x20002528
   0x200024c8: 0x00003ff0     DC32      0x3ff0 (16368)
   0x200024cc: 0x0000ca17     DC32      0xca17 (51735)
   0x200024d0: 0x1001a02a     DC32      0x1001a02a (268541994)
   0x200024d4: 0x21000000     DC32      0x21000000 (553648128)
   0x200024d8: 0x200028c8     DC32      0x200028c8 (536881352)
   0x200024dc: 0x200028c8     DC32      0x200028c8 (536881352)
   0x200024e0: 0x00000000     DC32      0x0 (0)
   0x200024e4: 0x00000000     DC32      0x0 (0)
   0x200024e8: 0xe000e000     DC32      0xe000e000 (-536813568)
   0x200024ec: 0x0000000d     DC32      0xd (13)
   0x200024f0: 0x20003fd4     DC32      hwiTaskAlert
   0x200024f4: 0x20002530     DC32      0x20002530 (536880432)
   0x200024f8: 0x00000000     DC32      0x0 (0)
   0x200024fc: 0x1001a43f     DC32      0x1001a43f (268543039)
   0x20002500: 0x00000000     DC32      0x0 (0)
   0x20002504: 0x0000001d     DC32      0x1d (29)
   0x20002508: 0x0000bb19     DC32      osalTaskAlertIsr
   0x2000250c: 0x20002530     DC32      0x20002530 (536880432)
   0x20002510: 0x00000008     DC32      0x8 (8)
   0x20002514: 0xfffffffd     DC32      0xfffffffd (-3)
   0x20002518: 0x20002598     DC32      0x20002598 (536880536)
   0x2000251c: 0x00001270     DC32      ti_sysbios_knl_Clock_Object__DESC__C
   0x20002520: 0x00000000     DC32      0x0 (0)
   0x20002524: 0x200025d0     DC32      0x200025d0 (536880592)
   0x20002528: 0xbebebebe     DC32      0xbebebebe (-1094795586)
   0x2000252c: 0xffffffff     DC32      0xffffffff (-1)

因为栈是向下生长型,我们分析栈历史录,发现这里进行了一次ti_sysbios_knl_Clock_Object__DESC__C 函数压栈。结合刚刚更改代码增加了对语音数据发送超时,已经能够大概知道出错位置,但是我们再次尝试深入挖掘。
最后确定为构造始终的时候Clock_construct,这里传入了一个NULL指针,其中clockObj 为0;

    Clock_construct(Clock_struct(clockObj), ClockCBFxn, SC_VOICE_TX_TIMEOUT, &clockParams);

程序停在0x1001c482


从死循环位置的最近的标号来看是在创建什么资源。

TI-RTOS->HeapMem->Detailed来看,可能存在堆分配溢出。
1/2/2017 12:07:57 PM
Concentrator再次出现改情况,可以断定的是,Concentrator在连续收到Node的语音程序后进入该异常。

Decoded : Hard Fault: FORCED:BUSFAULT:IMPRECISERR

12/25/2016 4:28:03 PM

threadType : Swi
htreadHandle : 0x20000914

通过对应TI-RTOS->Task->Detailed分析整个程序运行的逻辑,定位到UartTask被Create了两次。
12/26/2016 3:47:52 PM

threadType :  Hwi
threadHandle : 0x20030c0

对于Hwi错误,可以通过 TI-RTOS->Hwi->Detailed找到以上threadHandle 对应的中断服务程序;

static void ScifCtrlReadyCallback(void) {
    Event_post(scifTaskEnv.hEvnt, EVT_TASK_SIGNAL | EVT_SCIF_CTRL_READY);
}

程序直接停在了0x1001b986

10/18/2017 4:26:26 PM

日了狗了,程序直接停在了这里。

Target memory read failed at address: 0x20002b9c, length: 76
This read is at an INVALID address according to the application's section map. The application is likely either uninitialized or corrupt.

通过Rov->Hwi->Exception 居然扫描不出来错误,最后通过排除法大概确定是IO冲突,怀疑是操作了一个被初始化成串口的TX的IO进行Input 读操作,或者是把串口的TX重新初始化成了输入。


本文由 Jay 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处,点赞9

还不快抢沙发

添加新评论