Edit online

Backtrace 栈回溯

3 Mar 2025
Read time: 4 minute(s)

Luban-Lite 提供 Backtrace 及解析功能,便于开发者准确定位软件调试中出现的系统崩溃问题,例如内存访问越界。在系统创建线程时,会分配栈内存空间,通过分析运行时栈内存的结构,逐层解析函数调用的历史记录,从而定位出软件异常的问题点。

本节适用于以下芯片系列:
  • D21x
  • D13x
  • D12x
  • G73x

栈回溯功能的相关工具均已包含在最新 SDK 中,确保已更新至最新的 SDK。

注: 在 Luban-Lite 中,Backtrace 及解析功能仅用于调试 RT-Thread 的多线程,无法用于调试 BootLoader。

Backtrace 配置方法

在 menuconfig 中开启 Backtrace debug 功能,并修改编译链接脚本以支持栈回溯,以便在发生系统异常时打印出函数调用地址。详细配置流程如下所示:
注: 为避免量产软件的性能受影响,确保在量产软件中关闭 backtrace。
  1. 在 SDK 的 menuconfig 功能配置界面,选择项目的 RT-Thread 配置页,并打开 Backtrace 调试功能:
     Drivers options --->
        Drivers debug
                [*] Enable Backtrace debug
  2. 保存并退出配置界面。
  3. 修改编译链接脚本以支持栈回溯:
    • 在项目对应芯片目录中打开编译链接脚本,例如 D12x/bsp/artinchip/sys/d21x/rtconfig.py
    • 将 BACKTRACE = False 修改为 BACKTRACE = True:
    ...
    # BACKTRACE = True
    BACKTRACE = False
    ...
  4. 保存文件并关闭编辑器。

实例分析

以下是一个制造非法内存访问的示例代码,用于演示如何生成和解析栈回溯信息:

  1. 在 SDK 中加入下列代码进行编译、烧录:
    注:

    如需使用栈回溯,务必保证镜像和生成的 elf 文件对应,即编译一次、烧录一次、分析一次。

    此段代码尝试写入一个空指针地址,导致存储访问故障。

    int stack_protector_test(int argc, char **argv)
    {
        int * p = NULL;
        p = (int *)0x80000000;
        *p = 0x12345678;
        value = *p;
        printf("addr:%p value:0x%08X\r
    ", p, value);
        return 0;
    }
    MSH_CMD_EXPORT(stack_protector_test test stack protector test test test test)
    
  2. 系统运行后,执行下列命令,并观察串口终端输出的错误信息和堆栈回溯:
    stack_protector_test
    串口终端的系统输出示例如下所示:
    CPU Exception: NO.7
        x1: 4002bf64    x2: 30066270    x3: 30042d8c    x4: deadbeef
        x5: 80007880    x6: 300662b4    x7: deadbeef    x8: 00000014
        x9: 30064212    x10: 00000001   x11: 80000000   x12: 12345678
        x13: 00000000   x14: 30064226   x15: 80000000   x16: 30064226
        x17: fffffffd   x18: 400461ae   x19: 400bddf8   x20: 40155fb8
        x21: 400bdf30   x22: 0000007f   x23: 30044d04   x24: 20636961
        x25: 400c45d4   x26: 300641c2   x27: 30064212   x28: 00000022
        x29: 0000005c   x30: 0000000a   x31: deadbeef
        mcause : 0x38000007
        mtval  : 0x00000000
        mepc   : 0x400461c4
        mstatus: 0x80007880
    
        __stext:0x40000000 __etext:0x400bdfe0,stack:
        stack_addr:0x30064330 stack_addr_end:0x30066330
        0x0000007f 0x00000009 0x400c45c8 0x4002bf64
        0x0000001b 0x30044d8c 0x30064212 0x00000000
        0x00000000 0x00000000 0x00000000 0x00000000
        0x00000000 0x00000000 0x00000000 0x00000000
        0x0000007f 0x00000009 0x400c45c8 0x000000fd
        0x0000001b 0x30044d8c 0x30064190 0x4002b9c0
        0xdeadbeef 0xdeadbeef 0x00000000 0x30064190
        0xdeadbeef 0xdeadbeef 0xdeadbeef 0x0dadbeef
        0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef
        0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef
        0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef
        0xdeadbeef 0xdeadbeef 0xdeadbeef 0x4001a874
    
    
        [backtrace_call_stack:123]__stext:0x40000000 __etext:0x400bdfe0
        0x400461c4
        0x4002bf64
        0x4002b9c0
        0x4001a874
  3. 将串口终端的输出信息保存为 txt 文本,并使用 panic_parse.py 进行解析。

    假设 backtrace 信息保存在根目录中,保存的输出示例 txt文件为 kunlunpi-panic.txt,则在 SDK 根目录执行如下操作命令:
    python3 tools/scripts/panic_parse.py -l ./kunlunpi-panic.txt
  4. 查看解析后的输出,确定导致异常的具体函数位置。
    解析结果示例如下,分析文件指明了函数调用的关系和导致异常的函数具体位置:
    CPU: RISC-V
        ELF: output/d13x_kunlunpi88-nor_rt-thread_helloworld/images/d13x.elf
        Toolchain: riscv64-unknown-elf
        Text section: 0x40000000 - 0x400bdfe0, size: 778208 Bytes
    
        ---------------------------------------------------------------
        CPU Registers:
        ---------------------------------------------------------------
        CPU Exception: 7 (Store/AMO Access Fault)
        x1 (ra): 0x4002bf64 _msh_exec_cmd at kernel/rt-thread/components/finsh/msh.c:294
        x2 (sp): 0x30066270
        x3 (gp): 0x30042d8c
        x4 (tp): 0xdeadbeef
        x5 (t0): 0x80007880
        x6 (t1): 0x300662b4
        x7 (t2): 0xdeadbeef
        x8 (s0/fp): 0x00000014
        x9 (s1): 0x30064212
        x10 (a0): 0x00000001
        x11 (a1): 0x80000000
        x12 (a2): 0x12345678
        x13 (a3): 0x00000000
        x14 (a4): 0x30064226
        x15 (a5): 0x80000000
        x16 (a6): 0x30064226
        x17 (a7): 0xfffffffd
        x18 (s2): 0x400461ae stack_protector_test at packages/artinchip/lvgl-ui/aic_ui.c:64
        x19 (s3): 0x400bddf8 __console_init_start at ??:?
        x20 (s4): 0x40155fb8
        x21 (s5): 0x400bdf30 __fsymtab_end at ??:?
        x22 (s6): 0x0000007f
        x23 (s7): 0x30044d04
        x24 (s8): 0x20636961
        x25 (s9): 0x400c45d4
        x26 (s10): 0x300641c2
        x27 (s11): 0x30064212
        x28 (t3): 0x00000022
        x29 (t4): 0x0000005c
        x30 (t5): 0x0000000a
        x31 (t6): 0xdeadbeef
        mcause: 0x00000000
        mtval: 0x00000000
        mepc: 0x00000000
        mstatus: 0x00000000
    
        ---------------------------------------------------------------
        Call Stack:
        ---------------------------------------------------------------
        Stack section: 0x30064330 - 0x30066330, size: 8192 Bytes
        0: [0x4002bf64] _msh_exec_cmd at kernel/rt-thread/components/finsh/msh.c:294
        1: [0x4002b9c0] finsh_thread_entry at kernel/rt-thread/components/finsh/shell.c:657
        2: [0x4001a874] _thread_exit at kernel/rt-thread/src/thread.c:91