backtrace.c 9.8 KB

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