#include #include #include /* ------------------------------------------------------------------------------------------------------------------ */ /* */ // 定义常见 Cortex-M 芯片的内存映射边界 #define FLASH_START 0x08000000 #define FLASH_END 0x0C000000 #define SRAM_START 0x20000000 #define SRAM_END 0x30000000 #define PERIPH_START 0x40000000 #define PERIPH_END 0x60000000 #define FMC_START 0x60000000 #define FMC_END 0xA0000000 /* ------------------------------------------------------------------------------------------------------------------ */ /* */ // 深度分析崩溃的物理地址 static void analyze_fault_address(const char* fault_type, uint32_t addr) { printf("\n🔍 [%s Address Analysis] ----------------\n", fault_type); printf("Target Address: 0x%08X\n", addr); // 1. 经典空指针或极其接近0的地址(如结构体成员偏移) if (addr < 0x00000400) { printf("🚨 诊断结论: 空指针 (NULL Pointer) 解引用!\n"); if (addr == 0) { printf(" -> 代码尝试直接读取或写入 NULL。\n"); } else { printf(" -> 代码操作了 NULL 结构体指针,该地址是成员偏移量 (Offset: %d bytes)。\n", addr); } return; } // 2. 检查是否在代码区 (Flash) if (addr >= FLASH_START && addr < FLASH_END) { printf("🚨 诊断结论: 尝试写入只读的 Flash 区域,或者读取了未初始化的非法 Flash 地址!\n"); printf(" -> 请检查代码是否在尝试修改常量(const)或直接通过指针对0x08xxxxxx地址写数据。\n"); return; } // 3. 检查是否在运行内存区 (SRAM) if (addr >= SRAM_START && addr < SRAM_END) { printf("🚨 诊断结论: 访问 SRAM 时崩溃。\n"); printf(" -> 极大可能是 数组越界 或 堆栈溢出 (Stack Overflow) 破坏了相邻的数据边界。\n"); printf(" -> 请在 .map 文件中查找哪个全局/静态变量的地址最接近 0x%08X。\n", addr); return; } // 4. 检查是否在外设寄存器区 (Peripheral) if (addr >= PERIPH_START && addr < PERIPH_END) { printf("🚨 诊断结论: 访问外设寄存器时总线报错。\n"); printf(" -> 原因 1: 该外设的时钟 (RCC) 没有开启,就去读写它的寄存器!(最常见)\n"); printf(" -> 原因 2: 尝试访问当前芯片型号根本不存在的外设。\n"); return; } // 5. 检查是否在外部扩展内存 (FMC/FSMC, 如外部 SDRAM/LCD) if (addr >= FMC_START && addr < FMC_END) { printf("🚨 诊断结论: 访问外部存储器(FMC/FSMC)报错。\n"); printf(" -> 请检查外部 SDRAM/NAND/LCD 的初始化代码是否未执行,或者硬件引脚接触不良。\n"); return; } // 6. 处于完全未定义的无人区 (野指针) printf("🚨 诊断结论: 绝对的野指针 (Wild Pointer) 访问!\n"); printf(" -> 0x%08X 是一个完全不合法的未映射地址空间。\n", addr); printf(" -> 通常是因为指针变量未初始化、指针转义、或者堆栈被破坏导致恢复出的指针变成了垃圾值。\n"); } static void decode_xpsr(uint32_t xpsr) { printf("\n------ [ xPSR Detail Analysis ] ------\n"); printf("xPSR: 0x%08X\n", xpsr); // 检查第 24 位 (1 << 24 = 0x01000000) if ((xpsr & (1 << 24)) == 0) { printf("🚨 [CRITICAL ERROR] xPSR T-bit (Bit 24) is 0!\n"); printf(" Cortex-M processors ONLY support Thumb state.\n"); printf(" Switching to ARM state (T=0) is illegal and caused this crash.\n"); printf("💡 [SUGGESTION] This usually happens because:\n"); printf(" 1. A function pointer lacked the LSB set to 1 (e.g., calling an even address).\n"); printf(" 2. Destructed stack frame or corrupted LR/PC during pop/return.\n"); } else { printf(" -> T-bit (Bit 24) = 1 (Correct: Processor is in Thumb state).\n"); } // 顺便打印当前处于哪个中断/异常中 (IPSR 位: Bit 0-8) uint8_t exception_number = (xpsr & 0x1FF); if (exception_number == 0) { printf(" -> Mode: Thread Mode (Application code).\n"); } else { printf(" -> Mode: Handler Mode (Interrupt/Exception Handler #%d).\n", exception_number); } } // 解析 CFSR 寄存器 (Cortex-M3/M4/M7/M33 适用) static void decode_cfsr(uint32_t cfsr, uint32_t bfar, uint32_t mmfar) { uint8_t mmfsr = (cfsr & 0x000000FF); uint8_t bfsr = ((cfsr & 0x0000FF00) >> 8); uint16_t ufsr = ((cfsr & 0xFFFF0000) >> 16); printf("\n------ [ CFSR Detail Analysis ] ------\n"); if (ufsr) { printf("[UsageFault] Detected (0x%04X):\n", ufsr); if (ufsr & (1 << 9)) printf(" -> DIVBYZERO: Try to divide by zero.\n"); if (ufsr & (1 << 8)) printf(" -> UNALIGNED: Unaligned memory access alignment fault.\n"); if (ufsr & (1 << 3)) printf(" -> NOCP: Access to an unenabled coprocessor (e.g. FPU).\n"); if (ufsr & (1 << 2)) printf(" -> INVPC: Invalid PC load caused by EXC_RETURN.\n"); if (ufsr & (1 << 1)) printf(" -> INVSTATE: Invalid execution state (Thumb bit issue).\n"); if (ufsr & (1 << 0)) printf(" -> UNDEFINSTR: Executed an undefined instruction.\n"); } if (bfsr) { printf("[BusFault] Detected (0x%02X):\n", bfsr); if (bfsr & (1 << 7)) { printf(" -> BFARVALID: Address in BFAR is valid.\n"); analyze_fault_address("BusFault (BFAR)", bfar); } else { printf(" -> Note: BFAR address is NOT valid (Imprecise fault).\n"); } if (bfsr & (1 << 1)) printf(" -> PRECISERR: Precise data bus error.\n"); if (bfsr & (1 << 0)) printf(" -> IBUSERR: Instruction bus error.\n"); } if (mmfsr) { printf("[MemManage Fault] Detected (0x%02X):\n", mmfsr); if (mmfsr & (1 << 7)) { printf(" -> MMFARVALID: Address in MMFAR is valid.\n"); analyze_fault_address("MemManage (MMFAR)", mmfar); } if (mmfsr & (1 << 1)) printf(" -> DACCVIOL: Data access violation.\n"); } } /* ------------------------------------------------------------------------------------------------------------------ */ /* */ void HardFaultAnalysis(HardFaultDump_t *dump) { printf("==================================================\n"); printf(" Cortex-M Offline HardFault Decoder \n"); printf("==================================================\n"); printf("\n------ [ Core Registers Snapshot ] ------\n"); printf("PC : 0x%08X (崩溃发生在此指令附近)\n", dump->pc); printf("LR : 0x%08X (父级函数返回地址)\n", dump->lr); printf("SP : 0x%08X R0 : 0x%08X\n", dump->sp, dump->r0); printf("R1 : 0x%08X R2 : 0x%08X\n", dump->r1, dump->r2); printf("R3 : 0x%08X R12 : 0x%08X\n", dump->r3, dump->r12); decode_xpsr(dump->xpsr); printf("\n------ [ HFSR High Level Summary ] ------\n"); printf("HFSR : 0x%08X\n", dump->hfsr); if (dump->hfsr & (1 << 30)) { printf(" -> FORCED: 强制硬件故障。由于其他特定异常升级导致,详情见下方 CFSR。\n"); } decode_cfsr(dump->cfsr, dump->bfar, dump->mmfar); printf("==================================================\n"); } int HardFaultAnalysis_Load(const char* filename, HardFaultDump_t* dump ) { FILE *file = fopen(filename, "r"); if (!file) { printf("Error: Cannot open file %s\n", filename); return 0; } char line[256]; while (fgets(line, sizeof(line), file)) { // 忽略注释和空行 if (line[0] == '#' || line[0] == '/' || line[0] == '\n' || line[0] == '\r') { continue; } char key[32]; uint32_t val; // 解析 "key = 0xValue" 格式 if (sscanf(line, "%s = %i", key, &val) == 2) { if (strcasecmp(key, "r0") == 0) dump->r0 = val; else if (strcasecmp(key, "r1") == 0) dump->r1 = val; else if (strcasecmp(key, "r2") == 0) dump->r2 = val; else if (strcasecmp(key, "r3") == 0) dump->r3 = val; else if (strcasecmp(key, "r12") == 0) dump->r12 = val; else if (strcasecmp(key, "sp") == 0) dump->sp = val; else if (strcasecmp(key, "lr") == 0) dump->lr = val; else if (strcasecmp(key, "pc") == 0) dump->pc = val; else if (strcasecmp(key, "xpsr") == 0) dump->xpsr = val; else if (strcasecmp(key, "hfsr") == 0) dump->hfsr = val; else if (strcasecmp(key, "cfsr") == 0) dump->cfsr = val; else if (strcasecmp(key, "bfar") == 0) dump->bfar = val; else if (strcasecmp(key, "mmfar") == 0) dump->mmfar = val; } } fclose(file); return 1; }