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