RT-Thread使用CmBacktrace进行HardFault_Handler 追踪

大家在用STM32的时候有没有遇到过HardFault的问题呢:

======001

下面针对这个问题做个小总结。

现象还原:在debug模式下进行仿真调试,全速运行再停止运行,程序会跑到 HardFault_Handler函数中,产生 HardFault,即硬错。其产生的原因大概有如下几类:

(1)数组越界操作;

​ (2)内存溢出,访问越界;

​ (3)堆栈溢出,程序跑飞;

​ (4)中断处理错误;

针对HardFault问题的定位,网上有几种方法,大概都是围绕着:在debug模式下,查看一些地址,分析寄存器、函数调用栈等,这是很让人头疼的事情。这里分享一种简单的、直观的HardFault错误定位的方法,使用开源库:CmBacktrace 。这个库之前已经有介绍过了,这篇笔记我们来实践一下。

CmBacktrace 源码地址:

https://github.com/armink/CmBacktrace

======002

下面说下使用方法,具体使用方法如下:

一、把cm_backtrace文件夹复制到我们的工程目录下,并添加至keil工程中,并添加头文件、勾选C99模式

此时,编译会产生几个错误:
======005

那是因为有些预处理宏没有找到,打开、修改cmb_cfg.h文件的内容。cmb_cfg.h文件默认内容为:(我是使用RT-Thread  带系统的)

#ifndef _CMB_CFG_H_
#define _CMB_CFG_H_

/* print line, must config by user */
#define cmb_println(...)        rt_kprintf(__VA_ARGS__);rt_kprintf("\r\n") /* e.g., printf(__VA_ARGS__);printf("\r\n") */
/* enable bare metal(no OS) platform */
/* #define CMB_USING_BARE_METAL_PLATFORM */
/* enable OS platform */
#define CMB_USING_OS_PLATFORM 
/* OS platform type, must config when CMB_USING_OS_PLATFORM is enable */
#define CMB_OS_PLATFORM_TYPE           CMB_OS_PLATFORM_RTT //or CMB_OS_PLATFORM_UCOSII or CMB_OS_PLATFORM_UCOSIII or CMB_OS_PLATFORM_FREERTOS */
/* cpu platform type, must config by user */
#define CMB_CPU_PLATFORM_TYPE        CMB_CPU_ARM_CORTEX_M4  /* CMB_CPU_ARM_CORTEX_M0 or CMB_CPU_ARM_CORTEX_M3 or CMB_CPU_ARM_CORTEX_M4 or CMB_CPU_ARM_CORTEX_M7 */
/* enable dump stack information */
/* #define CMB_USING_DUMP_STACK_INFO */
/* language of print information */
#define CMB_PRINT_LANGUAGE            CMB_PRINT_LANUUAGE_ENGLISH // CMB_PRINT_LANGUAGE_ENGLISH(default) or CMB_PRINT_LANGUAGE_CHINESE */
#endif /* _CMB_CFG_H_ */

二、在使用了本库提供的 cmb_fault.s 汇编文件时,因为该汇编文件内部已经定义了 HardFault_Handler ,所以如果项目中还有其他地方定义了该函数,则会提示 HardFault_Handler 被重复定义的错误。此时有两种解决方法:

  • 1、注释/删除其他文件中定义的 HardFault_Handler 函数,仅保留 cmb_fault.s 中的;(我用的是stm32f302,注释代码如下)将context_rvds.S中最后的HardFault_Handler 注释掉,注意保留最后的END
  • ; compatible with old version
    rt_hw_interrupt_thread_switch PROC
        EXPORT rt_hw_interrupt_thread_switch
        BX      lr
        ENDP
    
        IMPORT rt_hw_hard_fault_exception
        ;EXPORT HardFault_Handler
    ;HardFault_Handler    PROC
    
        ;; get current context
        ;MRS     r0, psp                 ; get fault thread stack pointer
        ;PUSH    {lr}
        ;BL      rt_hw_hard_fault_exception
        ;POP     {lr}
    
        ;ORR     lr, lr, #0x04
        ;BX      lr
        ;ENDP
    
        ;ALIGN   4
    
        END

  • 2、将 cmb_fault.s 移除工程,手动添加 cm_backtrace_fault 函数至现有的故障处理函数,但需要注意的是,务必 保证该函数数入参的准备性 ,否则可能会导致故障诊断功能及堆栈打印功能无法正常运行。所以如果是新手,不推荐第二种解决方法

三、可能会有提示uint32_t重复定义的错误,这个问题可能不太好找。原因是cmb_def.h中引用了arm中的stdint.h和工程里的stdint.h中同时定义了uint32_t,解决方法为:将#include <stdint.h>改为#include "stdint.h"即可,具体可以研究下include<>与include“”的区别。

四、将一下两行代码 放在void init_thread_entry(void* parameter)中进行初始化。   

  cm_backtrace_init("CmBacktrace", HARDWARE_VERSION, SOFTWARE_VERSION);

 /* set exception hook */
  rt_hw_exception_install(exception_hook);    ‘

同时需要hook函数,如下:

#define HARDWARE_VERSION               "V1.0.0"
#define SOFTWARE_VERSION               "V0.1.0"

static rt_err_t exception_hook(void *context) {
    extern long list_thread(void);
    uint8_t _continue = 1;

    rt_enter_critical();

#ifdef RT_USING_FINSH
    list_thread();
#endif

    cm_backtrace_fault(*((uint32_t *)(cmb_get_sp() + sizeof(uint32_t) * 8)), cmb_get_sp() + sizeof(uint32_t) * 9);

    while (_continue == 1);

    return RT_EOK;
}

至此工程已经配置完毕并且可以编译通过了​​​,我们可以人为制造一个HardFault,比如使用一个没有初始化的信号量。这时候运行程序会有如下的串口打印出来:

Firmware name: CmBacktrace, hardware version: V1.0.0, software version: V0.1.0
Fault on thread uart1_rx€
=================== Registers information ====================
  R0 : 200027ac  R1 : 20001a2c  R2 : 00000000  R3 : 00008000
  R12: 00000000  LR : 0800438f  PC : 080056f8  PSR: 41000000
==============================================================
Bus fault is caused by imprecise data access violation
Show more call stack info by run: addr2line -e CmBacktrace.axf -a -f 080056f8 0800438e 0800456a 08000a0e 

五、

可以看到,列出的信息很详细,包括出错原因。按照它的提示,我们运行命令:

addr2line -e CmBacktrace.axf -a -f 080056f8 0800438e 0800456a 08000a0e

运行这个命令需要用到addr2line.exe工具,这个工具在CmBacktrace源码目录下的tools文件夹中:

======013

======014

在这个文件中进入到cmd窗口,方法:按下Shift键的同时点击鼠标右键:
======015

运行上面那条命令:
======016

但是win10按住shift右键打开控制台运行这个会有问题,因为我们可以写一个bat脚本来运行:

addr2line.exe -e STM32F302_B0.axf -a -f 080056f8 0800438e 0800456a 08000a0e 

pause

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值