xref: /nrf52832-nimble/rt-thread/libcpu/mips/x1000/mips_backtrace.c (revision 104654410c56c573564690304ae786df310c91fc)
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 
backtrace_ctx(mips_reg_ctx * ctx)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 
backtrace(void)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);
assert_hook(const char * ex,const char * func,rt_size_t line)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 
backtrace_init(void)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