db_trace.c revision 208392
1178172Simp/*-
2178172Simp * Copyright (c) 2004-2005, Juniper Networks, Inc.
3178172Simp * All rights reserved.
4178172Simp *
5178172Simp *	JNPR: db_trace.c,v 1.8 2007/08/09 11:23:32 katta
6178172Simp */
7178172Simp
8178172Simp#include <sys/cdefs.h>
9178172Simp__FBSDID("$FreeBSD: head/sys/mips/mips/db_trace.c 208392 2010-05-21 17:17:56Z jhb $");
10178172Simp
11178172Simp#include <sys/param.h>
12178172Simp#include <sys/systm.h>
13178172Simp#include <sys/kdb.h>
14178172Simp#include <sys/proc.h>
15178172Simp#include <sys/stack.h>
16178172Simp#include <sys/sysent.h>
17178172Simp
18178172Simp#include <machine/db_machdep.h>
19178172Simp#include <machine/md_var.h>
20202046Simp#include <machine/mips_opcode.h>
21178172Simp#include <machine/pcb.h>
22202046Simp#include <machine/trap.h>
23178172Simp
24178172Simp#include <ddb/ddb.h>
25202046Simp#include <ddb/db_sym.h>
26178172Simp
27202046Simpextern char _locore[];
28202046Simpextern char _locoreEnd[];
29202046Simpextern char edata[];
30202046Simp
31202046Simp/*
32202046Simp * A function using a stack frame has the following instruction as the first
33202046Simp * one: addiu sp,sp,-<frame_size>
34202046Simp *
35202046Simp * We make use of this to detect starting address of a function. This works
36202046Simp * better than using 'j ra' instruction to signify end of the previous
37202046Simp * function (for e.g. functions like boot() or panic() do not actually
38202046Simp * emit a 'j ra' instruction).
39202046Simp *
40202046Simp * XXX the abi does not require that the addiu instruction be the first one.
41202046Simp */
42202046Simp#define	MIPS_START_OF_FUNCTION(ins)	(((ins) & 0xffff8000) == 0x27bd8000)
43202046Simp
44202046Simp/*
45202046Simp * MIPS ABI 3.0 requires that all functions return using the 'j ra' instruction
46202046Simp *
47202046Simp * XXX gcc doesn't do this for functions with __noreturn__ attribute.
48202046Simp */
49202046Simp#define	MIPS_END_OF_FUNCTION(ins)	((ins) == 0x03e00008)
50202046Simp
51202046Simp/*
52202046Simp * kdbpeekD(addr) - skip one word starting at 'addr', then read the second word
53202046Simp */
54202046Simp#define	kdbpeekD(addr)	kdbpeek(((int *)(addr)) + 1)
55202046Simp
56202046Simp/*
57202046Simp * Functions ``special'' enough to print by name
58202046Simp */
59202046Simp#ifdef __STDC__
60202046Simp#define	Name(_fn)  { (void*)_fn, # _fn }
61202046Simp#else
62202046Simp#define	Name(_fn) { _fn, "_fn"}
63202046Simp#endif
64202046Simpstatic struct {
65202046Simp	void *addr;
66202046Simp	char *name;
67202046Simp}      names[] = {
68202046Simp
69202046Simp	Name(trap),
70202046Simp	Name(MipsKernGenException),
71202046Simp	Name(MipsUserGenException),
72202046Simp	Name(MipsKernIntr),
73202046Simp	Name(MipsUserIntr),
74202046Simp	Name(cpu_switch),
75202046Simp	{
76202046Simp		0, 0
77202046Simp	}
78202046Simp};
79202046Simp
80202046Simp/*
81202046Simp * Map a function address to a string name, if known; or a hex string.
82202046Simp */
83202046Simpstatic char *
84202046Simpfn_name(uintptr_t addr)
85202046Simp{
86202046Simp	static char buf[17];
87202046Simp	int i = 0;
88202046Simp
89202046Simp	db_expr_t diff;
90202046Simp	c_db_sym_t sym;
91202046Simp	char *symname;
92202046Simp
93202046Simp	diff = 0;
94202046Simp	symname = NULL;
95202046Simp	sym = db_search_symbol((db_addr_t)addr, DB_STGY_ANY, &diff);
96202046Simp	db_symbol_values(sym, (const char **)&symname, (db_expr_t *)0);
97202046Simp	if (symname && diff == 0)
98202046Simp		return (symname);
99202046Simp
100202046Simp	for (i = 0; names[i].name; i++)
101202046Simp		if (names[i].addr == (void *)addr)
102202046Simp			return (names[i].name);
103202046Simp	sprintf(buf, "%jx", (uintmax_t)addr);
104202046Simp	return (buf);
105202046Simp}
106202046Simp
107202046Simpvoid
108202046Simpstacktrace_subr(register_t pc, register_t sp, register_t ra,
109202046Simp	int (*printfn) (const char *,...))
110202046Simp{
111202046Simp	InstFmt i;
112202046Simp	/*
113202046Simp	 * Arrays for a0..a3 registers and flags if content
114202046Simp	 * of these registers is valid, e.g. obtained from the stack
115202046Simp	 */
116202046Simp	int valid_args[4];
117202046Simp	uintptr_t args[4];
118202046Simp	uintptr_t va, subr;
119202046Simp	unsigned instr, mask;
120202046Simp	unsigned int frames = 0;
121202046Simp	int more, stksize, j;
122202046Simp
123202046Simp/* Jump here when done with a frame, to start a new one */
124202046Simploop:
125202046Simp
126202046Simp	/*
127202046Simp	 * Invalidate arguments values
128202046Simp	 */
129202046Simp	valid_args[0] = 0;
130202046Simp	valid_args[1] = 0;
131202046Simp	valid_args[2] = 0;
132202046Simp	valid_args[3] = 0;
133202046Simp/* Jump here after a nonstandard (interrupt handler) frame */
134202046Simp	stksize = 0;
135202046Simp	subr = 0;
136202046Simp	if (frames++ > 100) {
137202046Simp		(*printfn) ("\nstackframe count exceeded\n");
138202046Simp		/* return breaks stackframe-size heuristics with gcc -O2 */
139202046Simp		goto finish;	/* XXX */
140202046Simp	}
141202046Simp	/* check for bad SP: could foul up next frame */
142202046Simp	/*XXX MIPS64 bad: this hard-coded SP is lame */
143202046Simp	if (sp & 3 || sp < 0x80000000) {
144202046Simp		(*printfn) ("SP 0x%x: not in kernel\n", sp);
145202046Simp		ra = 0;
146202046Simp		subr = 0;
147202046Simp		goto done;
148202046Simp	}
149202046Simp#define Between(x, y, z) \
150202046Simp		( ((x) <= (y)) && ((y) < (z)) )
151202046Simp#define pcBetween(a,b) \
152202046Simp		Between((uintptr_t)a, pc, (uintptr_t)b)
153202046Simp
154202046Simp	/*
155202046Simp	 * Check for current PC in  exception handler code that don't have a
156202046Simp	 * preceding "j ra" at the tail of the preceding function. Depends
157202046Simp	 * on relative ordering of functions in exception.S, swtch.S.
158202046Simp	 */
159202046Simp	if (pcBetween(MipsKernGenException, MipsUserGenException))
160202046Simp		subr = (uintptr_t)MipsKernGenException;
161202046Simp	else if (pcBetween(MipsUserGenException, MipsKernIntr))
162202046Simp		subr = (uintptr_t)MipsUserGenException;
163202046Simp	else if (pcBetween(MipsKernIntr, MipsUserIntr))
164202046Simp		subr = (uintptr_t)MipsKernIntr;
165205360Sneel	else if (pcBetween(MipsUserIntr, MipsTLBInvalidException))
166202046Simp		subr = (uintptr_t)MipsUserIntr;
167205360Sneel	else if (pcBetween(MipsTLBInvalidException, MipsTLBMissException))
168205360Sneel		subr = (uintptr_t)MipsTLBInvalidException;
169204997Sneel	else if (pcBetween(fork_trampoline, savectx))
170204997Sneel		subr = (uintptr_t)fork_trampoline;
171204997Sneel	else if (pcBetween(savectx, mips_cpu_throw))
172204997Sneel		subr = (uintptr_t)savectx;
173204997Sneel	else if (pcBetween(mips_cpu_throw, cpu_switch))
174204997Sneel		subr = (uintptr_t)cpu_throw;
175202046Simp	else if (pcBetween(cpu_switch, MipsSwitchFPState))
176202046Simp		subr = (uintptr_t)cpu_switch;
177202046Simp	else if (pcBetween(_locore, _locoreEnd)) {
178202046Simp		subr = (uintptr_t)_locore;
179202046Simp		ra = 0;
180202046Simp		goto done;
181202046Simp	}
182202046Simp	/* check for bad PC */
183202046Simp	/*XXX MIPS64 bad: These hard coded constants are lame */
184207645Sneel	if (pc & 3 || pc < (uintptr_t)0x80000000) {
185202046Simp		(*printfn) ("PC 0x%x: not in kernel\n", pc);
186202046Simp		ra = 0;
187202046Simp		goto done;
188202046Simp	}
189202046Simp	/*
190202046Simp	 * Find the beginning of the current subroutine by scanning
191202046Simp	 * backwards from the current PC for the end of the previous
192202046Simp	 * subroutine.
193202046Simp	 */
194202046Simp	if (!subr) {
195202046Simp		va = pc - sizeof(int);
196202046Simp		while (1) {
197202046Simp			instr = kdbpeek((int *)va);
198202046Simp
199202046Simp			if (MIPS_START_OF_FUNCTION(instr))
200202046Simp				break;
201202046Simp
202202046Simp			if (MIPS_END_OF_FUNCTION(instr)) {
203202046Simp				/* skip over branch-delay slot instruction */
204202046Simp				va += 2 * sizeof(int);
205202046Simp				break;
206202046Simp			}
207202046Simp
208202046Simp 			va -= sizeof(int);
209202046Simp		}
210202046Simp
211202046Simp		/* skip over nulls which might separate .o files */
212202046Simp		while ((instr = kdbpeek((int *)va)) == 0)
213202046Simp			va += sizeof(int);
214202046Simp		subr = va;
215202046Simp	}
216202046Simp	/* scan forwards to find stack size and any saved registers */
217202046Simp	stksize = 0;
218202046Simp	more = 3;
219202046Simp	mask = 0;
220202046Simp	for (va = subr; more; va += sizeof(int),
221202046Simp	    more = (more == 3) ? 3 : more - 1) {
222202046Simp		/* stop if hit our current position */
223202046Simp		if (va >= pc)
224202046Simp			break;
225202046Simp		instr = kdbpeek((int *)va);
226202046Simp		i.word = instr;
227202046Simp		switch (i.JType.op) {
228202046Simp		case OP_SPECIAL:
229202046Simp			switch (i.RType.func) {
230202046Simp			case OP_JR:
231202046Simp			case OP_JALR:
232202046Simp				more = 2;	/* stop after next instruction */
233202046Simp				break;
234202046Simp
235202046Simp			case OP_SYSCALL:
236202046Simp			case OP_BREAK:
237202046Simp				more = 1;	/* stop now */
238202046Simp			};
239202046Simp			break;
240202046Simp
241202046Simp		case OP_BCOND:
242202046Simp		case OP_J:
243202046Simp		case OP_JAL:
244202046Simp		case OP_BEQ:
245202046Simp		case OP_BNE:
246202046Simp		case OP_BLEZ:
247202046Simp		case OP_BGTZ:
248202046Simp			more = 2;	/* stop after next instruction */
249202046Simp			break;
250202046Simp
251202046Simp		case OP_COP0:
252202046Simp		case OP_COP1:
253202046Simp		case OP_COP2:
254202046Simp		case OP_COP3:
255202046Simp			switch (i.RType.rs) {
256202046Simp			case OP_BCx:
257202046Simp			case OP_BCy:
258202046Simp				more = 2;	/* stop after next instruction */
259202046Simp			};
260202046Simp			break;
261202046Simp
262202046Simp		case OP_SW:
263202046Simp			/* look for saved registers on the stack */
264202046Simp			if (i.IType.rs != 29)
265202046Simp				break;
266202046Simp			/* only restore the first one */
267202046Simp			if (mask & (1 << i.IType.rt))
268202046Simp				break;
269202046Simp			mask |= (1 << i.IType.rt);
270202046Simp			switch (i.IType.rt) {
271202046Simp			case 4:/* a0 */
272202046Simp				args[0] = kdbpeek((int *)(sp + (short)i.IType.imm));
273202046Simp				valid_args[0] = 1;
274202046Simp				break;
275202046Simp
276202046Simp			case 5:/* a1 */
277202046Simp				args[1] = kdbpeek((int *)(sp + (short)i.IType.imm));
278202046Simp				valid_args[1] = 1;
279202046Simp				break;
280202046Simp
281202046Simp			case 6:/* a2 */
282202046Simp				args[2] = kdbpeek((int *)(sp + (short)i.IType.imm));
283202046Simp				valid_args[2] = 1;
284202046Simp				break;
285202046Simp
286202046Simp			case 7:/* a3 */
287202046Simp				args[3] = kdbpeek((int *)(sp + (short)i.IType.imm));
288202046Simp				valid_args[3] = 1;
289202046Simp				break;
290202046Simp
291202046Simp			case 31:	/* ra */
292202046Simp				ra = kdbpeek((int *)(sp + (short)i.IType.imm));
293202046Simp			}
294202046Simp			break;
295202046Simp
296202046Simp		case OP_SD:
297202046Simp			/* look for saved registers on the stack */
298202046Simp			if (i.IType.rs != 29)
299202046Simp				break;
300202046Simp			/* only restore the first one */
301202046Simp			if (mask & (1 << i.IType.rt))
302202046Simp				break;
303202046Simp			mask |= (1 << i.IType.rt);
304202046Simp			switch (i.IType.rt) {
305202046Simp			case 4:/* a0 */
306202046Simp				args[0] = kdbpeekD((int *)(sp + (short)i.IType.imm));
307202046Simp				valid_args[0] = 1;
308202046Simp				break;
309202046Simp
310202046Simp			case 5:/* a1 */
311202046Simp				args[1] = kdbpeekD((int *)(sp + (short)i.IType.imm));
312202046Simp				valid_args[1] = 1;
313202046Simp				break;
314202046Simp
315202046Simp			case 6:/* a2 */
316202046Simp				args[2] = kdbpeekD((int *)(sp + (short)i.IType.imm));
317202046Simp				valid_args[2] = 1;
318202046Simp				break;
319202046Simp
320202046Simp			case 7:/* a3 */
321202046Simp				args[3] = kdbpeekD((int *)(sp + (short)i.IType.imm));
322202046Simp				valid_args[3] = 1;
323202046Simp				break;
324202046Simp
325202046Simp			case 31:	/* ra */
326202046Simp				ra = kdbpeekD((int *)(sp + (short)i.IType.imm));
327202046Simp			}
328202046Simp			break;
329202046Simp
330202046Simp		case OP_ADDI:
331202046Simp		case OP_ADDIU:
332202046Simp			/* look for stack pointer adjustment */
333202046Simp			if (i.IType.rs != 29 || i.IType.rt != 29)
334202046Simp				break;
335202046Simp			stksize = -((short)i.IType.imm);
336202046Simp		}
337202046Simp	}
338202046Simp
339202046Simpdone:
340202046Simp	(*printfn) ("%s+%x (", fn_name(subr), pc - subr);
341202046Simp	for (j = 0; j < 4; j ++) {
342202046Simp		if (j > 0)
343202046Simp			(*printfn)(",");
344202046Simp		if (valid_args[j])
345202046Simp			(*printfn)("%x", args[j]);
346202046Simp		else
347202046Simp			(*printfn)("?");
348202046Simp	}
349202046Simp
350202998Sneel	(*printfn) (") ra %x sp %x sz %d\n", ra, sp, stksize);
351202046Simp
352202046Simp	if (ra) {
353202046Simp		if (pc == ra && stksize == 0)
354202046Simp			(*printfn) ("stacktrace: loop!\n");
355202046Simp		else {
356202046Simp			pc = ra;
357202046Simp			sp += stksize;
358202046Simp			ra = 0;
359202046Simp			goto loop;
360202046Simp		}
361202046Simp	} else {
362202046Simpfinish:
363202046Simp		if (curproc)
364202046Simp			(*printfn) ("pid %d\n", curproc->p_pid);
365202046Simp		else
366202046Simp			(*printfn) ("curproc NULL\n");
367202046Simp	}
368202046Simp}
369202046Simp
370202046Simp
371178172Simpint
372178172Simpdb_md_set_watchpoint(db_expr_t addr, db_expr_t size)
373178172Simp{
374178172Simp
375178172Simp	return(0);
376178172Simp}
377178172Simp
378178172Simp
379178172Simpint
380178172Simpdb_md_clr_watchpoint( db_expr_t addr, db_expr_t size)
381178172Simp{
382178172Simp
383178172Simp	return(0);
384178172Simp}
385178172Simp
386178172Simp
387178172Simpvoid
388178172Simpdb_md_list_watchpoints()
389178172Simp{
390178172Simp}
391178172Simp
392178172Simpvoid
393178172Simpdb_trace_self(void)
394178172Simp{
395178172Simp	db_trace_thread (curthread, -1);
396178172Simp	return;
397178172Simp}
398178172Simp
399178172Simpint
400178172Simpdb_trace_thread(struct thread *thr, int count)
401178172Simp{
402202046Simp	register_t pc, ra, sp;
403178172Simp	struct pcb *ctx;
404178172Simp
405202046Simp	if (thr == curthread) {
406202046Simp		sp = (register_t)__builtin_frame_address(0);
407202046Simp		ra = (register_t)__builtin_return_address(0);
408202046Simp
409202046Simp        	__asm __volatile(
410202046Simp			"jal 99f\n"
411202046Simp			"nop\n"
412202046Simp			"99:\n"
413202046Simp                         "move %0, $31\n" /* get ra */
414202046Simp                         "move $31, %1\n" /* restore ra */
415202046Simp                         : "=r" (pc)
416202046Simp			 : "r" (ra));
417202046Simp
418204997Sneel	} else {
419204997Sneel		ctx = kdb_thr_ctx(thr);
420202046Simp		sp = (register_t)ctx->pcb_context[PREG_SP];
421202046Simp		pc = (register_t)ctx->pcb_context[PREG_PC];
422202046Simp		ra = (register_t)ctx->pcb_context[PREG_RA];
423202046Simp	}
424202046Simp
425202046Simp	stacktrace_subr(pc, sp, ra,
426202046Simp	    (int (*) (const char *, ...))db_printf);
427202046Simp
428202046Simp	return (0);
429178172Simp}
430178172Simp
431178172Simpvoid
432178172Simpdb_show_mdpcpu(struct pcpu *pc)
433178172Simp{
434178172Simp
435208392Sjhb	db_printf("ipis         = 0x%x\n", pc->pc_pending_ipis);
436178172Simp	db_printf("next ASID    = %d\n", pc->pc_next_asid);
437208392Sjhb	db_printf("GENID        = %d\n", pc->pc_asid_generation);
438178172Simp	return;
439178172Simp}
440