dump 死机调试指南
本节介绍发生死机后如何导出现场并恢复,所用工具以 Trace32 为主。
Dump 内存方法
Trace32 恢复与解析
用 Trace32 恢复 HCPU 死机现场
参照上文的导出方法将导出的内存文件和对应的 axf 放到同一目录。更加详细的死机现场保存方法可以查看保存现场方法
运行
SIFLI-SDK/tools/crash_dump_analyser/simarm/t32marm.exe工具。如下图:

打开工具后选择 HCPU assertion(HA)进行恢复。如果某些 bin 文件不存在(例如没有 PSRAM2),可取消勾选对应文件。

点击 “run_next_step” 加载,加载完成后会显示现场信息:

如果内存与地址映射建立成功,可参考芯片手册的 Memory 地址空间查看现场。如果未恢复,请检查 bin 是否有效,或通过修改 jlink/dump 脚本增加或减少需要 dump 的地址空间(例如
sf32lb55x.jlink)。

在 Window 菜单中可以切换不同显示窗口。

B::v.f /l /c 窗口是死机现场的函数调用栈
heapAllocation 窗口显示了系统中所有 heap pool 的分配情况,包括 system heap 以及各 memheap_pool:
system heap:
rt_malloc和lv_mem_alloc使用的池各
memheap_pool:由rt_memheap_init创建,分配/释放使用rt_memheap_alloc/rt_memheap_free
分配信息字段含义:
BLOCK_ADDR: 分配的内存块的起始地址,包括管理项
BLOCK_SIZE: 申请的内存大小,不包括管理项长度
USED: 是否已分配,1 表示已分配,0 表示未分配
TICK: 申请时间,单位为 OS tick(通常 1 ms)
RETURN ADDR: 申请者地址
现场未显示异常栈的处理
如果无法显示死机时的调用栈,可能是 dump 中未保存寄存器或保存异常。可尝试以下方法:
从 J-Link halt 的 log 信息加载现场寄存器(HR / HCPU Registers)。点击相应按钮,选择导出的
log.txt,工具会将其中 HCPU 的寄存器回填到 Trace32。

手动将 log 中打印出的 16 个寄存器值回填到 Trace32 的寄存器窗口(ARM 寄存器对应关系:SP <-> R13,LR <-> R14,PC <-> R15)。

gcc编译的可以尝试将PC修改成和r14的值一样
在自动恢复现场不成功时,也可以直接按照 hardfault 现场手动恢复。恢复死机现场中断发生时(hardfault 也是中断)的中断函数:
HardFault_Handler->rt_hw_hard_fault_exception->handle_exception
函数内会把寄存器 R0-R4、R12、R14(LR)、PC 压栈到 saved_stack_frame 和 saved_stack_pointer 变量中。

压栈的寄存器可以看下图二。如下图一的死机现场,地址 0x20054998 上是 R0,地址 0x200549AC 是 LR,地址 0x200549B0 是 PC: 0x10CD6602。
寄存器 PC:存放死机前的程序 PC 指针。
寄存器 LR:存放程序执行完要返回的程序指针。
全局变量
saved_stack_pointer存的是压栈的基地址。全局变量
saved_stack_frame存的是压栈的数据。

在 hardfault
RT_ERROR_HW_EXCEPTION死机的情况下,要特别留意出问题的 PC 汇编指令,考虑是否出现异常地址或异常指令,如下图:

用 Trace32 恢复 LCPU 死机现场
LCPU 恢复与 HCPU 类似,需将 lcpu.axf 和对应的 rom_axf 文件拷贝到脚本目录中:

注意:
Keil 编译生成的 LCPU 文件后缀为
.axf,GCC 编译生成的为.elf。
选择
rom_axf时请根据板子型号选择正确文件 。


打开 Trace32 并选择 LA(LCPU assertion)执行对应配置:

Trace32 常用脚本与命令
常用查看命令:
L <addr>:例如L 0x10063c,查看某处 PC 对应源码或反汇编。v.v *:打开变量窗口,支持通配符搜索全局变量。data.dump <addr>:查看内存地址。frame /locals /caller:查看调用栈与局部变量。在控制台输入
(struct rt_pm *)0x101fa2b9可把内存按结构体格式解析。
系统状态内置脚本(使用 do 运行):
do show_tasks:显示系统中所有线程及状态、栈地址和优先级。do switch_to 0x200A2F7C:在不同线程栈间强制切换上下文。do show_timer/do show_switch_history:查看定时器队列与线程切换历史。

Heap 分析示例
下图为检测到 heap 泄漏的现场:callstack 窗口显示断言处的调用栈,heapAllocation 窗口的 system heap 列表显示由 rt_malloc 申请的内存块,RETURN ADDR 为调用 rt_malloc 的函数地址,TICK 为申请时间(rt_tick_get)。

System heap 管理项结构示意:第一个 uint16 为特殊标记 0x1EA0,若被修改则表示被非法改写;第二个 uint16 为 used 标志,1 表示已分配,0 表示未分配,其他值意味着内存项被破坏。

例如地址 0x200A27EC 的内存块由 rt_serial_open 前的指令申请,申请大小为 4108 字节。System heap 管理项长度为 28 字节,因此实际使用地址为 block_addr + 28。
在出现内存泄漏时,可结合申请者地址与申请时间定位未释放代码位置。
