#include "addr2line.h" // 错误类型打印 #define DUMP_CPU_ARM_CORTEX_M0 0 #define DUMP_CPU_ARM_CORTEX_M3 1 #define DUMP_CPU_ARM_CORTEX_M4 2 #define DUMP_CPU_ARM_CORTEX_M7 3 #define DUMP_CPU_PLATFORM_TYPE DUMP_CPU_ARM_CORTEX_M4 /* system handler control and state register */ #ifndef DUMP_SYSHND_CTRL #define DUMP_SYSHND_CTRL (*(volatile unsigned int*) (0xE000ED24u)) #endif /* memory management fault status register */ #ifndef DUMP_NVIC_MFSR #define DUMP_NVIC_MFSR (*(volatile unsigned char*) (0xE000ED28u)) #endif /* bus fault status register */ #ifndef DUMP_NVIC_BFSR #define DUMP_NVIC_BFSR (*(volatile unsigned char*) (0xE000ED29u)) #endif /* usage fault status register */ #ifndef DUMP_NVIC_UFSR #define DUMP_NVIC_UFSR (*(volatile unsigned short*)(0xE000ED2Au)) #endif /* hard fault status register */ #ifndef DUMP_NVIC_HFSR #define DUMP_NVIC_HFSR (*(volatile unsigned int*) (0xE000ED2Cu)) #endif /* debug fault status register */ #ifndef DUMP_NVIC_DFSR #define DUMP_NVIC_DFSR (*(volatile unsigned short*)(0xE000ED30u)) #endif /* memory management fault address register */ #ifndef DUMP_NVIC_MMAR #define DUMP_NVIC_MMAR (*(volatile unsigned int*) (0xE000ED34u)) #endif /* bus fault manage address register */ #ifndef DUMP_NVIC_BFAR #define DUMP_NVIC_BFAR (*(volatile unsigned int*) (0xE000ED38u)) #endif /* auxiliary fault status register */ #ifndef DUMP_NVIC_AFSR #define DUMP_NVIC_AFSR (*(volatile unsigned short*)(0xE000ED3Cu)) #endif /** * Cortex-M fault registers */ struct dump_hard_fault_regs { struct { unsigned int r0; // Register R0 unsigned int r1; // Register R1 unsigned int r2; // Register R2 unsigned int r3; // Register R3 unsigned int r12; // Register R12 unsigned int lr; // Link register unsigned int pc; // Program counter union { unsigned int value; struct { unsigned int IPSR : 8; // Interrupt Program Status register (IPSR) unsigned int EPSR : 19; // Execution Program Status register (EPSR) unsigned int APSR : 5; // Application Program Status register (APSR) } bits; } psr; // Program status register. } saved; union { unsigned int value; struct { unsigned int MEMFAULTACT : 1; // Read as 1 if memory management fault is active unsigned int BUSFAULTACT : 1; // Read as 1 if bus fault exception is active unsigned int UnusedBits1 : 1; unsigned int USGFAULTACT : 1; // Read as 1 if usage fault exception is active unsigned int UnusedBits2 : 3; unsigned int SVCALLACT : 1; // Read as 1 if SVC exception is active unsigned int MONITORACT : 1; // Read as 1 if debug monitor exception is active unsigned int UnusedBits3 : 1; unsigned int PENDSVACT : 1; // Read as 1 if PendSV exception is active unsigned int SYSTICKACT : 1; // Read as 1 if SYSTICK exception is active unsigned int USGFAULTPENDED : 1; // Usage fault pended; usage fault started but was replaced by a higher-priority exception unsigned int MEMFAULTPENDED : 1; // Memory management fault pended; memory management fault started but was replaced by a higher-priority exception unsigned int BUSFAULTPENDED : 1; // Bus fault pended; bus fault handler was started but was replaced by a higher-priority exception unsigned int SVCALLPENDED : 1; // SVC pended; SVC was started but was replaced by a higher-priority exception unsigned int MEMFAULTENA : 1; // Memory management fault handler enable unsigned int BUSFAULTENA : 1; // Bus fault handler enable unsigned int USGFAULTENA : 1; // Usage fault handler enable } bits; } syshndctrl; // System Handler Control and State Register (0xE000ED24) union { unsigned char value; struct { unsigned char IACCVIOL : 1; // Instruction access violation unsigned char DACCVIOL : 1; // Data access violation unsigned char UnusedBits : 1; unsigned char MUNSTKERR : 1; // Unstacking error unsigned char MSTKERR : 1; // Stacking error unsigned char MLSPERR : 1; // Floating-point lazy state preservation (M4/M7) unsigned char UnusedBits2 : 1; unsigned char MMARVALID : 1; // Indicates the MMAR is valid } bits; } mfsr; // Memory Management Fault Status Register (0xE000ED28) unsigned int mmar; // Memory Management Fault Address Register (0xE000ED34) union { unsigned char value; struct { unsigned char IBUSERR : 1; // Instruction access violation unsigned char PRECISERR : 1; // Precise data access violation unsigned char IMPREISERR : 1; // Imprecise data access violation unsigned char UNSTKERR : 1; // Unstacking error unsigned char STKERR : 1; // Stacking error unsigned char LSPERR : 1; // Floating-point lazy state preservation (M4/M7) unsigned char UnusedBits : 1; unsigned char BFARVALID : 1; // Indicates BFAR is valid } bits; } bfsr; // Bus Fault Status Register (0xE000ED29) unsigned int bfar; // Bus Fault Manage Address Register (0xE000ED38) union { unsigned short value; struct { unsigned short UNDEFINSTR : 1; // Attempts to execute an undefined instruction unsigned short INVSTATE : 1; // Attempts to switch to an invalid state (e.g., ARM) unsigned short INVPC : 1; // Attempts to do an exception with a bad value in the EXC_RETURN number unsigned short NOCP : 1; // Attempts to execute a coprocessor instruction unsigned short UnusedBits : 4; unsigned short UNALIGNED : 1; // Indicates that an unaligned access fault has taken place unsigned short DIVBYZERO0 : 1; // Indicates a divide by zero has taken place (can be set only if DIV_0_TRP is set) } bits; } ufsr; // Usage Fault Status Register (0xE000ED2A) union { unsigned int value; struct { unsigned int UnusedBits : 1; unsigned int VECTBL : 1; // Indicates hard fault is caused by failed vector fetch unsigned int UnusedBits2 : 28; unsigned int FORCED : 1; // Indicates hard fault is taken because of bus fault/memory management fault/usage fault unsigned int DEBUGEVT : 1; // Indicates hard fault is triggered by debug event } bits; } hfsr; // Hard Fault Status Register (0xE000ED2C) union { unsigned int value; struct { unsigned int HALTED : 1; // Halt requested in NVIC unsigned int BKPT : 1; // BKPT instruction executed unsigned int DWTTRAP : 1; // DWT match occurred unsigned int VCATCH : 1; // Vector fetch occurred unsigned int EXTERNAL : 1; // EDBGRQ signal asserted } bits; } dfsr; // Debug Fault Status Register (0xE000ED30) unsigned int afsr; // Auxiliary Fault Status Register (0xE000ED3C), Vendor controlled (optional) }; enum { PRINT_MAIN_STACK_CFG_ERROR, PRINT_FIRMWARE_INFO, PRINT_ASSERT_ON_THREAD, PRINT_ASSERT_ON_HANDLER, PRINT_THREAD_STACK_INFO, PRINT_MAIN_STACK_INFO, PRINT_THREAD_STACK_OVERFLOW, PRINT_MAIN_STACK_OVERFLOW, PRINT_CALL_STACK_INFO, PRINT_CALL_STACK_ERR, PRINT_FAULT_ON_THREAD, PRINT_FAULT_ON_HANDLER, PRINT_REGS_TITLE, PRINT_HFSR_VECTBL, PRINT_MFSR_IACCVIOL, PRINT_MFSR_DACCVIOL, PRINT_MFSR_MUNSTKERR, PRINT_MFSR_MSTKERR, PRINT_MFSR_MLSPERR, PRINT_BFSR_IBUSERR, PRINT_BFSR_PRECISERR, PRINT_BFSR_IMPREISERR, PRINT_BFSR_UNSTKERR, PRINT_BFSR_STKERR, PRINT_BFSR_LSPERR, PRINT_UFSR_UNDEFINSTR, PRINT_UFSR_INVSTATE, PRINT_UFSR_INVPC, PRINT_UFSR_NOCP, PRINT_UFSR_UNALIGNED, PRINT_UFSR_DIVBYZERO0, PRINT_DFSR_HALTED, PRINT_DFSR_BKPT, PRINT_DFSR_DWTTRAP, PRINT_DFSR_VCATCH, PRINT_DFSR_EXTERNAL, PRINT_MMAR, PRINT_BFAR, }; static const char *const print_info[] = { [PRINT_MAIN_STACK_CFG_ERROR] = "ERROR: Unable to get the main stack information, please check the configuration of the main stack\n", [PRINT_FIRMWARE_INFO] = "Firmware name: %s, hardware version: %s, software version: %s\n", [PRINT_ASSERT_ON_THREAD] = "Assert on thread %s\n", [PRINT_ASSERT_ON_HANDLER] = "Assert on interrupt or bare metal(no OS) environment\n", [PRINT_THREAD_STACK_INFO] = "===== Thread stack information =====\n", [PRINT_MAIN_STACK_INFO] = "====== Main stack information ======\n", [PRINT_THREAD_STACK_OVERFLOW] = "Error: Thread stack(%08x) was overflow\n", [PRINT_MAIN_STACK_OVERFLOW] = "Error: Main stack(%08x) was overflow\n", [PRINT_CALL_STACK_INFO] = "Show more call stack info by run: addr2line -e %s%s -a -f %.*s\n", [PRINT_CALL_STACK_ERR] = "Dump call stack has an error\n", [PRINT_FAULT_ON_THREAD] = "Fault on thread %s\n", [PRINT_FAULT_ON_HANDLER] = "Fault on interrupt or bare metal(no OS) environment\n", [PRINT_REGS_TITLE] = "=================== Registers information ====================\n", [PRINT_HFSR_VECTBL] = "Hard fault is caused by failed vector fetch\n", [PRINT_MFSR_IACCVIOL] = "Memory management fault is caused by instruction access violation\n", [PRINT_MFSR_DACCVIOL] = "Memory management fault is caused by data access violation\n", [PRINT_MFSR_MUNSTKERR] = "Memory management fault is caused by unstacking error\n", [PRINT_MFSR_MSTKERR] = "Memory management fault is caused by stacking error\n", [PRINT_MFSR_MLSPERR] = "Memory management fault is caused by floating-point lazy state preservation\n", [PRINT_BFSR_IBUSERR] = "Bus fault is caused by instruction access violation\n", [PRINT_BFSR_PRECISERR] = "Bus fault is caused by precise data access violation\n", [PRINT_BFSR_IMPREISERR] = "Bus fault is caused by imprecise data access violation\n", [PRINT_BFSR_UNSTKERR] = "Bus fault is caused by unstacking error\n", [PRINT_BFSR_STKERR] = "Bus fault is caused by stacking error\n", [PRINT_BFSR_LSPERR] = "Bus fault is caused by floating-point lazy state preservation\n", [PRINT_UFSR_UNDEFINSTR] = "Usage fault is caused by attempts to execute an undefined instruction\n", [PRINT_UFSR_INVSTATE] = "Usage fault is caused by attempts to switch to an invalid state (e.g., ARM)\n", [PRINT_UFSR_INVPC] = "Usage fault is caused by attempts to do an exception with a bad value in the EXC_RETURN number\n", [PRINT_UFSR_NOCP] = "Usage fault is caused by attempts to execute a coprocessor instruction\n", [PRINT_UFSR_UNALIGNED] = "Usage fault is caused by indicates that an unaligned access fault has taken place\n", [PRINT_UFSR_DIVBYZERO0] = "Usage fault is caused by Indicates a divide by zero has taken place (can be set only if DIV_0_TRP is set)\n", [PRINT_DFSR_HALTED] = "Debug fault is caused by halt requested in NVIC\n", [PRINT_DFSR_BKPT] = "Debug fault is caused by BKPT instruction executed\n", [PRINT_DFSR_DWTTRAP] = "Debug fault is caused by DWT match occurred\n", [PRINT_DFSR_VCATCH] = "Debug fault is caused by Vector fetch occurred\n", [PRINT_DFSR_EXTERNAL] = "Debug fault is caused by EDBGRQ signal asserted\n", [PRINT_MMAR] = "The memory management fault occurred address is %08x\n", [PRINT_BFAR] = "The bus fault occurred address is %08x\n", }; static struct dump_hard_fault_regs regs; #if (DUMP_CPU_PLATFORM_TYPE != DUMP_CPU_ARM_CORTEX_M0) /** * fault diagnosis then print cause of fault */ static void fault_diagnosis(void) { if (regs.hfsr.bits.VECTBL) { addr2line_print(print_info[PRINT_HFSR_VECTBL]); } if (regs.hfsr.bits.FORCED) { /* Memory Management Fault */ if (regs.mfsr.value) { if (regs.mfsr.bits.IACCVIOL) { addr2line_print(print_info[PRINT_MFSR_IACCVIOL]); } if (regs.mfsr.bits.DACCVIOL) { addr2line_print(print_info[PRINT_MFSR_DACCVIOL]); } if (regs.mfsr.bits.MUNSTKERR) { addr2line_print(print_info[PRINT_MFSR_MUNSTKERR]); } if (regs.mfsr.bits.MSTKERR) { addr2line_print(print_info[PRINT_MFSR_MSTKERR]); } #if (DUMP_CPU_PLATFORM_TYPE == DUMP_CPU_ARM_CORTEX_M4) || (DUMP_CPU_PLATFORM_TYPE == DUMP_CPU_ARM_CORTEX_M7) if (regs.mfsr.bits.MLSPERR) { addr2line_print(print_info[PRINT_MFSR_MLSPERR]); } #endif if (regs.mfsr.bits.MMARVALID) { if (regs.mfsr.bits.IACCVIOL || regs.mfsr.bits.DACCVIOL) { addr2line_print(print_info[PRINT_MMAR], regs.mmar); } } } /* Bus Fault */ if (regs.bfsr.value) { if (regs.bfsr.bits.IBUSERR) { addr2line_print(print_info[PRINT_BFSR_IBUSERR]); } if (regs.bfsr.bits.PRECISERR) { addr2line_print(print_info[PRINT_BFSR_PRECISERR]); } if (regs.bfsr.bits.IMPREISERR) { addr2line_print(print_info[PRINT_BFSR_IMPREISERR]); } if (regs.bfsr.bits.UNSTKERR) { addr2line_print(print_info[PRINT_BFSR_UNSTKERR]); } if (regs.bfsr.bits.STKERR) { addr2line_print(print_info[PRINT_BFSR_STKERR]); } #if (DUMP_CPU_PLATFORM_TYPE == DUMP_CPU_ARM_CORTEX_M4) || (DUMP_CPU_PLATFORM_TYPE == DUMP_CPU_ARM_CORTEX_M7) if (regs.bfsr.bits.LSPERR) { addr2line_print(print_info[PRINT_BFSR_LSPERR]); } #endif if (regs.bfsr.bits.BFARVALID) { if (regs.bfsr.bits.PRECISERR) { addr2line_print(print_info[PRINT_BFAR], regs.bfar); } } } /* Usage Fault */ if (regs.ufsr.value) { if (regs.ufsr.bits.UNDEFINSTR) { addr2line_print(print_info[PRINT_UFSR_UNDEFINSTR]); } if (regs.ufsr.bits.INVSTATE) { addr2line_print(print_info[PRINT_UFSR_INVSTATE]); } if (regs.ufsr.bits.INVPC) { addr2line_print(print_info[PRINT_UFSR_INVPC]); } if (regs.ufsr.bits.NOCP) { addr2line_print(print_info[PRINT_UFSR_NOCP]); } if (regs.ufsr.bits.UNALIGNED) { addr2line_print(print_info[PRINT_UFSR_UNALIGNED]); } if (regs.ufsr.bits.DIVBYZERO0) { addr2line_print(print_info[PRINT_UFSR_DIVBYZERO0]); } } } /* Debug Fault */ if (regs.hfsr.bits.DEBUGEVT) { if (regs.dfsr.value) { if (regs.dfsr.bits.HALTED) { addr2line_print(print_info[PRINT_DFSR_HALTED]); } if (regs.dfsr.bits.BKPT) { addr2line_print(print_info[PRINT_DFSR_BKPT]); } if (regs.dfsr.bits.DWTTRAP) { addr2line_print(print_info[PRINT_DFSR_DWTTRAP]); } if (regs.dfsr.bits.VCATCH) { addr2line_print(print_info[PRINT_DFSR_VCATCH]); } if (regs.dfsr.bits.EXTERNAL) { addr2line_print(print_info[PRINT_DFSR_EXTERNAL]); } } } } #endif int coredump_fault_diagnosis(void) { /* the Cortex-M0 is not support fault diagnosis */ #if (DUMP_CPU_PLATFORM_TYPE != DUMP_CPU_ARM_CORTEX_M0) regs.syshndctrl.value = DUMP_SYSHND_CTRL; // System Handler Control and State Register regs.mfsr.value = DUMP_NVIC_MFSR; // Memory Fault Status Register regs.mmar = DUMP_NVIC_MMAR; // Memory Management Fault Address Register regs.bfsr.value = DUMP_NVIC_BFSR; // Bus Fault Status Register regs.bfar = DUMP_NVIC_BFAR; // Bus Fault Manage Address Register regs.ufsr.value = DUMP_NVIC_UFSR; // Usage Fault Status Register regs.hfsr.value = DUMP_NVIC_HFSR; // Hard Fault Status Register regs.dfsr.value = DUMP_NVIC_DFSR; // Debug Fault Status Register regs.afsr = DUMP_NVIC_AFSR; // Auxiliary Fault Status Register fault_diagnosis(); return 0; #endif return -1; } int addr2line_print_stack_before(uint32_t lr) { int on_thread_before_fault = lr & (1UL << 2); /* check which stack was used before (MSP or PSP) */ if (on_thread_before_fault) addr2line_print(print_info[PRINT_FAULT_ON_THREAD], rt_thread_self()->name != NULL ? rt_thread_self()->name : "NO_NAME"); else addr2line_print(print_info[PRINT_FAULT_ON_HANDLER]); coredump_fault_diagnosis(); return 0; } void addr2line_trigger_exception(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 = strlen(""); z = x / y; addr2line_print("z:%d\n", z); } // addr to line #include #pragma section = ".text" static bool is_in_text(uint32_t addr) { #if 0 uint32_t code_start_addr = (uint32_t)&CODE_SECTION_START(CMB_CODE_SECTION_NAME); uint32_t code_size = (uint32_t)&CODE_SECTION_END(CMB_CODE_SECTION_NAME) - code_start_addr; #else uint32_t code_start_addr = (uint32_t)__section_begin(".text"); uint32_t code_size = (uint32_t)__section_end(".text") - code_start_addr; #endif if (code_start_addr < addr && addr <= code_start_addr + code_size) { return true; } return false; } static bool disassembly_ins_is_bl_blx(uint32_t addr) { #define BL_INS_MASK 0xF800 #define BL_INS_HIGH 0xF800 #define BL_INS_LOW 0xF000 #define BLX_INX_MASK 0xFF00 #define BLX_INX 0x4700 uint16_t ins1 = *((uint16_t *)addr); uint16_t ins2 = *((uint16_t *)(addr + 2)); if ((ins2 & BL_INS_MASK) == BL_INS_HIGH && (ins1 & BL_INS_MASK) == BL_INS_LOW) { return true; } else if ((ins2 & BLX_INX_MASK) == BLX_INX) { return true; } else { return false; } } void addr2line_print(uint32_t *addr, int size) { addr2line_print("\naddr2line -e " PROJECT_NAME " -a -f "); size /= sizeof(uint32_t); for (int i = 1; i < size; i++) { const uint32_t lr = addr[i]; if (false == is_in_text(lr)) continue; uint32_t pc = lr - sizeof(size_t); // 假设当前是lr寄存器的值,向下增长4就是pc寄存器的值 if (pc % 2 == 0) // thumb 指令pc寄存器值一定是偶数 continue; pc = lr - 1; // lr寄存器值保存的是pc+1 if (true == disassembly_ins_is_bl_blx(pc - sizeof(size_t))) // pc 的上一条指令是跳转指令 addr2line_print("%08x ", pc); } addr2line_print("\n"); } #if 0 static void test_addr2line(void) { uint32_t sg_test_stack[] = { 0x00000001, 0x000514d5, 0x000000f0, 0x00000001, 0x000c3fcc, 0x00000000, 0x000538b4, 0x00549822, 0xdeadbeef, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000a, 0x00000210, 0x00000000, 0x00000000, 0x00000006, 0x000514eb, 0x000516f8, 0x49000000, 0x00000004, 0x0000007d, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000010, 0x00000000, 0x00000200, 0x00000000, 0x000008f4, 0x000537bb, 0x000000f0, 0x00000000, 0x00000001, 0x00000002, 0x20033378, 0x000468e3, 0x00000000, 0x20036c3c, 0x20036c78, 0x000b8789, 0x00000000, 0x20016dd8, 0x20008198, 0x000b819f, 0x00000000, 0x2003727c, 0x20016dd8, 0x0006047f, 0x00000050, 0x00000000, 0x20016dd8, 0x00000001, 0x00000001, 0x000604dd, 0x00000000, 0x2003092c, 0x20030b1c, 0x200334f4, 0x200334b4, 0x00060215, 0x2003764c, 0x20036e98, 0x00000008, 0x200081f4, 0x200334b4, 0x00000000, 0x0068007a, 0x00000000, 0x20030b1c, 0x00063dd3, 0x007a0068, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x20033520, 0x2003060c, 0x2002cc84, 0x2002cbf4, 0x20033378, 0x0005ce35, 0x20030e20, 0x000d17c8, 0x20030214, 0x00000014, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0x00057c99, 0x00000000, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0x000302e7 }; uint32_t *addr = sg_test_stack; int size = sizeof(sg_test_stack); _addr2line_print(addr, size); } #endif