Crash 处理

本章节介绍在 WQ SDK 启动及运行中出现 Crash 后,如何通过 log 定位问题,包括 log 分析、BackTrace 分析、反汇编分析及 GDB 与 CoreDump 分析。

Log 分析

发生 crash 后, crash 相关信息会通过 LOG 通道输出。 WQ 下载调试工具接收的 log ,存放在工具软件目录下的 LogUART 文件夹中的 .log 文件。详细信息如下:

 [auto]crash_test.c:140 Asserted! //crash 发生的代码位置
 0x0412006e:0x020093f8 //crash 发生时,调用栈信息
 0x041179cc:0x02009438
 0x02005f10:0x02009448
 0x0412006e:0x00000000
 [auto]mcause: 0x03[Breakpoint] //assert 类型的 crash
 [auto]core0: exception registers dump //crash 发生在 core0
 ra = 0x0200005a
 sp = 0x020092b0
 t0 = 0x0000002a
 t1 = 0x00000000
 t2 = 0x00000023
 fp = 0x020093c8
 s1 = 0x02006970
 a0 = 0x00000000
 a1 = 0x000000d2
 a2 = 0x00000030
 a3 = 0x00e88f1f
 a4 = 0x00000002
 a5 = 0x00000000
 a6 = 0x02009158
 a7 = 0x20303030
 s2 = 0x02006970
 s3 = 0x04116000
 s4 = 0x00000000
 s5 = 0x00000001
 s6 = 0xa5a5a5a5
 s7 = 0xa5a5a5a5
 s8 = 0xa5a5a5a5
 s9 = 0xa5a5a5a5
 s10 = 0xa5a5a5a5
 s11 = 0xa5a5a5a5
 t3 = 0x00000039
 t4 = 0x00000009
 t5 = 0x0000002e
 t6 = 0x00000025
 0x0412006e:0x020093f8 //crash 发生时,调用栈信息
 0x041179cc:0x02009438
 0x02005f10:0x02009448
 0x0412006e:0x00000000
 [auto]mepc: 0x02000076, mbadaddr: 0x00000000 //crash 发生时的代码位置
 coredump_callback address: 0x0411 6c84
 Current task RA/SP/A0/FP/EPC 2000 05a 20092b0 0 20093c8 2000076
 Core dump len = 4192 (8 0)
 ================= CORE DUMP START =================
 YBAAAAEAAAAIAAAAfAAAAA==
 WJQAAjiEAAKkkgACSJQAAg==
 sJIAAiROAABQcwACUHMAAliUAAJIcwACC AAAAEvrlycWXxZ/WJQAAgAAAAAHAAAA
......

用户可以通过 mcause 判断 crash 类型,初步分析 crash 原因。表 5 1 列举了常见的 mcause 和相应的分析策略。

常见 mcause 与分析策略

mcause

carsh 原因

分析策略

0x8000000b

外部中断

外部中断可能导致 crash dump 的只有 watchdog timeout 中
断。因此,可以判定为代码存在死循环

1

数据访问异常

  • 中断服务函数代码在 Flash 里面,找到 mepc 即可。
    mepc 所在的函数必须加上IRAM TEXT(func xxxx)
  • 野指针数据访问。如果 mbadaddr 不是 Flash 的地址而
    是一个野指针,则需要根据汇编找到对应的变量,再进
    一步推测野指针产生的原因。

2

非法指令异常

首先根据 crash dump内容排查指令是否被修改。

  • 被修改:说明存在内存踩踏。

  • 未被修改:检查指令自身问题。

3

assert 对应的异常

同样看log 和 BackTrace 定位问题。

5

非对齐访问的异常

根据 mepc 定位代码和变量,一般都是地址不对齐导致的。

7

0地址访问对应的异常

根据上面的办法找到对应的变量和代码,推测 0 地址访问产
生的原因。

根据上文中的 mcause: 0x03 ,可以判断 Crash 原因为 assert 对应的异常。

BackTrace 分析

用户可以通过运行 BackTrace 命令查看调用栈信息,进而定位 Crash 原因。BackTrace 命令可以使用 WQ 下载调试工具运行或通过编译环境运行。

运行 BackTrace 命令需要 log 和相应 core 的 .elf 文件。ELF 文件在编译时生成,存放于 build 目录下相应 core 的文件夹中。如: /<SDK>/application/target_a/build/acore/target_a_acore.elf

使用 WQ 下载调试工具

用户可以使用 WQ 下载调试工具运行 BackTrace 命令,查看调用栈信息。操作步骤如下:

  1. 打开 WQ 下载调试工具,点击 LogDebug 菜单栏。

  2. 在左侧 LOG FILE 区域,选择 UART 输出的 .log 文件。

说明

WQ 下载调试工具接收的 log 存放于工具软件目录下的 LogUART 文件夹下的 .log 文件。

  1. 在左侧 APP ELF FILE 区域,选择发生 crash 的 core 所对应的 .elf 文件。

  2. 确保串口处于关闭状态。点击 START,即可生成调用栈信息。

../_images/SDK_5-1_log_debug.png

使用 BackTrace 命令

在编译环境下运行 BackTrace 命令可以查看调用栈信息。命令如下:

riscv64-unknown-elf-addr2line -f -e build/acore/target_a_acore.elf 0x0412006e:0x020093f8 0x041179cc:0x02009438 0x02005f10:0x02009448 0x0200005a:0x00000000

命令解析:

  • riscv64-unknown-elf-addr2line -f -e 为指令和参数。

  • build/acore/target_a_acore.elf.elf 文件相对路径。

  • 0x0412006e:0x020093f8 0x041179cc:0x02009438 0x02005f10:0x02009448 0x0200005a:0x00000000 为 Crash Log 中的栈调用信息。

输出结果如下:

crash_test
/wqcore/components/share_task_2/src/crash_test.c:141
app_entry
/wqcore/application/target_a/acore/app.c:221 (discriminator 3)
wrapper_task_func
/wqcore/os/os_shim/src/freertos_10_2_1/os_task.c:44
wq_debug_assert
/wqcore/components/wq_debug/src/wq_debug.c:608

查看反汇编

汇编文件可以用于 Crash 原因定位。

WQ SDK 编译时会在相应 core 的 .elf 文件目录下生成.asm 汇编文件,如 /<SDK>/application/target_a/build/acore/target_a_acore.asm 。 用户也可以通过 .elf 文件和反汇编指令生成汇编文件,方便排查定位故障。反汇编指令如下:

riscv64-unknown-elf-objdump -S -x target_a_acore.elf > target_a_acore.asm

GDB 与 CoreDump 分析

Log 中 "=== CORE DUMP START ===""=== CORE DUMP END ===" 之间的内容(不包含上述两行)为 CoreDump 信息。详细信息如下:

 ......
 Current task RA/SP/A0/FP/EPC 2000 05a 20092b0 0 20093c8 2000076
 Core dump len = 4192 (8 0)
 ================= CORE DUMP START =================
 YBAAAAEAAAAIAAAAfAAAAA==
 WJQAAjiEAAKkkgACSJQAAg==
 sJIAAiROAABQcwACUHMAAliUAAJIcwACC AAAAEvrlycWXxZ/WJQAAgAAAAAHAAAA
......
 7x6iiRJ1QtSefzCbz7Zzd9XaBM//nGsb3VEXELWWS7GOaIW74j9QmNww5zqssBvg
 e/dpClD6j9zc8AiMGnAcYESv5ejPgdHcNJJwqhaA4uRfqwWGKn481s+sNxJKvhU/
 yHitWLoqXhC7HmjaAAAAAAAAAAA=
 ================= CORE DUMP END =================

CoreDump 信息拷贝到一个文件中,重命名以 .b64 做后缀,如 coredump.b64

可以通过 wq_coredump.py 脚本执行 CoreDump 指令:

python3 tools/wq_coredump.py dbg_corefile --gdb ~/xxx/riscv64-unknown-elf-gdb -c dump/coredump.b64 -t b64 elf/xcore.elf

指令解析:

  • tools/wq_coredump.pycoredump 脚本路径

  • ~/xxx/riscv64-unknown-elf-gdbGDB 脚本绝对路径

  • dump/coredump.b64coredump 文件路径

  • elf/xcore.elf.elf 文件路径

执行完成后,进入 GDB 调试状态。可以执行一些 GDB 指令查看 backtrace(bt) 、thread 信息(info thread )、全局变量( p )等信息,如下图所示。

../_images/SDK_5-2_GDB_debug.png