| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342 |
- /*
- * 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 <rtthread.h>
- #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", 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);
|