/* * Copyright (c) 2025, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2025-08-16 Rbb666 first version */ #include #include "coredump.h" #include "arch/mcd_arch_interface.h" #include "addr2line/addr2line.h" #define PRINT_COREDUMP_ELF 1 // 直接打印elf格式 #define PRINT_COREDUMP_INFO_STRING 0 // 打印字符串格式的coredump信息 #define STACK_CORE_REG_SIZE (17 * 4) // 16个自动+手动压栈寄存器 + exe_return #define STACK_FPU_REG_SIZE (16 * 4) // 16个自动压栈的浮点寄存器 static rt_int32_t is_thread_object(rt_thread_t thread) { /* Check if the object is a thread (both static and dynamic) */ return ((thread->type & ~RT_Object_Class_Static) == RT_Object_Class_Thread); } #if PRINT_COREDUMP_ELF /* * RT-Thread OS abstraction layer implementation for MCoreDump */ typedef struct { rt_int32_t thr_cnts; rt_int32_t cur_idx; } rtthread_ti_priv_t; static int32_t rtthread_thread_cnts(struct thread_info_ops *ops) { rtthread_ti_priv_t *priv = (rtthread_ti_priv_t *)ops->priv; rt_int32_t idx = 0; struct rt_object_information *information; struct rt_object *object; struct rt_list_node *node; rt_thread_t current_thread; if (-1 == priv->thr_cnts) { information = rt_object_get_information(RT_Object_Class_Thread); mcd_assert(information != RT_NULL); current_thread = rt_thread_self(); priv->cur_idx = -1; /* Initialize current thread index */ for (node = information->object_list.next; node != &(information->object_list); node = node->next) { object = rt_list_entry(node, struct rt_object, list); rt_thread_t thread = (rt_thread_t)object; if (is_thread_object(thread)) { /* Check if this is the current thread */ if (thread == current_thread) { priv->cur_idx = idx; } idx++; } } priv->thr_cnts = idx; /* If current thread not found, default to 0 */ if (priv->cur_idx == -1) { priv->cur_idx = 0; mcd_print("MCD DEBUG: Current thread not found, defaulting to index 0\n"); } } return priv->thr_cnts; } static int32_t rtthread_cur_index(struct thread_info_ops *ops) { rtthread_ti_priv_t *priv = (rtthread_ti_priv_t *)ops->priv; if (-1 == priv->cur_idx) rtthread_thread_cnts(ops); return priv->cur_idx; } static void rtthread_thread_register(struct thread_info_ops *ops, int32_t idx, core_regset_type *core_regset, fp_regset_type *fp_regset) { rt_int32_t idx_l = 0; rt_int32_t current_idx = rtthread_cur_index(ops); struct rt_object_information *information; struct rt_object *object; struct rt_list_node *node; information = rt_object_get_information(RT_Object_Class_Thread); mcd_assert(information != RT_NULL); for (node = information->object_list.next; node != &(information->object_list); node = node->next) { object = rt_list_entry(node, struct rt_object, list); rt_thread_t thread = (rt_thread_t)object; if (is_thread_object(thread)) { if (idx == idx_l) { /* If this is the current thread, use current registers */ if (idx_l == current_idx) { mcd_memcpy(core_regset, get_cur_core_regset_address(), sizeof(core_regset_type)); // 异常中填充 mcd_memcpy(fp_regset, get_cur_fp_regset_address(), sizeof(fp_regset_type)); } else { /* Debug: Dynamic thread for comparison */ collect_registers((uint32_t *)thread->sp, core_regset, fp_regset); } return; } idx_l++; } } } static int32_t rtthread_get_mem_cnts(struct thread_info_ops *ops) { return rtthread_thread_cnts(ops); } static int32_t rtthread_get_memarea(struct thread_info_ops *ops, int32_t idx, uint32_t *addr, uint32_t *memlen) { rt_int32_t idx_l = 0; rt_int32_t current_idx = rtthread_cur_index(ops); struct rt_object_information *information; struct rt_object *object; struct rt_list_node *node; information = rt_object_get_information(RT_Object_Class_Thread); mcd_assert(information != RT_NULL); for (node = information->object_list.next; node != &(information->object_list); node = node->next) { object = rt_list_entry(node, struct rt_object, list); rt_thread_t thread = (rt_thread_t)object; if (is_thread_object(thread)) { if (idx == idx_l) { /* If this is the current thread, use current stack pointer */ if (idx_l == current_idx) { *addr = get_cur_core_regset_address()->sp; // 异常中填充 *memlen = (rt_uint32_t)thread->stack_addr + thread->stack_size - (rt_uint32_t)thread->sp; *addr -= STACK_CORE_REG_SIZE; // 异常中断里面已经压栈了但还没更新tcb里面的sp指针 *memlen += STACK_CORE_REG_SIZE * 2; // 前后括大两倍:实际可能更多局部变量在死机前还没来得及向下增长sp #if MCD_FPU_SUPPORT /* Read FPU flag first - indicates if FPU context was saved */ uint32_t fpu_flag = 0 != get_cur_fp_regset_address()->fpscr; // 异常标志位肯定被置位 *addr -= 1; *memlen += 1; if (fpu_flag) { *addr -= STACK_FPU_REG_SIZE; // 异常中断里面已经压栈了但还没更新tcb里面的sp指针 *memlen += STACK_FPU_REG_SIZE; } #endif if (*memlen > thread->stack_size) { mcd_println("The stack may overflow!!!"); *memlen = thread->stack_size; } } else { *addr = (rt_uint32_t)thread->sp; *memlen = (rt_uint32_t)thread->stack_addr + thread->stack_size - (rt_uint32_t)thread->sp; } return 0; } idx_l++; } } return 0; } #endif #if PRINT_COREDUMP_INFO_STRING static int mcd_print_coredump_info_string(struct thread_info_ops *ops) { rt_thread_t current_thread = rt_thread_self(); rt_int32_t idx_l = 0; struct rt_object_information *information; struct rt_object *object; struct rt_list_node *node; uint32_t addr; uint32_t memlen; information = rt_object_get_information(RT_Object_Class_Thread); mcd_assert(information != RT_NULL); mcd_print("\n\n"); for (node = information->object_list.next; node != &(information->object_list); node = node->next) { object = rt_list_entry(node, struct rt_object, list); rt_thread_t thread = (rt_thread_t)object; if (is_thread_object(thread)) { /* If this is the current thread, use current stack pointer */ if (thread == current_thread) { uint32_t fpu_flag = 0; addr = (rt_uint32_t)get_cur_core_regset_address()->sp; // 异常中填充 memlen = (rt_uint32_t)thread->stack_addr + thread->stack_size - (rt_uint32_t)thread->sp; addr -= STACK_CORE_REG_SIZE; // 异常中断里面已经压栈了但还没更新tcb里面的sp指针 memlen += STACK_CORE_REG_SIZE * 2; // 前后括大两倍:实际可能更多局部变量在死机前还没来得及向下增长sp #if MCD_FPU_SUPPORT /* Read FPU flag first - indicates if FPU context was saved */ fpu_flag = 0 != get_cur_fp_regset_address()->fpscr; // 异常标志位肯定被置位 addr -= 1; memlen += 1; if (fpu_flag) { addr -= STACK_FPU_REG_SIZE; // 异常中断里面已经压栈了但还没更新tcb里面的sp指针 memlen += STACK_FPU_REG_SIZE; } #endif if (memlen > thread->stack_size) { mcd_println("The stack may overflow!!!"); memlen = thread->stack_size; } mcd_print("Thread index:%d (fpu:%d)\n", 200 + idx_l + 1, fpu_flag); print_registers((void *)get_cur_core_regset_address(), get_cur_fp_regset_address(), thread->name); addr2line_cmd_with_pc_print((rt_uint32_t *)get_cur_core_regset_address()->pc, (uint32_t *)addr, memlen); } else { addr = (rt_uint32_t)thread->sp; memlen = (rt_uint32_t)thread->stack_addr + thread->stack_size - addr; core_regset_type core_regset = {0}; fp_regset_type fp_regset = {0}; uint32_t use_fpu = collect_registers((uint32_t *)addr, &core_regset, &fp_regset); // rtos栈寄存器格式转换成core_regset类型的 mcd_print("Thread index:%d (fpu:%d)\n", idx_l + 1, use_fpu); print_registers(&core_regset, &fp_regset, thread->name); addr2line_cmd_with_pc_print((rt_uint32_t *)core_regset.pc, (uint32_t *)addr, memlen); } print_mem(addr, memlen); idx_l++; } } mcd_variable_dump(); return 0; } #endif void mcd_rtos_thread_ops(struct thread_info_ops *ops) { memset(ops, 0, sizeof(struct thread_info_ops)); #if PRINT_COREDUMP_ELF static rtthread_ti_priv_t priv; ops->get_threads_count = rtthread_thread_cnts; ops->get_current_thread_idx = rtthread_cur_index; ops->get_thread_regset = rtthread_thread_register; ops->get_memarea_count = rtthread_get_mem_cnts; ops->get_memarea = rtthread_get_memarea; ops->priv = &priv; priv.cur_idx = -1; priv.thr_cnts = -1; #endif #if PRINT_COREDUMP_INFO_STRING ops->print_info_string = mcd_print_coredump_info_string; #endif } MCD_WEAK rt_err_t rtt_hard_fault_exception_hook(void *context) { arch_hard_fault_exception_hook(context); addr2line_print_stack_before((uint32_t)context); //error_user_info_print(); return -RT_ERROR; } MCD_WEAK void rtt_assert_hook(const char *ex, const char *func, rt_size_t line) { volatile uint8_t _continue = 1; rt_interrupt_enter(); mcd_print("(%s) has assert failed at %s:%ld.\n", ex, func, line); mcd_faultdump(MCD_OUTPUT_SERIAL); error_user_info_print(); rt_interrupt_leave(); while (_continue == 1); } void coredump_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; rt_kprintf("z:%d\n", z); } static int mcd_coredump_init(void) { //mcd_print_memoryinfo(); rt_hw_exception_install(rtt_hard_fault_exception_hook); #ifdef RT_DEBUG rt_assert_set_hook(rtt_assert_hook); #endif return 0; } INIT_DEVICE_EXPORT(mcd_coredump_init);