死机分析¶
Solution提供开发过程中以及产品量产后的死机dump机制。
1. 死机分类¶
本平台上的死机主要分为两类:
ASSERT 断言,由
RT_ASSERT触发,在log 里会显示触发的函数名和行数。发生断言时,error_reason的值为RT_ERROR_ASSERT。HWFAULT CPU触发的硬件异常,常见有访问非法地址、非法指令等,在log 中会显示具体的异常类型,比如
bus fault、mem management fault、usage fault。发生硬件异常时,error_reason的值为RT_ERROR_HW_EXCEPTION。
2. 死机分析方法¶
针对死机,一般借助于log和死机现场进行分析。
log: 通常有执行流程、打印异常后死机原因(断言或HW Fault)、系统信息(线程状态、heap、ipc信息等)等。简单的死机是可以通过log直接进行定位的;
死机现场的分析可分为离线和在线分析:
离线分析:离线分析必须要有dump信息。死机后需要抓取dump,结合axf或elf文件,然后用trace32恢复现场来进行分析。
在线分析:使用
Ozone、j-link,使用调试器attach上被测设备, 查看全局变量、memory和寄存器。
死机分析相关介绍可以参见《SDK的文档死机分析指南》。
3. 工具获取¶
3.1 获取Sifli_Trace¶
该工具是思澈开发的log跟踪工具,支持多串口的同时log跟踪,支持finsh命令,集成死机dump以及支持使用DBGUART(52x/56x)模拟JLINK。
3.2 获取AssertDump¶
AssertDump集成在工具Sifli_Trace中。打开Sifli_Trace,在工具快捷栏点击DUMP图标,将打开AssertDump。
该工具是思澈开发死机dump工具,通过各种内置的脚本支持各种板级的死机dump,其中:
52x/56x: 支持通过UART的死机dump
55x/58x: 支持通过JLINK的死机dump
3.3 获取Sifli_UartServer¶
Sifli_UartServer集成在工具Sifli_Trace中。打开Sifli_Trace,在工具快捷栏点击DUMP图标,将打开Sifli_UartServer。
该工具是思澈开发死机使用DBGUART(52x/56x)模拟JLINK的工具。
3.4 获取Ozone¶
3.5 获取SiFli_ble工具¶
该工具集成了各种开放相关的测试验证功能,这里主要是使用该工具中的蓝牙dump死机信息。
4. 保存死机现场(抓dump)¶
死机现场的dump有两种情况,
4.1 开发时DUMP¶
通过连线(52x/56x使用串口;55x/58x使用JLINK)dump
55x/58x需要连接JLink仿真器到目标板(52x/56x不需要)
打开
AssertDump工具,设置dump的保存路径
选择芯片分类以及型号
选择设备(55x/58x选择JLINK, 52x/56x选择UART以及对应的波特率)
点击
导出
4.2 量产后DUMP¶
产品量产后,无法飞线抓取log和dump,Solution提供了死机自动保存机制(存放在预留的Flash空间中),使用SiFli_ble工具通过蓝牙dump死机信息
5. 死机现场恢复(Trace32)¶
5.1 准备¶
dump bin: 通过保存死机现场(抓dump)导出死机bin文件。把烧写到板子上对应工程的axf文件/elf文件(gcc编译环境) copy 到
dump bin的同一个目录
5.2 恢复现场步骤¶
5.2.1 运行t32marm¶
该文件的路径为\sdk\tools\crash_dump_analyser\simarm\t32marm.exe
5.2.2 HCPU现场的恢复¶
5.2.3 LCPU现场的恢复¶
参照HCPU现场的恢复,其中第1步选择LA。
5.2.4 恢复成功¶
恢复成功会自动打开以下窗口:
task list(任务列表)
heap allocation(内存概况,包含sys heap、memheap)
timer list(定时器列表)
task switch history(任务切换历史)
出错时的函数调用栈
error_reason(表示死机类型)。
5.2.5 恢复失败处理¶
恢复失败时(没有显示异常调用栈),可先确认是不是存在以下情况:
dump文件保存异常(比如0字节)。
axf/elf文件和当前异常机器的软件版本不对应(一般需要一次编译生成的)。
如排除以上情况,可能是保存异常,可以尝试以下几种方法:
从串口log里面打印的16个寄存器中,回填到trace32的register窗口中:

从Jlink halt的log信息加载现场栈。
HR(HCPU Registers)按钮/LR(LCPU Registers)按钮用于恢复没有走到异常处理程序的CPU寄存器,点击按钮后选择导出现场的log.txt文件,他将把里面的寄存器回填到trace32:
从
saved_stack_pointer/saved_stack_frame加载寄存器。
saved_stack_pointer/saved_stack_frame如果有保存值,可以将值对应回填到register窗口中:
如果是PC为空,

可以简单设置pc=lr(r14)来尝试查看函数调用关系:

6 常用命令(Trace32)¶
6.1 查看寄存器¶
菜单:View – Registers
命令窗口:B::Register
6.2 查看变量¶
菜单:View – Watch
命令窗口:B::Var.Watch
6.3 查看汇编¶
菜单:View – List Source
命令窗口:B::List symbol/address
6.4 查看内存¶
菜单:View – Dump
命令窗口:Data.dump address
7. 扩展脚本(Trace32)¶
7.1 switch_to.cmm¶
可用于切换task,命令格式:
do switch_to.cmm [task SP address]
7.2 show_running_app.cmm¶
可列出当前running app下的obj list,命令格式:
do show_running_app.cmm
8. 常见死机案例¶
8.1 断言¶
SF55X/56X都是双核,当一个核发生异常后,会通知另外一个核触发断言。
HCPU log 打印如下断言(下图是SF56x的打印,SF55x机制略有不同,会直接打印HCPU crash/LCPU crash),表示是LCPU先发生异常,需要分析LCPU状态(反之亦然):
LCPU log显示有发生断言,断言函数和所在行数都有打印。
使用trace32恢复LCPU现场,通过dump也可以看到断言位置:
8.2 HW Fault¶
查看log,显示在app_watch发生HW Fault:
恢复dump,error_reason = RT_ERROR_HW_EXCEPTION表示是发生了HW Fault(bus fault , 错误地址0x55AA1EC4)。可以从list窗口看到当前发生异常的位置:lv_obj.c line 3015发生异常。
obj=0x55AA1EA0,明显obj指向无效地址。明确基本原因和位置后,即可结合代码进一步定位。
8.3 内存泄漏¶
Solution内存管理方案在《SiFli-Solution内存管理介绍》中有专门介绍,此处不再赘述。当内存不足时,malloc会触发断言。异常后,可通过log、dump来确认当前内存使用情况:
不同的malloc接口使用的heap有所差异(常用rt_malloc是从sys heap申请内存),如确定对应heap的内存不足,可通过heap allocation窗口来是否存在泄漏以及可能泄漏点:
USED为1表示申请未释放,为0表示已经释放:
如下为例,可以看到有很多msg_handler申请的内存没有释放,基本可以确定泄漏,需要针对具体代码查看msg_handler申请的内存是不是有正常释放:
8.4 Data service 死机¶
data_send_proxy 断言, 对应的log和dump信息如下:


断言原因:data service发送队列满,超时(固定1s)断言。
如何确认data service存在发送队列满:
查看ipc_ctx.queues[4],这里最大支持同时active 4路,查看active状态的queue.tx_ring_buffer状态:
rd_idx_mirror和 write_idx_mirror的高16位相同、低16位不同时,表示队列满;rd_idx_mirror和 write_idx_mirror的高16位相同、低16位也相同时,表示队列空;
如下图,则存在queue队列满:

此类问题可能的原因:
发送频率过快,接收速度跟不上。比如,<1ms内的间隔快速发送,有可能导致发送超时。可能需要结合大小核串口log协助分析。
接收方发生异常,比如死机、硬件异常(例如静电打挂)等情况。
高优先级线程影响消息接收。