xref: /f-stack/freebsd/mips/mips/db_trace.c (revision 22ce4aff)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2004-2005, Juniper Networks, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  *	JNPR: db_trace.c,v 1.8 2007/08/09 11:23:32 katta
29  */
30 
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kdb.h>
37 #include <sys/proc.h>
38 #include <sys/stack.h>
39 #include <sys/sysent.h>
40 
41 #include <machine/asm.h>
42 #include <machine/db_machdep.h>
43 #include <machine/md_var.h>
44 #include <machine/mips_opcode.h>
45 #include <machine/pcb.h>
46 #include <machine/trap.h>
47 
48 #include <ddb/ddb.h>
49 #include <ddb/db_sym.h>
50 
51 extern char _locore[];
52 extern char _locoreEnd[];
53 extern char edata[];
54 
55 /*
56  * A function using a stack frame has the following instruction as the first
57  * one: [d]addiu sp,sp,-<frame_size>
58  *
59  * We make use of this to detect starting address of a function. This works
60  * better than using 'j ra' instruction to signify end of the previous
61  * function (for e.g. functions like boot() or panic() do not actually
62  * emit a 'j ra' instruction).
63  *
64  * XXX the abi does not require that the addiu instruction be the first one.
65  */
66 #define	MIPS_START_OF_FUNCTION(ins)	((((ins) & 0xffff8000) == 0x27bd8000) \
67 	|| (((ins) & 0xffff8000) == 0x67bd8000))
68 
69 /*
70  * LLD will insert invalid instruction traps between functions.
71  * Currently this is 0xefefefef but it may change in the future.
72  */
73 #define	MIPS_LLD_PADDING_BETWEEN_FUNCTIONS(ins)	((ins) == 0xefefefef)
74 
75 #if defined(__mips_n64)
76 #	define	MIPS_IS_VALID_KERNELADDR(reg)	((((reg) & 3) == 0) && \
77 					((vm_offset_t)(reg) >= MIPS_XKPHYS_START))
78 #else
79 #	define	MIPS_IS_VALID_KERNELADDR(reg)	((((reg) & 3) == 0) && \
80 					((vm_offset_t)(reg) >= MIPS_KSEG0_START))
81 #endif
82 
83 static void
stacktrace_subr(register_t pc,register_t sp,register_t ra)84 stacktrace_subr(register_t pc, register_t sp, register_t ra)
85 {
86 	InstFmt i;
87 	/*
88 	 * Arrays for a0..a3 registers and flags if content
89 	 * of these registers is valid, e.g. obtained from the stack
90 	 */
91 	int valid_args[4];
92 	register_t args[4];
93 	register_t va, subr, cause, badvaddr;
94 	unsigned instr, mask;
95 	unsigned int frames = 0;
96 	int more, stksize, j;
97 	register_t	next_ra;
98 	bool trapframe;
99 
100 /* Jump here when done with a frame, to start a new one */
101 loop:
102 
103 	/*
104 	 * Invalidate arguments values
105 	 */
106 	valid_args[0] = 0;
107 	valid_args[1] = 0;
108 	valid_args[2] = 0;
109 	valid_args[3] = 0;
110 	next_ra = 0;
111 	stksize = 0;
112 	subr = 0;
113 	trapframe = false;
114 	if (frames++ > 100) {
115 		db_printf("\nstackframe count exceeded\n");
116 		return;
117 	}
118 
119 	/* Check for bad SP: could foul up next frame. */
120 	if (!MIPS_IS_VALID_KERNELADDR(sp)) {
121 		db_printf("SP 0x%jx: not in kernel\n", (uintmax_t)sp);
122 		ra = 0;
123 		subr = 0;
124 		goto done;
125 	}
126 #define Between(x, y, z) \
127 		( ((x) <= (y)) && ((y) < (z)) )
128 #define pcBetween(a,b) \
129 		Between((uintptr_t)a, pc, (uintptr_t)b)
130 
131 	/*
132 	 * Check for current PC in  exception handler code that don't have a
133 	 * preceding "j ra" at the tail of the preceding function. Depends
134 	 * on relative ordering of functions in exception.S, swtch.S.
135 	 */
136 	if (pcBetween(MipsKernGenException, MipsUserGenException)) {
137 		subr = (uintptr_t)MipsKernGenException;
138 		trapframe = true;
139 	} else if (pcBetween(MipsUserGenException, MipsKernIntr))
140 		subr = (uintptr_t)MipsUserGenException;
141 	else if (pcBetween(MipsKernIntr, MipsUserIntr)) {
142 		subr = (uintptr_t)MipsKernIntr;
143 		trapframe = true;
144 	} else if (pcBetween(MipsUserIntr, MipsTLBInvalidException))
145 		subr = (uintptr_t)MipsUserIntr;
146 	else if (pcBetween(MipsTLBInvalidException, MipsTLBMissException)) {
147 		subr = (uintptr_t)MipsTLBInvalidException;
148 		if (pc == (uintptr_t)MipsKStackOverflow)
149 			trapframe = true;
150 	} else if (pcBetween(fork_trampoline, savectx))
151 		subr = (uintptr_t)fork_trampoline;
152 	else if (pcBetween(savectx, cpu_throw))
153 		subr = (uintptr_t)savectx;
154 	else if (pcBetween(cpu_throw, cpu_switch))
155 		subr = (uintptr_t)cpu_throw;
156 	else if (pcBetween(cpu_switch, MipsSwitchFPState))
157 		subr = (uintptr_t)cpu_switch;
158 	else if (pcBetween(_locore, _locoreEnd)) {
159 		subr = (uintptr_t)_locore;
160 		ra = 0;
161 		goto done;
162 	}
163 
164 	/* Check for bad PC. */
165 	if (!MIPS_IS_VALID_KERNELADDR(pc)) {
166 		db_printf("PC 0x%jx: not in kernel\n", (uintmax_t)pc);
167 		ra = 0;
168 		goto done;
169 	}
170 
171 	/*
172 	 * For a trapframe, skip to the output and afterwards pull the
173 	 * previous registers out of the trapframe instead of decoding
174 	 * the function prologue.
175 	 */
176 	if (trapframe)
177 		goto done;
178 
179 	/*
180 	 * Find the beginning of the current subroutine by scanning
181 	 * backwards from the current PC for the end of the previous
182 	 * subroutine.
183 	 */
184 	if (!subr) {
185 		va = pc;
186 		while (1) {
187 			instr = kdbpeek((int *)va);
188 
189 			/* LLD fills padding between functions with 0xefefefef */
190 			if (MIPS_LLD_PADDING_BETWEEN_FUNCTIONS(instr))
191 				break;
192 
193 			if (MIPS_START_OF_FUNCTION(instr))
194 				break;
195 
196  			va -= sizeof(int);
197 		}
198 
199 		/*
200 		 * Skip over nulls/trap padding which might separate
201 		 * object files or functions.
202 		 */
203 		instr = kdbpeek((int *)va);
204 		while (instr == 0 || MIPS_LLD_PADDING_BETWEEN_FUNCTIONS(instr)) {
205 			va += sizeof(int);
206 			instr = kdbpeek((int *)va);
207 		}
208 		subr = va;
209 	}
210 
211 	/* scan forwards to find stack size and any saved registers */
212 	stksize = 0;
213 	more = 3;
214 	mask = 0;
215 	for (va = subr; more; va += sizeof(int),
216 	    more = (more == 3) ? 3 : more - 1) {
217 		/* stop if hit our current position */
218 		if (va >= pc)
219 			break;
220 		instr = kdbpeek((int *)va);
221 		i.word = instr;
222 		switch (i.JType.op) {
223 		case OP_SPECIAL:
224 			switch (i.RType.func) {
225 			case OP_JR:
226 			case OP_JALR:
227 				more = 2;	/* stop after next instruction */
228 				break;
229 
230 			case OP_SYSCALL:
231 			case OP_BREAK:
232 				more = 1;	/* stop now */
233 			}
234 			break;
235 
236 		case OP_BCOND:
237 		case OP_J:
238 		case OP_JAL:
239 		case OP_BEQ:
240 		case OP_BNE:
241 		case OP_BLEZ:
242 		case OP_BGTZ:
243 			more = 2;	/* stop after next instruction */
244 			break;
245 
246 		case OP_COP0:
247 		case OP_COP1:
248 		case OP_COP2:
249 		case OP_COP3:
250 			switch (i.RType.rs) {
251 			case OP_BCx:
252 			case OP_BCy:
253 				more = 2;	/* stop after next instruction */
254 			}
255 			break;
256 
257 		case OP_SW:
258 			/* look for saved registers on the stack */
259 			if (i.IType.rs != 29)
260 				break;
261 			/*
262 			 * only restore the first one except RA for
263 			 * MipsKernGenException case
264 			 */
265 			if (mask & (1 << i.IType.rt)) {
266 				if (subr == (uintptr_t)MipsKernGenException &&
267 				    i.IType.rt == 31)
268 					next_ra = kdbpeek((int *)(sp +
269 					    (short)i.IType.imm));
270 				break;
271 			}
272 			mask |= (1 << i.IType.rt);
273 			switch (i.IType.rt) {
274 			case 4:/* a0 */
275 				args[0] = kdbpeek((int *)(sp + (short)i.IType.imm));
276 				valid_args[0] = 1;
277 				break;
278 
279 			case 5:/* a1 */
280 				args[1] = kdbpeek((int *)(sp + (short)i.IType.imm));
281 				valid_args[1] = 1;
282 				break;
283 
284 			case 6:/* a2 */
285 				args[2] = kdbpeek((int *)(sp + (short)i.IType.imm));
286 				valid_args[2] = 1;
287 				break;
288 
289 			case 7:/* a3 */
290 				args[3] = kdbpeek((int *)(sp + (short)i.IType.imm));
291 				valid_args[3] = 1;
292 				break;
293 
294 			case 31:	/* ra */
295 				ra = kdbpeek((int *)(sp + (short)i.IType.imm));
296 			}
297 			break;
298 
299 		case OP_SD:
300 			/* look for saved registers on the stack */
301 			if (i.IType.rs != 29)
302 				break;
303 			/* only restore the first one */
304 			if (mask & (1 << i.IType.rt))
305 				break;
306 			mask |= (1 << i.IType.rt);
307 			switch (i.IType.rt) {
308 			case 4:/* a0 */
309 				args[0] = kdbpeekd((int *)(sp + (short)i.IType.imm));
310 				valid_args[0] = 1;
311 				break;
312 
313 			case 5:/* a1 */
314 				args[1] = kdbpeekd((int *)(sp + (short)i.IType.imm));
315 				valid_args[1] = 1;
316 				break;
317 
318 			case 6:/* a2 */
319 				args[2] = kdbpeekd((int *)(sp + (short)i.IType.imm));
320 				valid_args[2] = 1;
321 				break;
322 
323 			case 7:/* a3 */
324 				args[3] = kdbpeekd((int *)(sp + (short)i.IType.imm));
325 				valid_args[3] = 1;
326 				break;
327 
328 			case 31:	/* ra */
329 				ra = kdbpeekd((int *)(sp + (short)i.IType.imm));
330 			}
331 			break;
332 
333 		case OP_ADDI:
334 		case OP_ADDIU:
335 		case OP_DADDI:
336 		case OP_DADDIU:
337 			/* look for stack pointer adjustment */
338 			if (i.IType.rs != 29 || i.IType.rt != 29)
339 				break;
340 			stksize = -((short)i.IType.imm);
341 		}
342 	}
343 
344 done:
345 	db_printsym(pc, DB_STGY_PROC);
346 	db_printf(" (");
347 	for (j = 0; j < 4; j ++) {
348 		if (j > 0)
349 			db_printf(",");
350 		if (valid_args[j])
351 			db_printf("%jx", (uintmax_t)(u_register_t)args[j]);
352 		else
353 			db_printf("?");
354 	}
355 
356 	db_printf(") ra %jx sp %jx sz %d\n",
357 	    (uintmax_t)(u_register_t) ra,
358 	    (uintmax_t)(u_register_t) sp,
359 	    stksize);
360 
361 	if (trapframe) {
362 #define	TF_REG(base, reg)	((base) + CALLFRAME_SIZ + ((reg) * SZREG))
363 #if defined(__mips_n64) || defined(__mips_n32)
364 		pc = kdbpeekd((int *)TF_REG(sp, PC));
365 		ra = kdbpeekd((int *)TF_REG(sp, RA));
366 		sp = kdbpeekd((int *)TF_REG(sp, SP));
367 		cause = kdbpeekd((int *)TF_REG(sp, CAUSE));
368 		badvaddr = kdbpeekd((int *)TF_REG(sp, BADVADDR));
369 #else
370 		pc = kdbpeek((int *)TF_REG(sp, PC));
371 		ra = kdbpeek((int *)TF_REG(sp, RA));
372 		sp = kdbpeek((int *)TF_REG(sp, SP));
373 		cause = kdbpeek((int *)TF_REG(sp, CAUSE));
374 		badvaddr = kdbpeek((int *)TF_REG(sp, BADVADDR));
375 #endif
376 #undef TF_REG
377 		db_printf("--- exception, cause %jx badvaddr %jx ---\n",
378 		    (uintmax_t)cause, (uintmax_t)badvaddr);
379 		goto loop;
380 	} else if (ra) {
381 		/*
382 		 * We subtract two instructions from ra to convert it
383 		 * from a return address to a calling address,
384 		 * accounting for the delay slot.
385 		 */
386 		register_t next_pc = ra - 2 * sizeof(int);
387 		if (pc == next_pc && stksize == 0)
388 			db_printf("stacktrace: loop!\n");
389 		else {
390 			pc = next_pc;
391 			sp += stksize;
392 			ra = next_ra;
393 			goto loop;
394 		}
395 	}
396 }
397 
398 int
db_md_set_watchpoint(db_expr_t addr,db_expr_t size)399 db_md_set_watchpoint(db_expr_t addr, db_expr_t size)
400 {
401 
402 	return(0);
403 }
404 
405 int
db_md_clr_watchpoint(db_expr_t addr,db_expr_t size)406 db_md_clr_watchpoint(db_expr_t addr, db_expr_t size)
407 {
408 
409 	return(0);
410 }
411 
412 void
db_md_list_watchpoints()413 db_md_list_watchpoints()
414 {
415 }
416 
417 void
db_trace_self(void)418 db_trace_self(void)
419 {
420 	register_t pc, ra, sp;
421 
422 	sp = (register_t)(intptr_t)__builtin_frame_address(0);
423 	ra = (register_t)(intptr_t)__builtin_return_address(0);
424 
425 	__asm __volatile(
426 		"jal 99f\n"
427 		"nop\n"
428 		"99:\n"
429 		 "move %0, $31\n" /* get ra */
430 		 "move $31, %1\n" /* restore ra */
431 		 : "=r" (pc)
432 		 : "r" (ra));
433 	stacktrace_subr(pc, sp, ra);
434 	return;
435 }
436 
437 int
db_trace_thread(struct thread * thr,int count)438 db_trace_thread(struct thread *thr, int count)
439 {
440 	register_t pc, ra, sp;
441 	struct pcb *ctx;
442 
443 	ctx = kdb_thr_ctx(thr);
444 	sp = (register_t)ctx->pcb_context[PCB_REG_SP];
445 	pc = (register_t)ctx->pcb_context[PCB_REG_PC];
446 	ra = (register_t)ctx->pcb_context[PCB_REG_RA];
447 	stacktrace_subr(pc, sp, ra);
448 
449 	return (0);
450 }
451 
452 void
db_show_mdpcpu(struct pcpu * pc)453 db_show_mdpcpu(struct pcpu *pc)
454 {
455 
456 	db_printf("ipis         = 0x%x\n", pc->pc_pending_ipis);
457 	db_printf("next ASID    = %d\n", pc->pc_next_asid);
458 	db_printf("GENID        = %d\n", pc->pc_asid_generation);
459 	return;
460 }
461