Cortex-M7进入异常中断分析
使用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 1
INT32U 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_INFO
uint32_t stack_start_addr = main_stack_start_addr;
size_t stack_size = main_stack_size;
#endif
CMB_ASSERT(init_ok);
/* only call once */
CMB_ASSERT(!on_fault);
on_fault = true;
cmb_println(" ");
cm_backtrace_firmware_info();
#ifdef CMB_USING_OS_PLATFORM
on_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_INFO
get_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 R0
regs.saved.r1 = ((uint32_t *)saved_regs_addr)[1]; // Register R1
regs.saved.r2 = ((uint32_t *)saved_regs_addr)[2]; // Register R2
regs.saved.r3 = ((uint32_t *)saved_regs_addr)[3]; // Register R3
regs.saved.r12 = ((uint32_t *)saved_regs_addr)[4]; // Register R12
regs.saved.lr = ((uint32_t *)saved_regs_addr)[5]; // Link register LR
regs.saved.pc = ((uint32_t *)saved_regs_addr)[6]; // Program counter PC
regs.saved.psr.value = ((uint32_t *)saved_regs_addr)[7]; // Program status word PSR
cmb_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 Register
regs.mfsr.value = CMB_NVIC_MFSR; // Memory Fault Status Register
regs.mmar = CMB_NVIC_MMAR; // Memory Management Fault Address Register
regs.bfsr.value = CMB_NVIC_BFSR; // Bus Fault Status Register
regs.bfar = CMB_NVIC_BFAR; // Bus Fault Manage Address Register
regs.ufsr.value = CMB_NVIC_UFSR; // Usage Fault Status Register
regs.hfsr.value = CMB_NVIC_HFSR; // Hard Fault Status Register
regs.dfsr.value = CMB_NVIC_DFSR; // Debug Fault Status Register
regs.afsr = CMB_NVIC_AFSR; // Auxiliary Fault Status Register
fault_diagnosis();
#endif
print_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>