You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

rtthread_port.c 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. /*
  2. * Copyright (c) 2025, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2025-08-16 Rbb666 first version
  9. */
  10. #include <rtthread.h>
  11. #include "coredump.h"
  12. #include "arch/mcd_arch_interface.h"
  13. #include "addr2line/addr2line.h"
  14. #define PRINT_COREDUMP_ELF 1 // 直接打印elf格式
  15. #define PRINT_COREDUMP_INFO_STRING 0 // 打印字符串格式的coredump信息
  16. #define STACK_CORE_REG_SIZE (17 * 4) // 16个自动+手动压栈寄存器 + exe_return
  17. #define STACK_FPU_REG_SIZE (16 * 4) // 16个自动压栈的浮点寄存器
  18. static rt_int32_t is_thread_object(rt_thread_t thread)
  19. {
  20. /* Check if the object is a thread (both static and dynamic) */
  21. return ((thread->type & ~RT_Object_Class_Static) == RT_Object_Class_Thread);
  22. }
  23. #if PRINT_COREDUMP_ELF
  24. /*
  25. * RT-Thread OS abstraction layer implementation for MCoreDump
  26. */
  27. typedef struct
  28. {
  29. rt_int32_t thr_cnts;
  30. rt_int32_t cur_idx;
  31. } rtthread_ti_priv_t;
  32. static int32_t rtthread_thread_cnts(struct thread_info_ops *ops)
  33. {
  34. rtthread_ti_priv_t *priv = (rtthread_ti_priv_t *)ops->priv;
  35. rt_int32_t idx = 0;
  36. struct rt_object_information *information;
  37. struct rt_object *object;
  38. struct rt_list_node *node;
  39. rt_thread_t current_thread;
  40. if (-1 == priv->thr_cnts)
  41. {
  42. information = rt_object_get_information(RT_Object_Class_Thread);
  43. mcd_assert(information != RT_NULL);
  44. current_thread = rt_thread_self();
  45. priv->cur_idx = -1; /* Initialize current thread index */
  46. for (node = information->object_list.next;
  47. node != &(information->object_list);
  48. node = node->next)
  49. {
  50. object = rt_list_entry(node, struct rt_object, list);
  51. rt_thread_t thread = (rt_thread_t)object;
  52. if (is_thread_object(thread))
  53. {
  54. /* Check if this is the current thread */
  55. if (thread == current_thread)
  56. {
  57. priv->cur_idx = idx;
  58. }
  59. idx++;
  60. }
  61. }
  62. priv->thr_cnts = idx;
  63. /* If current thread not found, default to 0 */
  64. if (priv->cur_idx == -1)
  65. {
  66. priv->cur_idx = 0;
  67. mcd_print("MCD DEBUG: Current thread not found, defaulting to index 0\n");
  68. }
  69. }
  70. return priv->thr_cnts;
  71. }
  72. static int32_t rtthread_cur_index(struct thread_info_ops *ops)
  73. {
  74. rtthread_ti_priv_t *priv = (rtthread_ti_priv_t *)ops->priv;
  75. if (-1 == priv->cur_idx)
  76. rtthread_thread_cnts(ops);
  77. return priv->cur_idx;
  78. }
  79. static void rtthread_thread_register(struct thread_info_ops *ops, int32_t idx,
  80. core_regset_type *core_regset,
  81. fp_regset_type *fp_regset)
  82. {
  83. rt_int32_t idx_l = 0;
  84. rt_int32_t current_idx = rtthread_cur_index(ops);
  85. struct rt_object_information *information;
  86. struct rt_object *object;
  87. struct rt_list_node *node;
  88. information = rt_object_get_information(RT_Object_Class_Thread);
  89. mcd_assert(information != RT_NULL);
  90. for (node = information->object_list.next; node != &(information->object_list); node = node->next)
  91. {
  92. object = rt_list_entry(node, struct rt_object, list);
  93. rt_thread_t thread = (rt_thread_t)object;
  94. if (is_thread_object(thread))
  95. {
  96. if (idx == idx_l)
  97. {
  98. /* If this is the current thread, use current registers */
  99. if (idx_l == current_idx)
  100. {
  101. mcd_memcpy(core_regset, get_cur_core_regset_address(), sizeof(core_regset_type)); // 异常中填充
  102. mcd_memcpy(fp_regset, get_cur_fp_regset_address(), sizeof(fp_regset_type));
  103. }
  104. else
  105. {
  106. /* Debug: Dynamic thread for comparison */
  107. collect_registers((uint32_t *)thread->sp, core_regset, fp_regset);
  108. }
  109. return;
  110. }
  111. idx_l++;
  112. }
  113. }
  114. }
  115. static int32_t rtthread_get_mem_cnts(struct thread_info_ops *ops)
  116. {
  117. return rtthread_thread_cnts(ops);
  118. }
  119. static int32_t rtthread_get_memarea(struct thread_info_ops *ops, int32_t idx,
  120. uint32_t *addr, uint32_t *memlen)
  121. {
  122. rt_int32_t idx_l = 0;
  123. rt_int32_t current_idx = rtthread_cur_index(ops);
  124. struct rt_object_information *information;
  125. struct rt_object *object;
  126. struct rt_list_node *node;
  127. information = rt_object_get_information(RT_Object_Class_Thread);
  128. mcd_assert(information != RT_NULL);
  129. for (node = information->object_list.next; node != &(information->object_list); node = node->next)
  130. {
  131. object = rt_list_entry(node, struct rt_object, list);
  132. rt_thread_t thread = (rt_thread_t)object;
  133. if (is_thread_object(thread))
  134. {
  135. if (idx == idx_l)
  136. {
  137. /* If this is the current thread, use current stack pointer */
  138. if (idx_l == current_idx)
  139. {
  140. *addr = get_cur_core_regset_address()->sp; // 异常中填充
  141. *memlen = (rt_uint32_t)thread->stack_addr + thread->stack_size - (rt_uint32_t)thread->sp;
  142. *addr -= STACK_CORE_REG_SIZE; // 异常中断里面已经压栈了但还没更新tcb里面的sp指针
  143. *memlen += STACK_CORE_REG_SIZE * 2; // 前后括大两倍:实际可能更多局部变量在死机前还没来得及向下增长sp
  144. #if MCD_FPU_SUPPORT
  145. /* Read FPU flag first - indicates if FPU context was saved */
  146. uint32_t fpu_flag = 0 != get_cur_fp_regset_address()->fpscr; // 异常标志位肯定被置位
  147. *addr -= 1;
  148. *memlen += 1;
  149. if (fpu_flag)
  150. {
  151. *addr -= STACK_FPU_REG_SIZE; // 异常中断里面已经压栈了但还没更新tcb里面的sp指针
  152. *memlen += STACK_FPU_REG_SIZE;
  153. }
  154. #endif
  155. if (*memlen > thread->stack_size)
  156. {
  157. mcd_println("The stack may overflow!!!");
  158. *memlen = thread->stack_size;
  159. }
  160. }
  161. else
  162. {
  163. *addr = (rt_uint32_t)thread->sp;
  164. *memlen = (rt_uint32_t)thread->stack_addr + thread->stack_size - (rt_uint32_t)thread->sp;
  165. }
  166. return 0;
  167. }
  168. idx_l++;
  169. }
  170. }
  171. return 0;
  172. }
  173. #endif
  174. #if PRINT_COREDUMP_INFO_STRING
  175. static int mcd_print_coredump_info_string(struct thread_info_ops *ops)
  176. {
  177. rt_thread_t current_thread = rt_thread_self();
  178. rt_int32_t idx_l = 0;
  179. struct rt_object_information *information;
  180. struct rt_object *object;
  181. struct rt_list_node *node;
  182. uint32_t addr;
  183. uint32_t memlen;
  184. information = rt_object_get_information(RT_Object_Class_Thread);
  185. mcd_assert(information != RT_NULL);
  186. mcd_print("\n\n");
  187. for (node = information->object_list.next; node != &(information->object_list); node = node->next)
  188. {
  189. object = rt_list_entry(node, struct rt_object, list);
  190. rt_thread_t thread = (rt_thread_t)object;
  191. if (is_thread_object(thread))
  192. {
  193. /* If this is the current thread, use current stack pointer */
  194. if (thread == current_thread)
  195. {
  196. uint32_t fpu_flag = 0;
  197. addr = (rt_uint32_t)get_cur_core_regset_address()->sp; // 异常中填充
  198. memlen = (rt_uint32_t)thread->stack_addr + thread->stack_size - (rt_uint32_t)thread->sp;
  199. addr -= STACK_CORE_REG_SIZE; // 异常中断里面已经压栈了但还没更新tcb里面的sp指针
  200. memlen += STACK_CORE_REG_SIZE * 2; // 前后括大两倍:实际可能更多局部变量在死机前还没来得及向下增长sp
  201. #if MCD_FPU_SUPPORT
  202. /* Read FPU flag first - indicates if FPU context was saved */
  203. fpu_flag = 0 != get_cur_fp_regset_address()->fpscr; // 异常标志位肯定被置位
  204. addr -= 1;
  205. memlen += 1;
  206. if (fpu_flag)
  207. {
  208. addr -= STACK_FPU_REG_SIZE; // 异常中断里面已经压栈了但还没更新tcb里面的sp指针
  209. memlen += STACK_FPU_REG_SIZE;
  210. }
  211. #endif
  212. if (memlen > thread->stack_size)
  213. {
  214. mcd_println("The stack may overflow!!!");
  215. memlen = thread->stack_size;
  216. }
  217. mcd_print("Thread index:%d (fpu:%d)\n", idx_l + 1, fpu_flag);
  218. print_registers((void *)get_cur_core_regset_address(), get_cur_fp_regset_address(), thread->name);
  219. addr2line_cmd_with_pc_print((rt_uint32_t *)get_cur_core_regset_address()->pc, (uint32_t *)addr, memlen);
  220. }
  221. else
  222. {
  223. addr = (rt_uint32_t)thread->sp;
  224. memlen = (rt_uint32_t)thread->stack_addr + thread->stack_size - addr;
  225. core_regset_type core_regset = {0};
  226. fp_regset_type fp_regset = {0};
  227. uint32_t use_fpu = collect_registers((uint32_t *)addr, &core_regset, &fp_regset); // rtos栈寄存器格式转换成core_regset类型的
  228. mcd_print("Thread index:%d (fpu:%d)\n", idx_l + 1, use_fpu);
  229. print_registers(&core_regset, &fp_regset, thread->name);
  230. addr2line_cmd_with_pc_print((rt_uint32_t *)core_regset.pc, (uint32_t *)addr, memlen);
  231. }
  232. print_mem(addr, memlen);
  233. idx_l++;
  234. }
  235. }
  236. mcd_variable_dump();
  237. return 0;
  238. }
  239. #endif
  240. void mcd_rtos_thread_ops(struct thread_info_ops *ops)
  241. {
  242. memset(ops, 0, sizeof(struct thread_info_ops));
  243. #if PRINT_COREDUMP_ELF
  244. static rtthread_ti_priv_t priv;
  245. ops->get_threads_count = rtthread_thread_cnts;
  246. ops->get_current_thread_idx = rtthread_cur_index;
  247. ops->get_thread_regset = rtthread_thread_register;
  248. ops->get_memarea_count = rtthread_get_mem_cnts;
  249. ops->get_memarea = rtthread_get_memarea;
  250. ops->priv = &priv;
  251. priv.cur_idx = -1;
  252. priv.thr_cnts = -1;
  253. #endif
  254. #if PRINT_COREDUMP_INFO_STRING
  255. ops->print_info_string = mcd_print_coredump_info_string;
  256. #endif
  257. }
  258. MCD_WEAK rt_err_t rtt_hard_fault_exception_hook(void *context)
  259. {
  260. arch_hard_fault_exception_hook(context);
  261. addr2line_print_stack_before((uint32_t)context);
  262. //error_user_info_print();
  263. return -RT_ERROR;
  264. }
  265. MCD_WEAK void rtt_assert_hook(const char *ex, const char *func, rt_size_t line)
  266. {
  267. volatile uint8_t _continue = 1;
  268. rt_interrupt_enter();
  269. mcd_print("(%s) has assert failed at %s:%ld.\n", ex, func, line);
  270. mcd_faultdump(MCD_OUTPUT_SERIAL);
  271. error_user_info_print();
  272. rt_interrupt_leave();
  273. while (_continue == 1);
  274. }
  275. void coredump_trigger_exception(void)
  276. {
  277. volatile int *SCB_CCR = (volatile int *)0xE000ED14; // SCB->CCR
  278. int x, y, z;
  279. *SCB_CCR |= (1 << 4); /* bit4: DIV_0_TRP. */
  280. x = 10;
  281. y = strlen("");
  282. z = x / y;
  283. rt_kprintf("z:%d\n", z);
  284. }
  285. static int mcd_coredump_init(void)
  286. {
  287. //mcd_print_memoryinfo();
  288. rt_hw_exception_install(rtt_hard_fault_exception_hook);
  289. #ifdef RT_DEBUG
  290. rt_assert_set_hook(rtt_assert_hook);
  291. #endif
  292. return 0;
  293. }
  294. INIT_DEVICE_EXPORT(mcd_coredump_init);