mips_backtrace.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /*
  2. * File : mips_backtrace.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2008 - 2012, RT-Thread Development Team
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program; if not, write to the Free Software Foundation, Inc.,
  18. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  19. *
  20. * Change Logs:
  21. * Date Author Notes
  22. * 2016Äê9ÔÂ11ÈÕ Urey the first version
  23. */
  24. #include <rtthread.h>
  25. #include <stdlib.h>
  26. #include <stdio.h>
  27. #include <stdint.h>
  28. #include "mips.h"
  29. /*********************************************************************************************************
  30. Ö¸ÁÒå
  31. *********************************************************************************************************/
  32. #define ADDUI_SP_INST 0x27bd0000
  33. #define SW_RA_INST 0xafbf0000
  34. #define JR_RA_INST 0x03e00008
  35. #define INST_OP_MASK 0xffff0000
  36. #define INST_OFFSET_MASK 0x0000ffff
  37. #define abs(s) ((s) < 0 ? -(s):(s))
  38. int backtrace_ctx(mips_reg_ctx *ctx)
  39. {
  40. unsigned long *addr;
  41. unsigned long *pc, *ra, *sp;
  42. size_t ra_offset;
  43. size_t stack_size;
  44. int depth;
  45. int size = 8;
  46. pc = (unsigned long *)(unsigned long)ctx->CP0EPC;
  47. ra = (unsigned long *)(unsigned long)ctx->regs[REG_RA];
  48. sp = (unsigned long *)(unsigned long)ctx->regs[REG_SP];
  49. rt_kprintf("[0x%08x]\n", pc);
  50. if (size == 1) return 1;
  51. ra_offset = stack_size = 0;
  52. for (addr = ra; !ra_offset || !stack_size; --addr)
  53. {
  54. switch (*addr & INST_OP_MASK) {
  55. case ADDUI_SP_INST:
  56. stack_size = abs((short)(*addr&INST_OFFSET_MASK));
  57. break;
  58. case SW_RA_INST:
  59. ra_offset = (short)(*addr&INST_OFFSET_MASK);
  60. break;
  61. case 0x3c1c0000:
  62. goto out_of_loop;
  63. default:
  64. break;
  65. }
  66. }
  67. out_of_loop:
  68. if (ra_offset) ra = *(unsigned long **)((unsigned long)sp + ra_offset);
  69. if (stack_size) sp = (unsigned long *)((unsigned long)sp + stack_size);
  70. // repeat backwar scanning
  71. for (depth = 1; depth < size && ra && ra != (unsigned long *)0xffffffff; ++depth)
  72. {
  73. rt_kprintf("RA[%2d] : [0x%08x]\n", depth ,ra);
  74. ra_offset = 0;
  75. stack_size = 0;
  76. for ( addr = ra; !ra_offset || !stack_size; -- addr )
  77. {
  78. switch( *addr & INST_OP_MASK)
  79. {
  80. case ADDUI_SP_INST:
  81. stack_size = abs((short)(*addr&INST_OFFSET_MASK));
  82. break;
  83. case SW_RA_INST:
  84. ra_offset = abs((short)(*addr&INST_OFFSET_MASK));
  85. break;
  86. case 0x3c1c0000:
  87. return depth +1;
  88. default:
  89. break;
  90. }
  91. }
  92. ra = *(unsigned long **)((unsigned long)sp + ra_offset);
  93. sp = (unsigned long *)((unsigned long)sp + stack_size);
  94. }
  95. return depth;
  96. }
  97. int backtrace(void)
  98. {
  99. unsigned long *addr;
  100. unsigned long *ra;
  101. unsigned long *sp;
  102. int size = 8, depth;
  103. size_t ra_offset;
  104. size_t stack_size;
  105. // get current $a and $sp
  106. __asm__ __volatile__ (
  107. " move %0, $ra\n"
  108. " move %1, $sp\n"
  109. : "=r"(ra), "=r"(sp)
  110. );
  111. // scanning to find the size of hte current stack frame
  112. stack_size = 0;
  113. for ( addr = (unsigned long *)backtrace; !stack_size; ++addr)
  114. {
  115. if ((*addr & INST_OP_MASK ) == ADDUI_SP_INST )
  116. stack_size = abs((short)(*addr&INST_OFFSET_MASK));
  117. else if ( *addr == JR_RA_INST )
  118. break;
  119. }
  120. sp = (unsigned long *) (( unsigned long )sp + stack_size);
  121. // repeat backwar scanning
  122. for ( depth = 0; depth < size && ((( unsigned long )ra > KSEG0BASE) && (( unsigned long )ra < KSEG1BASE)); ++ depth )
  123. {
  124. rt_kprintf("RA[%2d] : [0x%08x]\n", depth, ra);
  125. {
  126. extern void rt_thread_exit(void);
  127. if ((uint32_t)ra == (uint32_t)(rt_thread_exit))
  128. return depth;
  129. }
  130. ra_offset = 0;
  131. stack_size = 0;
  132. for ( addr = ra; !ra_offset || !stack_size; -- addr )
  133. {
  134. switch( *addr & INST_OP_MASK)
  135. {
  136. case ADDUI_SP_INST:
  137. stack_size = abs((short)(*addr&INST_OFFSET_MASK));
  138. break;
  139. case SW_RA_INST:
  140. ra_offset = (short)(*addr&INST_OFFSET_MASK);
  141. break;
  142. case 0x3c1c0000:
  143. return depth +1;
  144. default:
  145. break;
  146. }
  147. }
  148. ra = *(unsigned long **)((unsigned long)sp + ra_offset);
  149. sp = (unsigned long*) ((unsigned long)sp+stack_size );
  150. }
  151. return depth;
  152. }
  153. #include <rtthread.h>
  154. extern long list_thread(void);
  155. void assert_hook(const char* ex, const char* func, rt_size_t line)
  156. {
  157. backtrace();
  158. list_thread();
  159. rt_kprintf("(%s) assertion failed at function:%s, line number:%d \n", ex, func, line);
  160. }
  161. int backtrace_init(void)
  162. {
  163. #ifdef RT_DEBUG
  164. rt_assert_set_hook(assert_hook);
  165. #endif
  166. return 0;
  167. }
  168. INIT_DEVICE_EXPORT(backtrace_init);