Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

rtthread_port.c 11KB

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