cmbacktrace分析 分析 以瑞萨RZN2L举例,在发生错误时,由于默认情况下RZN2L运行在SVC模式,所以要先切换回SVC模式,栈才对应。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 void Default_Handler (void) { /** A error has occurred. The user will need to investigate the cause. Common problems are stack corruption * or use of an invalid pointer. Use the Fault Status window in e2 studio or manually check the fault status * registers for more information. */ __asm volatile ( "mrs r0, cpsr \n" "bic r0, r0, %[bsp_mode_mask] \n" "orr r0, r0, %[bsp_svc_mode] \n" "msr cpsr, r0 \n" "push {lr} \n" "mov r0, lr \n" "mov r1, sp \n" "bl backtrace_fault \n" ::[bsp_mode_mask] "i" (BSP_MODE_MASK), [bsp_svc_mode] "i" (BSP_SVC_MODE) : "memory" ); while (1); BSP_CFG_HANDLE_UNRECOVERABLE_ERROR(0); }
这里栈的地址也要用SVC
1 2 3 4 5 6 7 8 9 10 11 void backtrace_fault(uint32_t fault_handler_lr, uint32_t fault_handler_sp) { uint32_t stack_pointer = fault_handler_sp; uint32_t saved_regs_addr = stack_pointer; HS_UNUSED(saved_regs_addr); stack_start_addr = (uint32_t)((uint32_t *)&__SvcStackBase); stack_size = (uint32_t)((uint32_t *)&__SvcStackLimit) - stack_start_addr; code_start_addr = (uint32_t)((uint32_t *)&_text_start); code_size = (uint32_t)((uint32_t *)&_text_end) - code_start_addr; hs_log_error(TAG, "A error has occurred."); print_backtrace(stack_pointer); }
分析一下这幅图,这是栈的存储结构,其中混合存储了参数和LR,所以我们要将它们区分出来。
我们可以通过判断指令码里是否有BL或者BLX来判断这是不是函数,pc % 2 ==0 过滤掉不是thumb指令的信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 void print_backtrace(uint32_t sp) { int deep = 0; uint32_t pc, lr; uint32_t addr[MAX_DEEP]; for (; sp < stack_start_addr + stack_size; sp += sizeof(uint32_t)) { lr = *((uint32_t *)sp); pc = lr - sizeof(uint32_t); if (pc % 2 == 0) { continue; } pc -= 1; if (pc >= code_start_addr && pc <= code_start_addr + code_size) { if (disassembly_ins_is_bl_blx(pc)) { if (deep >= MAX_DEEP) break; addr[deep] = lr; deep++; } } } while (deep > 0) { deep--; hs_log_error(TAG, "addr: %x", addr[deep]); } }