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