使用cmbacktrace库,其支持M3,4,7。
1、串口输出异常信息
#define cmb_println(...) Debug_Printf(__VA_ARGS__)//cmb_println处理可变参数和格式化字符串
int Debug_Printf(const char *fmt, ...) {char buffer[DEBUG_TxBUFLEN];INT16U n;va_list args;va_start(args, fmt);int len = vsnprintf(buffer, sizeof(buffer), fmt, args);va_end(args);for ( n = 0; n < len; n++ ) WriteDebugTxBuffer( buffer[n] );return len;
}//串口查询方式发送,被cm_backtrace_fault调用
void UartDbg_CheckSend(void)
{
#if 1INT32U status;if ( DebugBuf.PtrTxHead == DebugBuf.PtrTxTail ) return;status = LPUART_GetStatusFlags( DEBUG_SIO_BASE );if ( status & kLPUART_TxDataRegEmptyFlag ){LPUART_WriteByte( DEBUG_SIO_BASE, DebugBuf.TxBuffer[ DebugBuf.PtrTxTail ] );++DebugBuf.PtrTxTail;if ( DebugBuf.PtrTxTail >= DEBUG_TxBUFLEN ) DebugBuf.PtrTxTail = 0;}
#endif
}/*** backtrace for fault* @note only call once** @param fault_handler_lr the LR register value on fault handler* @param fault_handler_sp the stack pointer on fault handler*/
void cm_backtrace_fault(uint32_t fault_handler_lr, uint32_t fault_handler_sp) {uint32_t stack_pointer = fault_handler_sp, saved_regs_addr = stack_pointer, tcb_stack_pointer = 0;const char *regs_name[] = { "R0 ", "R1 ", "R2 ", "R3 ", "R12", "LR ", "PC ", "PSR" };#ifdef CMB_USING_DUMP_STACK_INFOuint32_t stack_start_addr = main_stack_start_addr;size_t stack_size = main_stack_size;
#endifCMB_ASSERT(init_ok);/* only call once */CMB_ASSERT(!on_fault);on_fault = true;cmb_println(" ");cm_backtrace_firmware_info();#ifdef CMB_USING_OS_PLATFORMon_thread_before_fault = fault_handler_lr & (1UL << 2);/* check which stack was used before (MSP or PSP) */if (on_thread_before_fault) {cmb_println(print_info[PRINT_FAULT_ON_THREAD], get_cur_thread_name() != NULL ? get_cur_thread_name() : "NO_NAME");saved_regs_addr = stack_pointer = cmb_get_psp();#ifdef CMB_USING_DUMP_STACK_INFOget_cur_thread_stack_info(&tcb_stack_pointer, &stack_start_addr, &stack_size);
#endif /* CMB_USING_DUMP_STACK_INFO */} else {cmb_println(print_info[PRINT_FAULT_ON_HANDLER]);}
#else/* bare metal(no OS) environment */cmb_println(print_info[PRINT_FAULT_ON_HANDLER]);
#endif /* CMB_USING_OS_PLATFORM *//* delete saved R0~R3, R12, LR,PC,xPSR registers space */stack_pointer += sizeof(size_t) * 8;#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M4) || (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M7) || \(CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)stack_pointer = statck_del_fpu_regs(fault_handler_lr, stack_pointer);
#endif /* (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M4) || (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M7) */#ifdef CMB_USING_DUMP_STACK_INFO/* check stack overflow */if (stack_pointer < stack_start_addr || stack_pointer > stack_start_addr + stack_size) {cmb_println("stack_pointer: 0x%08x, stack_start_addr: 0x%08x, stack_end_addr: 0x%08x", stack_pointer, stack_start_addr,stack_start_addr + stack_size);stack_is_overflow = true;
#if (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_RTT)if (on_thread_before_fault) {/* change the stack start adder to TCB->sp when stack is overflow */stack_pointer = tcb_stack_pointer;}
#endif}/* dump stack information */dump_stack(stack_start_addr, stack_size, (uint32_t *) stack_pointer);
#endif /* CMB_USING_DUMP_STACK_INFO */{/* dump register */cmb_println(print_info[PRINT_REGS_TITLE]);regs.saved.r0 = ((uint32_t *)saved_regs_addr)[0]; // Register R0regs.saved.r1 = ((uint32_t *)saved_regs_addr)[1]; // Register R1regs.saved.r2 = ((uint32_t *)saved_regs_addr)[2]; // Register R2regs.saved.r3 = ((uint32_t *)saved_regs_addr)[3]; // Register R3regs.saved.r12 = ((uint32_t *)saved_regs_addr)[4]; // Register R12regs.saved.lr = ((uint32_t *)saved_regs_addr)[5]; // Link register LRregs.saved.pc = ((uint32_t *)saved_regs_addr)[6]; // Program counter PCregs.saved.psr.value = ((uint32_t *)saved_regs_addr)[7]; // Program status word PSRcmb_println(" %s: %08x %s: %08x %s: %08x %s: %08x", regs_name[0], regs.saved.r0,regs_name[1], regs.saved.r1,regs_name[2], regs.saved.r2,regs_name[3], regs.saved.r3);cmb_println(" %s: %08x %s: %08x %s: %08x %s: %08x", regs_name[4], regs.saved.r12,regs_name[5], regs.saved.lr,regs_name[6], regs.saved.pc,regs_name[7], regs.saved.psr.value);cmb_println("==============================================================");}/* the Cortex-M0 is not support fault diagnosis */
#if (CMB_CPU_PLATFORM_TYPE != CMB_CPU_ARM_CORTEX_M0)regs.syshndctrl.value = CMB_SYSHND_CTRL; // System Handler Control and State Registerregs.mfsr.value = CMB_NVIC_MFSR; // Memory Fault Status Registerregs.mmar = CMB_NVIC_MMAR; // Memory Management Fault Address Registerregs.bfsr.value = CMB_NVIC_BFSR; // Bus Fault Status Registerregs.bfar = CMB_NVIC_BFAR; // Bus Fault Manage Address Registerregs.ufsr.value = CMB_NVIC_UFSR; // Usage Fault Status Registerregs.hfsr.value = CMB_NVIC_HFSR; // Hard Fault Status Registerregs.dfsr.value = CMB_NVIC_DFSR; // Debug Fault Status Registerregs.afsr = CMB_NVIC_AFSR; // Auxiliary Fault Status Registerfault_diagnosis();
#endifprint_call_stack(stack_pointer);//在末尾处执行串口发送while (1){UartDbg_CheckSend();}
}
Firmware name: CmBacktrace, hardware version: V1.00, software version: V1.00Fault on interrupt or bare metal(no OS) environment=================== Registers information ==================== R0 : 20015ca0 R1 : 00000064 R2 : 00000000 R3 : 00000001 R12: 00000001 LR : 7008fe8b PC : 7008fdee PSR: 01000000==============================================================Usage fault is caused by Indicates a divide by zero has taken place (can be set only if DIV_0_TRP is set)Show more call stack info by run: addr2line -e CmBacktrace.out -afpiC 7008fdee 7008fe8a 7009b45a
2、ddr2line解析地址,解析出来函数名和行数,准确解析了trigger_hardfault_by_div0函数115行出错
0x7008fe8b
MainFunction
E:\tfs\12.5\Equipment\firmware\Smartsafe\MC\Source\User_5200N\UserIAR\MiddleControl/Main_Mid.c:171
0x7008fdee
trigger_hardfault_by_div0
E:\tfs\12.5\Equipment\firmware\Smartsafe\MC\Source\User_5200N\UserIAR\MiddleControl/Main_Mid.c:115
PS F:\CmBacktrace\tools\addr2line\win64>