您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

coredump2.c 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. // SPDX-License-Identifier: GPL-3.0-only
  2. /*
  3. * Copyright (c) 2008-2023 100askTeam : Dongshan WEI <weidongshan@qq.com>
  4. * Discourse: https://forums.100ask.net
  5. */
  6. /* Copyright (C) 2008-2023 深圳百问网科技有限公司
  7. * All rights reserved
  8. *
  9. * 免责声明: 百问网编写的文档, 仅供学员学习使用, 可以转发或引用(请保留作者信息),禁止用于商业用途!
  10. * 免责声明: 百问网编写的程序, 可以用于商业用途, 但百问网不承担任何后果!
  11. *
  12. * 本程序遵循GPL V3协议, 请遵循协议
  13. * 百问网学习平台 : https://www.100ask.net
  14. * 百问网交流社区 : https://forums.100ask.net
  15. * 百问网官方B站 : https://space.bilibili.com/275908810
  16. * 百问网官方淘宝 : https://100ask.taobao.com
  17. * 联系我们(E-mail): weidongshan@qq.com
  18. *
  19. * 版权所有,盗版必究。
  20. *
  21. * 修改历史 版本号 作者 修改内容
  22. *-----------------------------------------------------
  23. * 2024.09.20 v01 百问科技 创建文件
  24. *-----------------------------------------------------
  25. */
  26. #include <stdbool.h>
  27. #include <stdint.h>
  28. #include "main.h"
  29. struct exception_stack_frame
  30. {
  31. rt_uint32_t r0;
  32. rt_uint32_t r1;
  33. rt_uint32_t r2;
  34. rt_uint32_t r3;
  35. rt_uint32_t r12;
  36. rt_uint32_t lr;
  37. rt_uint32_t pc;
  38. rt_uint32_t psr;
  39. };
  40. struct stack_frame
  41. {
  42. #if USE_FPU
  43. rt_uint32_t flag;
  44. #endif /* USE_FPU */
  45. /* r4 ~ r11 register */
  46. rt_uint32_t r4;
  47. rt_uint32_t r5;
  48. rt_uint32_t r6;
  49. rt_uint32_t r7;
  50. rt_uint32_t r8;
  51. rt_uint32_t r9;
  52. rt_uint32_t r10;
  53. rt_uint32_t r11;
  54. struct exception_stack_frame exception_stack_frame;
  55. };
  56. struct exception_info
  57. {
  58. rt_uint32_t exc_return;
  59. struct stack_frame stack_frame;
  60. };
  61. #if defined(__ARMCC_VERSION)
  62. /* C stack block name, default is STACK */
  63. #ifndef CMB_CSTACK_BLOCK_NAME
  64. #define CMB_CSTACK_BLOCK_NAME Image$$ARM_LIB_STACK$$ZI
  65. #endif
  66. /* code section name, default is ER_IROM1 */
  67. #ifndef CMB_CODE_SECTION_NAME
  68. #define CMB_CODE_SECTION_NAME FLASH_CODE
  69. #endif
  70. #elif defined(__ICCARM__)
  71. /* C stack block name, default is 'CSTACK' */
  72. #ifndef CMB_CSTACK_BLOCK_NAME
  73. #define CMB_CSTACK_BLOCK_NAME "CSTACK"
  74. #endif
  75. /* code section name, default is '.text' */
  76. #ifndef CMB_CODE_SECTION_NAME
  77. #define CMB_CODE_SECTION_NAME ".text"
  78. #endif
  79. #elif defined(__GNUC__)
  80. /* C stack block start address, defined on linker script file, default is _sstack */
  81. #ifndef CMB_CSTACK_BLOCK_START
  82. #define CMB_CSTACK_BLOCK_START _sstack
  83. #endif
  84. /* C stack block end address, defined on linker script file, default is _estack */
  85. #ifndef CMB_CSTACK_BLOCK_END
  86. #define CMB_CSTACK_BLOCK_END _estack
  87. #endif
  88. /* code section start address, defined on linker script file, default is _stext */
  89. #ifndef CMB_CODE_SECTION_START
  90. #define CMB_CODE_SECTION_START _stext
  91. #endif
  92. /* code section end address, defined on linker script file, default is _etext */
  93. #ifndef CMB_CODE_SECTION_END
  94. #define CMB_CODE_SECTION_END _etext
  95. #endif
  96. #else
  97. #error "not supported compiler"
  98. #endif
  99. #if __STDC_VERSION__ < 199901L
  100. #error "must be C99 or higher. try to add '-std=c99' to compile parameters"
  101. #endif
  102. #if defined(__CC_ARM)
  103. #define SECTION_START(_name_) _name_##$$Base
  104. #define SECTION_END(_name_) _name_##$$Limit
  105. #define IMAGE_SECTION_START(_name_) Image$$##_name_##$$Base
  106. #define IMAGE_SECTION_END(_name_) Image$$##_name_##$$Limit
  107. #define CSTACK_BLOCK_START(_name_) SECTION_START(_name_)
  108. #define CSTACK_BLOCK_END(_name_) SECTION_END(_name_)
  109. #define CODE_SECTION_START(_name_) IMAGE_SECTION_START(_name_)
  110. #define CODE_SECTION_END(_name_) IMAGE_SECTION_END(_name_)
  111. extern const int CSTACK_BLOCK_START(CMB_CSTACK_BLOCK_NAME);
  112. extern const int CSTACK_BLOCK_END(CMB_CSTACK_BLOCK_NAME);
  113. extern const int CODE_SECTION_START(CMB_CODE_SECTION_NAME);
  114. extern const int CODE_SECTION_END(CMB_CODE_SECTION_NAME);
  115. #elif defined(__ICCARM__)
  116. #pragma section=CMB_CSTACK_BLOCK_NAME
  117. #pragma section=CMB_CODE_SECTION_NAME
  118. #elif defined(__GNUC__)
  119. extern const int CMB_CSTACK_BLOCK_START;
  120. extern const int CMB_CSTACK_BLOCK_END;
  121. extern const int CMB_CODE_SECTION_START;
  122. extern const int CMB_CODE_SECTION_END;
  123. #else
  124. #error "not supported compiler"
  125. #endif
  126. static bool is_in_text(uint32_t addr)
  127. {
  128. #if 0
  129. uint32_t code_start_addr = (uint32_t)&CODE_SECTION_START(CMB_CODE_SECTION_NAME);
  130. uint32_t code_size = (uint32_t)&CODE_SECTION_END(CMB_CODE_SECTION_NAME) - code_start_addr;
  131. #else
  132. uint32_t code_start_addr = (uint32_t)__section_begin(CMB_CODE_SECTION_NAME);
  133. uint32_t code_size = (uint32_t)__section_end(CMB_CODE_SECTION_NAME) - code_start_addr;
  134. #endif
  135. if (code_start_addr < addr && addr <= code_start_addr + code_size)
  136. {
  137. return true;
  138. }
  139. return false;
  140. }
  141. static bool disassembly_ins_is_bl_blx(uint32_t addr)
  142. {
  143. #define BL_INS_MASK 0xF800
  144. #define BL_INS_HIGH 0xF800
  145. #define BL_INS_LOW 0xF000
  146. #define BLX_INX_MASK 0xFF00
  147. #define BLX_INX 0x4700
  148. uint16_t ins1 = *((uint16_t *)addr);
  149. uint16_t ins2 = *((uint16_t *)(addr + 2));
  150. if ((ins2 & BL_INS_MASK) == BL_INS_HIGH && (ins1 & BL_INS_MASK) == BL_INS_LOW)
  151. {
  152. return true;
  153. }
  154. else if ((ins2 & BLX_INX_MASK) == BLX_INX)
  155. {
  156. return true;
  157. }
  158. else
  159. {
  160. return false;
  161. }
  162. }
  163. void svc_exception(struct exception_info *exception_info)
  164. {
  165. //struct exception_stack_frame *exception_stack = &exception_info->stack_frame.exception_stack_frame;
  166. struct stack_frame *context = &exception_info->stack_frame;
  167. unsigned int addr;
  168. unsigned short swi_inst;
  169. unsigned int *old_sp;
  170. unsigned int value;
  171. /* 取出swi指令 */
  172. addr = context->exception_stack_frame.pc;
  173. addr -= 2;
  174. swi_inst = *((unsigned short *)addr);
  175. rt_kprintf("swi_inst = 0x%04x\n", swi_inst);
  176. swi_inst = swi_inst & 0xff;
  177. /* 分析swi指令 */
  178. old_sp = (unsigned int *)(exception_info + 1); // 得到栈顶
  179. unsigned int *p_reg = &context->exception_stack_frame.r0; // 得到r0的地址
  180. if (swi_inst == 0xff)
  181. {
  182. /* POP {PC} */
  183. value = *old_sp;
  184. old_sp++;
  185. context->exception_stack_frame.pc = value;
  186. }
  187. else
  188. {
  189. for (int i = 0; i < 8; i ++)
  190. {
  191. if (swi_inst & (1 << i))
  192. {
  193. /* POP {r0, PC} */
  194. value = *old_sp;
  195. old_sp++;
  196. p_reg[i] = value; // 哪个寄存器就保存哪个值
  197. /* POP {PC} */
  198. value = *old_sp;
  199. old_sp++;
  200. context->exception_stack_frame.pc = value;
  201. }
  202. }
  203. }
  204. rt_kprintf("old_sp = 0x%0x\n", old_sp);
  205. rt_kprintf("context->exception_stack_frame.pc= 0x%0x\n", context->exception_stack_frame.pc);
  206. /* 模拟swi指令 */
  207. struct exception_info stack_frame = *exception_info;
  208. unsigned int old_pos = (unsigned int)(exception_info + 1);
  209. unsigned int new_pos = (unsigned int)old_sp;
  210. unsigned int offset = new_pos - old_pos;
  211. exception_info = (struct exception_info *)((unsigned int)exception_info + offset);
  212. *exception_info = stack_frame;
  213. /* 返回 */
  214. }
  215. void rt_hw_hard_fault_exception(struct exception_info *exception_info)
  216. {
  217. #if 0
  218. //struct exception_stack_frame *exception_stack = &exception_info->stack_frame.exception_stack_frame;
  219. struct stack_frame *context = &exception_info->stack_frame;
  220. rt_kprintf("psr: 0x%08x\n", context->exception_stack_frame.psr);
  221. rt_kprintf("r00: 0x%08x\n", context->exception_stack_frame.r0);
  222. rt_kprintf("r01: 0x%08x\n", context->exception_stack_frame.r1);
  223. rt_kprintf("r02: 0x%08x\n", context->exception_stack_frame.r2);
  224. rt_kprintf("r03: 0x%08x\n", context->exception_stack_frame.r3);
  225. rt_kprintf("r04: 0x%08x\n", context->r4);
  226. rt_kprintf("r05: 0x%08x\n", context->r5);
  227. rt_kprintf("r06: 0x%08x\n", context->r6);
  228. rt_kprintf("r07: 0x%08x\n", context->r7);
  229. rt_kprintf("r08: 0x%08x\n", context->r8);
  230. rt_kprintf("r09: 0x%08x\n", context->r9);
  231. rt_kprintf("r10: 0x%08x\n", context->r10);
  232. rt_kprintf("r11: 0x%08x\n", context->r11);
  233. rt_kprintf("r12: 0x%08x\n", context->exception_stack_frame.r12);
  234. rt_kprintf(" lr: 0x%08x\n", context->exception_stack_frame.lr);
  235. rt_kprintf(" pc: 0x%08x\n", context->exception_stack_frame.pc);
  236. rt_kprintf("use command: addr2line -e your.out -a -f ");
  237. rt_kprintf("%08x ", context->exception_stack_frame.pc);
  238. rt_kprintf("%08x ", context->exception_stack_frame.lr);
  239. uint32_t lr;
  240. uint32_t pc;
  241. uint32_t *app_sp = (unsigned int *)(exception_info + 1); // 得到栈顶;
  242. for(int i = 0; i < 1024; i++)
  243. {
  244. lr = *app_sp;
  245. app_sp++;
  246. if ((lr & 0x01) && true == is_in_text(lr))
  247. {
  248. pc = (lr & ~0x01) - 4;
  249. if (true == disassembly_ins_is_bl_blx(pc))
  250. {
  251. rt_kprintf("%08x ", pc);
  252. }
  253. }
  254. }
  255. #else
  256. void DumpCore(struct stack_frame *sp);
  257. DumpCore(&exception_info->stack_frame);
  258. #endif
  259. while(1);
  260. }
  261. /**********************************************************************
  262. * 函数名称: DumpRegisters
  263. * 功能描述: 打印寄存器的值
  264. * 输入参数: sp - hardfault.s里设置的这个参数,它是栈的地址
  265. * thread - 线程名
  266. * 输出参数: 无
  267. * 返 回 值: 无
  268. * 修改日期 版本号 修改人 修改内容
  269. * -----------------------------------------------
  270. * 2023/09/20 V1.0 韦东山 创建
  271. ***********************************************************************/
  272. static void DumpRegisters(struct stack_frame *sp, char *thread)
  273. {
  274. rt_kprintf("Registers@%s\n", thread);
  275. rt_kprintf("R0: 0x%08X\n", sp->exception_stack_frame.r0);
  276. rt_kprintf("R1: 0x%08X\n", sp->exception_stack_frame.r1);
  277. rt_kprintf("R2: 0x%08X\n", sp->exception_stack_frame.r2);
  278. rt_kprintf("R3: 0x%08X\n", sp->exception_stack_frame.r3);
  279. rt_kprintf("R4: 0x%08X\n", sp->r4);
  280. rt_kprintf("R5: 0x%08X\n", sp->r5);
  281. rt_kprintf("R6: 0x%08X\n", sp->r6);
  282. rt_kprintf("R7: 0x%08X\n", sp->r7);
  283. rt_kprintf("R8: 0x%08X\n", sp->r8);
  284. rt_kprintf("R9: 0x%08X\n", sp->r9);
  285. rt_kprintf("R10: 0x%08X\n", sp->r10);
  286. rt_kprintf("R11: 0x%08X\n", sp->r11);
  287. rt_kprintf("R12: 0x%08X\n", sp->exception_stack_frame.r12);
  288. rt_kprintf("R13(SP): 0x%08X\n", (uint32_t)sp + sizeof(*sp));
  289. rt_kprintf("R14(LR): 0x%08X\n", sp->exception_stack_frame.lr);
  290. rt_kprintf("R15(PC): 0x%08X\n", sp->exception_stack_frame.pc);
  291. rt_kprintf("xPSR: 0x%08X\n", sp->exception_stack_frame.psr);
  292. }
  293. /**********************************************************************
  294. * 函数名称: DumpMem
  295. * 功能描述: 打印内存的值
  296. * 输入参数: addr - 内存起始地址(4对齐)
  297. * len - 内存长度(4对齐)
  298. * 输出参数: 无
  299. * 返 回 值: 无
  300. * 修改日期 版本号 修改人 修改内容
  301. * -----------------------------------------------
  302. * 2023/09/20 V1.0 韦东山 创建
  303. ***********************************************************************/
  304. static void DumpMem(uint32_t addr, uint32_t len)
  305. {
  306. uint32_t *paddr;
  307. uint32_t i;
  308. paddr = (uint32_t *)addr;
  309. rt_kprintf("mem@0x%08X, 0x%08X\n", addr, len);
  310. for (i = 0; i < len;)
  311. {
  312. rt_kprintf("0x%08X", *paddr);
  313. paddr++;
  314. i+= 4;
  315. if (i % 16 == 0)
  316. rt_kprintf("\n");
  317. else
  318. rt_kprintf(" ");
  319. }
  320. rt_kprintf("\n");
  321. }
  322. /**********************************************************************
  323. * 函数名称: DumpCore
  324. * 功能描述: 打印寄存器、内存的值
  325. * 输入参数: sp - hardfault.s里设置的这个参数,它是栈的地址
  326. * 输出参数: 无
  327. * 返 回 值: 无
  328. * 修改日期 版本号 修改人 修改内容
  329. * -----------------------------------------------
  330. * 2023/09/20 V1.0 韦东山 创建
  331. ***********************************************************************/
  332. #pragma section=".data"
  333. #pragma section=".bss"
  334. void DumpCore(struct stack_frame *sp)
  335. {
  336. /* 打印寄存器 */
  337. DumpRegisters(sp, "current_thread");
  338. /* 打印数据段 */
  339. uint32_t start = (uint32_t)__section_begin(".data");
  340. uint32_t end = (uint32_t)__section_end(".data");
  341. rt_kprintf("Data segment:\n");
  342. DumpMem(start, end - start);
  343. /* 打印ZI段 */
  344. rt_kprintf("ZI segment:\n");
  345. start = (uint32_t)__section_begin(".bss");
  346. end = (uint32_t)__section_end(".bss");
  347. DumpMem(start, end - start);
  348. /* 打印栈 */
  349. rt_kprintf("Stack segment:\n");
  350. DumpMem((uint32_t)sp + sizeof(*sp), 1024);
  351. }