backtrace.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. #include <string.h>
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include "libs/backtrace.h"
  5. #include "bsp/gd32_bkp.h"
  6. #if defined(__CC_ARM)
  7. #define SECTION_START(_name_) _name_##$$Base
  8. #define SECTION_END(_name_) _name_##$$Limit
  9. #define IMAGE_SECTION_START(_name_) Image$$##_name_##$$Base
  10. #define IMAGE_SECTION_END(_name_) Image$$##_name_##$$Limit
  11. #define CSTACK_BLOCK_START(_name_) SECTION_START(_name_)
  12. #define CSTACK_BLOCK_END(_name_) SECTION_END(_name_)
  13. #define CODE_SECTION_START(_name_) IMAGE_SECTION_START(_name_)
  14. #define CODE_SECTION_END(_name_) IMAGE_SECTION_END(_name_)
  15. extern const int CSTACK_BLOCK_START(CMB_CSTACK_BLOCK_NAME);
  16. extern const int CSTACK_BLOCK_END(CMB_CSTACK_BLOCK_NAME);
  17. extern const int CODE_SECTION_START(CMB_CODE_SECTION_NAME);
  18. extern const int CODE_SECTION_END(CMB_CODE_SECTION_NAME);
  19. #elif defined(__ICCARM__)
  20. #pragma section=CMB_CSTACK_BLOCK_NAME
  21. #pragma section=CMB_CODE_SECTION_NAME
  22. #elif defined(__GNUC__)
  23. extern const int CMB_CSTACK_BLOCK_START;
  24. extern const int CMB_CSTACK_BLOCK_END;
  25. extern const int CMB_CODE_SECTION_START;
  26. extern const int CMB_CODE_SECTION_END;
  27. #else
  28. #error "not supported compiler"
  29. #endif
  30. //extern int STACK$$Base;
  31. static void get_cur_thread_stack_info(uint32_t sp, uint32_t *start_addr, size_t *size) {
  32. *start_addr = SECTION_START(STACK);//(uint32_t)vTaskStackAddr();
  33. *size = SECTION_END(STACK) - SECTION_START(STACK);//vTaskStackSize() * sizeof( StackType_t );
  34. }
  35. #ifdef __TARGET_FPU_VFP
  36. static uint32_t statck_del_fpu_regs(uint32_t fault_handler_lr, uint32_t sp) {
  37. bool statck_has_fpu_regs = (fault_handler_lr & (1UL << 4)) == 0 ? true : false;
  38. /* the stack has S0~S15 and FPSCR registers when statck_has_fpu_regs is true, double word align */
  39. return statck_has_fpu_regs == true ? sp + sizeof(size_t) * 18 : sp;
  40. }
  41. #endif
  42. /* check the disassembly instruction is 'BL' or 'BLX' */
  43. static bool disassembly_ins_is_bl_blx(uint32_t addr) {
  44. uint16_t ins1 = *((uint16_t *)addr);
  45. uint16_t ins2 = *((uint16_t *)(addr + 2));
  46. #define BL_INS_MASK 0xF800
  47. #define BL_INS_HIGH 0xF800
  48. #define BL_INS_LOW 0xF000
  49. #define BLX_INX_MASK 0xFF00
  50. #define BLX_INX 0x4700
  51. if ((ins2 & BL_INS_MASK) == BL_INS_HIGH && (ins1 & BL_INS_MASK) == BL_INS_LOW) {
  52. return true;
  53. } else if ((ins2 & BLX_INX_MASK) == BLX_INX) {
  54. return true;
  55. } else {
  56. return false;
  57. }
  58. }
  59. static uint32_t main_stack_start_addr;
  60. static size_t main_stack_size;
  61. static uint32_t code_start_addr;
  62. static size_t code_size;
  63. static uint32_t call_stack_buf[CMB_CALL_STACK_MAX_DEPTH] = {0};
  64. void backtrace_init(void){
  65. main_stack_start_addr = (uint32_t)&CSTACK_BLOCK_START(CMB_CSTACK_BLOCK_NAME);
  66. main_stack_size = (uint32_t)&CSTACK_BLOCK_END(CMB_CSTACK_BLOCK_NAME) - main_stack_start_addr;
  67. code_start_addr = (uint32_t)&CODE_SECTION_START(CMB_CODE_SECTION_NAME);
  68. code_size = (uint32_t)&CODE_SECTION_END(CMB_CODE_SECTION_NAME) - code_start_addr;
  69. }
  70. void backtrace_assert(int line) {
  71. uint32_t stack_start_addr = main_stack_start_addr, pc;
  72. size_t depth = 0, stack_size = main_stack_size;
  73. bool regs_saved_lr_is_valid = false;
  74. bool stack_is_overflow = false;
  75. uint32_t sp = cmb_get_sp();
  76. /* OS environment */
  77. get_cur_thread_stack_info(sp, &stack_start_addr, &stack_size);
  78. if ((sp < stack_start_addr) || (sp > (stack_start_addr + stack_size))) {
  79. stack_is_overflow = true;
  80. }
  81. if (stack_is_overflow) {
  82. if (sp < stack_start_addr) {
  83. sp = stack_start_addr;
  84. } else if (sp > stack_start_addr + stack_size) {
  85. sp = stack_start_addr + stack_size;
  86. }
  87. }
  88. /* copy called function address */
  89. for (; sp < stack_start_addr + stack_size; sp += sizeof(size_t)) {
  90. /* the *sp value may be LR, so need decrease a word to PC */
  91. pc = *((uint32_t *) sp) - sizeof(size_t);
  92. /* the Cortex-M using thumb instruction, so the pc must be an odd number */
  93. if (pc % 2 == 0) {
  94. continue;
  95. }
  96. /* fix the PC address in thumb mode */
  97. pc = *((uint32_t *) sp) - 1;
  98. if ((pc >= code_start_addr) && (pc <= code_start_addr + code_size) && (depth < CMB_CALL_STACK_MAX_DEPTH)
  99. /* check the the instruction before PC address is 'BL' or 'BLX' */
  100. && disassembly_ins_is_bl_blx(pc - sizeof(size_t)) && (depth < CMB_CALL_STACK_MAX_DEPTH)) {
  101. /* the second depth function may be already saved, so need ignore repeat */
  102. if ((depth == 2) && regs_saved_lr_is_valid && (pc == call_stack_buf[1])) {
  103. continue;
  104. }
  105. call_stack_buf[depth++] = pc;
  106. }
  107. }
  108. gd32_bkp_save_backtrace(call_stack_buf, stack_is_overflow, depth, line);
  109. NVIC_SystemReset();
  110. }
  111. void fault_backtrace(uint32_t fault_handler_lr, uint32_t fault_handler_sp) {
  112. uint32_t stack_pointer = fault_handler_sp, saved_regs_addr = stack_pointer;
  113. struct cmb_hard_fault_regs regs;
  114. uint32_t stack_start_addr = main_stack_start_addr;
  115. size_t stack_size = main_stack_size;
  116. bool stack_is_overflow = false;
  117. bool on_fault = true;
  118. bool on_thread_before_fault = fault_handler_lr & (1UL << 2);
  119. /* check which stack was used before (MSP or PSP) */
  120. if (on_thread_before_fault) {
  121. saved_regs_addr = stack_pointer = cmb_get_psp();
  122. get_cur_thread_stack_info(stack_pointer, &stack_start_addr, &stack_size);
  123. }
  124. /* delete saved R0~R3, R12, LR,PC,xPSR registers space */
  125. stack_pointer += sizeof(size_t) * 8;
  126. #ifdef __TARGET_FPU_VFP
  127. stack_pointer = statck_del_fpu_regs(fault_handler_lr, stack_pointer);
  128. #endif /* (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M4) || (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M7) */
  129. /* check stack overflow */
  130. if ((stack_pointer < stack_start_addr) || (stack_pointer > (stack_start_addr + stack_size))) {
  131. stack_is_overflow = true;
  132. }
  133. /* the stack frame may be get failed when it is overflow */
  134. if (!stack_is_overflow) {
  135. /* dump register */
  136. regs.saved.r0 = ((uint32_t *)saved_regs_addr)[0]; // Register R0
  137. regs.saved.r1 = ((uint32_t *)saved_regs_addr)[1]; // Register R1
  138. regs.saved.r2 = ((uint32_t *)saved_regs_addr)[2]; // Register R2
  139. regs.saved.r3 = ((uint32_t *)saved_regs_addr)[3]; // Register R3
  140. regs.saved.r12 = ((uint32_t *)saved_regs_addr)[4]; // Register R12
  141. regs.saved.lr = ((uint32_t *)saved_regs_addr)[5]; // Link register LR
  142. regs.saved.pc = ((uint32_t *)saved_regs_addr)[6]; // Program counter PC
  143. regs.saved.psr.value = ((uint32_t *)saved_regs_addr)[7]; // Program status word PSR
  144. }
  145. /* the Cortex-M0 is not support fault diagnosis */
  146. regs.syshndctrl.value = CMB_SYSHND_CTRL; // System Handler Control and State Register
  147. regs.mfsr.value = CMB_NVIC_MFSR; // Memory Fault Status Register
  148. regs.mmar = CMB_NVIC_MMAR; // Memory Management Fault Address Register
  149. regs.bfsr.value = CMB_NVIC_BFSR; // Bus Fault Status Register
  150. regs.bfar = CMB_NVIC_BFAR; // Bus Fault Manage Address Register
  151. regs.ufsr.value = CMB_NVIC_UFSR; // Usage Fault Status Register
  152. regs.hfsr.value = CMB_NVIC_HFSR; // Hard Fault Status Register
  153. regs.dfsr.value = CMB_NVIC_DFSR; // Debug Fault Status Register
  154. regs.afsr = CMB_NVIC_AFSR; // Auxiliary Fault Status Register
  155. {
  156. uint32_t stack_start_addr = main_stack_start_addr, pc;
  157. size_t depth = 0, stack_size = main_stack_size;
  158. bool regs_saved_lr_is_valid = false;
  159. uint32_t sp = stack_pointer;
  160. if (on_fault) {
  161. if (!stack_is_overflow) {
  162. /* first depth is PC */
  163. call_stack_buf[depth++] = regs.saved.pc;
  164. /* fix the LR address in thumb mode */
  165. #if 0
  166. pc = regs.saved.lr - 1;
  167. if ((pc >= code_start_addr) && (pc <= code_start_addr + code_size) && (depth < CMB_CALL_STACK_MAX_DEPTH)
  168. && (depth < CMB_CALL_STACK_MAX_DEPTH)) {
  169. call_stack_buf[depth++] = pc;
  170. regs_saved_lr_is_valid = true;
  171. }
  172. #endif
  173. }
  174. /* program is running on thread before fault */
  175. if (on_thread_before_fault) {
  176. get_cur_thread_stack_info(sp, &stack_start_addr, &stack_size);
  177. }
  178. } else {
  179. /* OS environment */
  180. if (cmb_get_sp() == cmb_get_psp()) {
  181. get_cur_thread_stack_info(sp, &stack_start_addr, &stack_size);
  182. }
  183. }
  184. if (stack_is_overflow) {
  185. if (sp < stack_start_addr) {
  186. sp = stack_start_addr;
  187. } else if (sp > stack_start_addr + stack_size) {
  188. sp = stack_start_addr + stack_size;
  189. }
  190. }
  191. /* copy called function address */
  192. for (; sp < stack_start_addr + stack_size; sp += sizeof(size_t)) {
  193. /* the *sp value may be LR, so need decrease a word to PC */
  194. pc = *((uint32_t *) sp) - sizeof(size_t);
  195. /* the Cortex-M using thumb instruction, so the pc must be an odd number */
  196. if (pc % 2 == 0) {
  197. continue;
  198. }
  199. /* fix the PC address in thumb mode */
  200. pc = *((uint32_t *) sp) - 1;
  201. if ((pc >= code_start_addr) && (pc <= code_start_addr + code_size) && (depth < CMB_CALL_STACK_MAX_DEPTH)
  202. /* check the the instruction before PC address is 'BL' or 'BLX' */
  203. && disassembly_ins_is_bl_blx(pc - sizeof(size_t)) && (depth < CMB_CALL_STACK_MAX_DEPTH)) {
  204. /* the second depth function may be already saved, so need ignore repeat */
  205. if ((depth == 2) && regs_saved_lr_is_valid && (pc == call_stack_buf[1])) {
  206. continue;
  207. }
  208. call_stack_buf[depth++] = pc;
  209. }
  210. }
  211. gd32_bkp_save_backtrace(call_stack_buf, stack_is_overflow, depth, 0);
  212. }
  213. NVIC_SystemReset();
  214. }