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 25 #include <rtthread.h> 26 #include <stdlib.h> 27 #include <stdio.h> 28 #include <stdint.h> 29 30 #include "mips.h" 31 32 /********************************************************************************************************* 33 ָ��� 34 *********************************************************************************************************/ 35 #define ADDUI_SP_INST 0x27bd0000 36 #define SW_RA_INST 0xafbf0000 37 #define JR_RA_INST 0x03e00008 38 39 #define INST_OP_MASK 0xffff0000 40 #define INST_OFFSET_MASK 0x0000ffff 41 42 #define abs(s) ((s) < 0 ? -(s):(s)) 43 44 int backtrace_ctx(mips_reg_ctx *ctx) 45 { 46 unsigned long *addr; 47 unsigned long *pc, *ra, *sp; 48 size_t ra_offset; 49 size_t stack_size; 50 int depth; 51 int size = 8; 52 53 pc = (unsigned long *)(unsigned long)ctx->CP0EPC; 54 ra = (unsigned long *)(unsigned long)ctx->regs[REG_RA]; 55 sp = (unsigned long *)(unsigned long)ctx->regs[REG_SP]; 56 57 rt_kprintf("[0x%08x]\n", pc); 58 59 if (size == 1) return 1; 60 61 ra_offset = stack_size = 0; 62 63 for (addr = ra; !ra_offset || !stack_size; --addr) 64 { 65 switch (*addr & INST_OP_MASK) { 66 case ADDUI_SP_INST: 67 stack_size = abs((short)(*addr&INST_OFFSET_MASK)); 68 break; 69 70 case SW_RA_INST: 71 ra_offset = (short)(*addr&INST_OFFSET_MASK); 72 break; 73 74 case 0x3c1c0000: 75 goto out_of_loop; 76 77 default: 78 break; 79 } 80 } 81 82 out_of_loop: 83 if (ra_offset) ra = *(unsigned long **)((unsigned long)sp + ra_offset); 84 if (stack_size) sp = (unsigned long *)((unsigned long)sp + stack_size); 85 86 // repeat backwar scanning 87 for (depth = 1; depth < size && ra && ra != (unsigned long *)0xffffffff; ++depth) 88 { 89 rt_kprintf("RA[%2d] : [0x%08x]\n", depth ,ra); 90 91 ra_offset = 0; 92 stack_size = 0; 93 94 for ( addr = ra; !ra_offset || !stack_size; -- addr ) 95 { 96 switch( *addr & INST_OP_MASK) 97 { 98 case ADDUI_SP_INST: 99 stack_size = abs((short)(*addr&INST_OFFSET_MASK)); 100 break; 101 102 case SW_RA_INST: 103 ra_offset = abs((short)(*addr&INST_OFFSET_MASK)); 104 break; 105 106 case 0x3c1c0000: 107 return depth +1; 108 109 default: 110 break; 111 } 112 } 113 114 ra = *(unsigned long **)((unsigned long)sp + ra_offset); 115 sp = (unsigned long *)((unsigned long)sp + stack_size); 116 } 117 118 return depth; 119 } 120 121 int backtrace(void) 122 { 123 unsigned long *addr; 124 unsigned long *ra; 125 unsigned long *sp; 126 int size = 8, depth; 127 128 size_t ra_offset; 129 size_t stack_size; 130 131 // get current $a and $sp 132 __asm__ __volatile__ ( 133 " move %0, $ra\n" 134 " move %1, $sp\n" 135 : "=r"(ra), "=r"(sp) 136 ); 137 138 // scanning to find the size of hte current stack frame 139 stack_size = 0; 140 141 for ( addr = (unsigned long *)backtrace; !stack_size; ++addr) 142 { 143 if ((*addr & INST_OP_MASK ) == ADDUI_SP_INST ) 144 stack_size = abs((short)(*addr&INST_OFFSET_MASK)); 145 else if ( *addr == JR_RA_INST ) 146 break; 147 } 148 149 sp = (unsigned long *) (( unsigned long )sp + stack_size); 150 151 // repeat backwar scanning 152 for ( depth = 0; depth < size && ((( unsigned long )ra > KSEG0BASE) && (( unsigned long )ra < KSEG1BASE)); ++ depth ) 153 { 154 rt_kprintf("RA[%2d] : [0x%08x]\n", depth, ra); 155 { 156 extern void rt_thread_exit(void); 157 if ((uint32_t)ra == (uint32_t)(rt_thread_exit)) 158 return depth; 159 } 160 161 ra_offset = 0; 162 stack_size = 0; 163 164 for ( addr = ra; !ra_offset || !stack_size; -- addr ) 165 { 166 switch( *addr & INST_OP_MASK) 167 { 168 case ADDUI_SP_INST: 169 stack_size = abs((short)(*addr&INST_OFFSET_MASK)); 170 break; 171 172 case SW_RA_INST: 173 ra_offset = (short)(*addr&INST_OFFSET_MASK); 174 break; 175 176 case 0x3c1c0000: 177 return depth +1; 178 179 default: 180 break; 181 } 182 } 183 184 ra = *(unsigned long **)((unsigned long)sp + ra_offset); 185 sp = (unsigned long*) ((unsigned long)sp+stack_size ); 186 } 187 188 return depth; 189 } 190 191 #include <rtthread.h> 192 extern long list_thread(void); 193 void assert_hook(const char* ex, const char* func, rt_size_t line) 194 { 195 backtrace(); 196 197 list_thread(); 198 rt_kprintf("(%s) assertion failed at function:%s, line number:%d \n", ex, func, line); 199 } 200 201 int backtrace_init(void) 202 { 203 #ifdef RT_DEBUG 204 rt_assert_set_hook(assert_hook); 205 #endif 206 return 0; 207 } 208 INIT_DEVICE_EXPORT(backtrace_init); 209