简介
CmBacktrace 是一个轻量级、跨平台针对CoretexM架构的开源嵌入式软件崩溃堆栈跟踪库。它通过捕获程序崩溃时的寄存器值并解析函数调用栈,帮助开发者快速定位问题。主要特点包括低内存占用、支持多种平台、易于集成、提供详细的堆栈信息,以及灵活配置。使用步骤包括初始化库、捕捉崩溃信息并解析堆栈。CmBacktrace 适用于调试崩溃问题、异常监控和质量保证,显著提高了嵌入式系统开发中的调试效率
CmBacktrace 移植适配
CmBacktrace 软件包可以从github 获取,可以从该地址获取(https://github.com/armink/CmBacktrace),最新的代码已经支持了Cortex-M33架构,这就意味着我们不需要额外的适配工作直接就可以用起来。
将源代码加入工程
本地使用的开发环境为IAR,我们把cm_backtrace.c 及cm_backtrace\fault_handler\iar\cmb_fault.S加入编译即可。
因为cmb_fault.S 实现了hard fault 的中断入口函数,如果工程内有默认的hard fault 函数需要删除或者weak 处理使用cmb_fault.S 文件的入口函数,本地将默认的weak 处理了。
适配threadx 系统
本地使用的系统为Threadx 系统,最新的代码还没有适配支持,只需要修改以来系统的获取单前任务信息的处理即可。
--- a/stm32cube_fw_h5_v120/STM32Cube_FW_H5_V1.2.0/Middlewares/Third_Party/cm_backtrace/cm_backtrace.c
+++ b/stm32cube_fw_h5_v120/STM32Cube_FW_H5_V1.2.0/Middlewares/Third_Party/cm_backtrace/cm_backtrace.c
@@ -214,6 +214,11 @@ static void get_cur_thread_stack_info(uint32_t *sp, uint32_t *start_addr, size_t
osRtxThread_t *thread = osRtxInfo.thread.run.curr;
*start_addr = (uint32_t)thread->stack_mem;
*size = thread->stack_size;
+#elif (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_THREADX)
+ TX_THREAD * ptThread = NULL;
+ TX_THREAD_GET_CURRENT(ptThread);
+ *start_addr = (uint32_t)ptThread->tx_thread_stack_start;
+ *size = ptThread->tx_thread_stack_size;
#endif
}
@@ -244,6 +249,10 @@ static const char *get_cur_thread_name(void) {
return vTaskName();
#elif (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_RTX5)
return osRtxInfo.thread.run.curr->name;
+#elif (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_THREADX)
+ TX_THREAD * ptThread = NULL;
+ TX_THREAD_GET_CURRENT(ptThread);
+ return ptThread->tx_thread_name;
#endif
--- a/stm32cube_fw_h5_v120/STM32Cube_FW_H5_V1.2.0/Middlewares/Third_Party/cm_backtrace/cmb_def.h
+++ b/stm32cube_fw_h5_v120/STM32Cube_FW_H5_V1.2.0/Middlewares/Third_Party/cm_backtrace/cmb_def.h
@@ -47,6 +47,7 @@
#define CMB_OS_PLATFORM_UCOSIII 2
#define CMB_OS_PLATFORM_FREERTOS 3
#define CMB_OS_PLATFORM_RTX5 4
+#define CMB_OS_PLATFORM_THREADX 5
#define CMB_PRINT_LANGUAGE_ENGLISH 0
#define CMB_PRINT_LANGUAGE_CHINESE 1
@@ -348,6 +349,9 @@ if (!(EXPR)) \
extern char * vTaskName(void);
#elif (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_RTX5)
#include "rtx_os.h"
+ #elif (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_THREADX)
+ #include "tx_api.h"
+ #include "tx_thread.h"
#else
#error "not supported OS type"
#endif /* (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_RTT) */
代码对应完毕后,工程内加入如下配置文件即可使用了。
/* print line, must config by user */
#define cmb_println(...) printf(__VA_ARGS__);printf("\r\n")
/* 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_THREADX
/* cpu platform type, must config by user */
#define CMB_CPU_PLATFORM_TYPE CMB_CPU_ARM_CORTEX_M33
/* enable dump stack information */
#define CMB_USING_DUMP_STACK_INFO
/* language of print information */
#define CMB_PRINT_LANGUAGE CMB_PRINT_LANGUAGE_ENGLISH
板子验证
添加如下测试代码触发死机异常验证CmBacktrace 功能。
/*
* fault_test.c
*
* Created on: 2016/12/25
* Author: Armink
*/
#include <stdio.h>
#include "littleshell.h"
void fault_test_by_unalign(void) {
volatile int * SCB_CCR = (volatile int *) 0xE000ED14; // SCB->CCR
volatile int * p;
volatile int value;
*SCB_CCR |= (1 << 3); /* bit3: UNALIGN_TRP. */
p = (int *) 0x00;
value = *p;
printf("addr:0x%02X value:0x%08X\r\n", (int) p, value);
p = (int *) 0x04;
value = *p;
printf("addr:0x%02X value:0x%08X\r\n", (int) p, value);
p = (int *) 0x03;
value = *p;
printf("addr:0x%02X value:0x%08X\r\n", (int) p, value);
}
int hard1(char argc,char ** argv)
{
fault_test_by_unalign();
return 0;
}
LTSH_FUNCTION_EXPORT(hard1,"test hard fault1")
void fault_test_by_div0(void) {
volatile int * SCB_CCR = (volatile int *) 0xE000ED14; // SCB->CCR
int x, y, z;
*SCB_CCR |= (1 << 4); /* bit4: DIV_0_TRP. */
x = 10;
y = 0;
z = x / y;
printf("z:%d\n", z);
}
int hard2(char argc,char ** argv)
{
fault_test_by_div0();
return 0;
}
LTSH_FUNCTION_EXPORT(hard2,"test hard fault2")
输入hard2 触发除0错误:
使用addr2line 工具dump 死机调用栈,根据输出的函数信息我们很方便的查找到了死机的异常点,对于调试死机问题是个利器。