199730Sbenno/*	$FreeBSD$ */
299730Sbenno/*	$NetBSD: db_trace.c,v 1.20 2002/05/13 20:30:09 matt Exp $	*/
399730Sbenno/*	$OpenBSD: db_trace.c,v 1.3 1997/03/21 02:10:48 niklas Exp $	*/
499730Sbenno
5139825Simp/*-
699730Sbenno * Mach Operating System
799730Sbenno * Copyright (c) 1992 Carnegie Mellon University
899730Sbenno * All Rights Reserved.
9132070Sgrehan *
1099730Sbenno * Permission to use, copy, modify and distribute this software and its
1199730Sbenno * documentation is hereby granted, provided that both the copyright
1299730Sbenno * notice and this permission notice appear in all copies of the
1399730Sbenno * software, derivative works or modified versions, and any portions
1499730Sbenno * thereof, and that both notices appear in supporting documentation.
15132070Sgrehan *
1699730Sbenno * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
1799730Sbenno * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
1899730Sbenno * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
19132070Sgrehan *
2099730Sbenno * Carnegie Mellon requests users of this software to return to
21132070Sgrehan *
2299730Sbenno *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
2399730Sbenno *  School of Computer Science
2499730Sbenno *  Carnegie Mellon University
2599730Sbenno *  Pittsburgh PA 15213-3890
26132070Sgrehan *
27132070Sgrehan * any improvements or extensions that they make and grant Carnegie Mellon
2899730Sbenno * the rights to redistribute these changes.
2999730Sbenno */
3099730Sbenno
3199730Sbenno#include <sys/param.h>
32104435Sgrehan#include <sys/systm.h>
33132070Sgrehan#include <sys/kdb.h>
3499730Sbenno#include <sys/proc.h>
35148666Sjeff#include <sys/stack.h>
3699730Sbenno
3799730Sbenno#include <vm/vm.h>
3899730Sbenno#include <vm/pmap.h>
3999730Sbenno#include <vm/vm_extern.h>
4099730Sbenno
4199730Sbenno#include <machine/db_machdep.h>
42138129Sdas#include <machine/pcb.h>
4399730Sbenno#include <machine/spr.h>
44174195Srwatson#include <machine/stack.h>
4599730Sbenno#include <machine/trap.h>
4699730Sbenno
4799730Sbenno#include <ddb/ddb.h>
4899730Sbenno#include <ddb/db_access.h>
4999730Sbenno#include <ddb/db_sym.h>
5099730Sbenno#include <ddb/db_variables.h>
5199730Sbenno
52132070Sgrehanstatic db_varfcn_t db_frame;
53132070Sgrehan
54132070Sgrehan#define DB_OFFSET(x)	(db_expr_t *)offsetof(struct trapframe, x)
55132070Sgrehan
56209975Snwhitehorn#ifdef __powerpc64__
57209975Snwhitehorn#define	CALLOFFSET	8	/* Include TOC reload slot */
58209975Snwhitehorn#else
59209975Snwhitehorn#define	CALLOFFSET	4
60209975Snwhitehorn#endif
61209975Snwhitehorn
6299730Sbennostruct db_variable db_regs[] = {
63132070Sgrehan	{ "r0",	 DB_OFFSET(fixreg[0]),	db_frame },
64132070Sgrehan	{ "r1",	 DB_OFFSET(fixreg[1]),	db_frame },
65132070Sgrehan	{ "r2",	 DB_OFFSET(fixreg[2]),	db_frame },
66132070Sgrehan	{ "r3",	 DB_OFFSET(fixreg[3]),	db_frame },
67132070Sgrehan	{ "r4",	 DB_OFFSET(fixreg[4]),	db_frame },
68132070Sgrehan	{ "r5",	 DB_OFFSET(fixreg[5]),	db_frame },
69132070Sgrehan	{ "r6",	 DB_OFFSET(fixreg[6]),	db_frame },
70132070Sgrehan	{ "r7",	 DB_OFFSET(fixreg[7]),	db_frame },
71132070Sgrehan	{ "r8",	 DB_OFFSET(fixreg[8]),	db_frame },
72132070Sgrehan	{ "r9",	 DB_OFFSET(fixreg[9]),	db_frame },
73132070Sgrehan	{ "r10", DB_OFFSET(fixreg[10]),	db_frame },
74132070Sgrehan	{ "r11", DB_OFFSET(fixreg[11]),	db_frame },
75132070Sgrehan	{ "r12", DB_OFFSET(fixreg[12]),	db_frame },
76132070Sgrehan	{ "r13", DB_OFFSET(fixreg[13]),	db_frame },
77132070Sgrehan	{ "r14", DB_OFFSET(fixreg[14]),	db_frame },
78132070Sgrehan	{ "r15", DB_OFFSET(fixreg[15]),	db_frame },
79132070Sgrehan	{ "r16", DB_OFFSET(fixreg[16]),	db_frame },
80132070Sgrehan	{ "r17", DB_OFFSET(fixreg[17]),	db_frame },
81132070Sgrehan	{ "r18", DB_OFFSET(fixreg[18]),	db_frame },
82132070Sgrehan	{ "r19", DB_OFFSET(fixreg[19]),	db_frame },
83132070Sgrehan	{ "r20", DB_OFFSET(fixreg[20]),	db_frame },
84132070Sgrehan	{ "r21", DB_OFFSET(fixreg[21]),	db_frame },
85132070Sgrehan	{ "r22", DB_OFFSET(fixreg[22]),	db_frame },
86132070Sgrehan	{ "r23", DB_OFFSET(fixreg[23]),	db_frame },
87132070Sgrehan	{ "r24", DB_OFFSET(fixreg[24]),	db_frame },
88132070Sgrehan	{ "r25", DB_OFFSET(fixreg[25]),	db_frame },
89132070Sgrehan	{ "r26", DB_OFFSET(fixreg[26]),	db_frame },
90132070Sgrehan	{ "r27", DB_OFFSET(fixreg[27]),	db_frame },
91132070Sgrehan	{ "r28", DB_OFFSET(fixreg[28]),	db_frame },
92132070Sgrehan	{ "r29", DB_OFFSET(fixreg[29]),	db_frame },
93132070Sgrehan	{ "r30", DB_OFFSET(fixreg[30]),	db_frame },
94132070Sgrehan	{ "r31", DB_OFFSET(fixreg[31]),	db_frame },
95132070Sgrehan	{ "srr0", DB_OFFSET(srr0),	db_frame },
96132070Sgrehan	{ "srr1", DB_OFFSET(srr1),	db_frame },
97132070Sgrehan	{ "lr",	 DB_OFFSET(lr),		db_frame },
98132070Sgrehan	{ "ctr", DB_OFFSET(ctr),	db_frame },
99132070Sgrehan	{ "cr",	 DB_OFFSET(cr),		db_frame },
100132070Sgrehan	{ "xer", DB_OFFSET(xer),	db_frame },
101176742Sraj#ifdef AIM
102176742Sraj	{ "dar", DB_OFFSET(cpu.aim.dar),	db_frame },
103176742Sraj	{ "dsisr", DB_OFFSET(cpu.aim.dsisr),	db_frame },
104176742Sraj#endif
105236141Sraj#if defined(BOOKE)
106176742Sraj	{ "dear", DB_OFFSET(cpu.booke.dear),	db_frame },
107176742Sraj	{ "esr", DB_OFFSET(cpu.booke.esr),	db_frame },
108176742Sraj#endif
10999730Sbenno};
11099730Sbennostruct db_variable *db_eregs = db_regs + sizeof (db_regs)/sizeof (db_regs[0]);
11199730Sbenno
11299730Sbenno/*
113132070Sgrehan * register variable handling
114132070Sgrehan */
115132070Sgrehanstatic int
116132070Sgrehandb_frame(struct db_variable *vp, db_expr_t *valuep, int op)
117132070Sgrehan{
118209975Snwhitehorn	register_t *reg;
119132070Sgrehan
120132070Sgrehan	if (kdb_frame == NULL)
121132070Sgrehan		return (0);
122209975Snwhitehorn        reg = (register_t*)((uintptr_t)kdb_frame + (uintptr_t)vp->valuep);
123132070Sgrehan        if (op == DB_VAR_GET)
124132070Sgrehan                *valuep = *reg;
125132070Sgrehan        else
126132070Sgrehan                *reg = *valuep;
127132070Sgrehan        return (1);
128132070Sgrehan}
129132070Sgrehan
130132070Sgrehan
131132070Sgrehan/*
13299730Sbenno *	Frame tracing.
13399730Sbenno */
134132070Sgrehanstatic int
135132070Sgrehandb_backtrace(struct thread *td, db_addr_t fp, int count)
13699730Sbenno{
137132070Sgrehan	db_addr_t stackframe, lr, *args;
13899730Sbenno	db_expr_t diff;
139104435Sgrehan	c_db_sym_t sym;
140104435Sgrehan	const char *symname;
14199730Sbenno	boolean_t kernel_only = TRUE;
14299730Sbenno	boolean_t full = FALSE;
14399730Sbenno
144132070Sgrehan#if 0
14599730Sbenno	{
14699730Sbenno		register char *cp = modif;
14799730Sbenno		register char c;
14899730Sbenno
14999730Sbenno		while ((c = *cp++) != 0) {
15099730Sbenno			if (c == 't')
15199730Sbenno				trace_thread = TRUE;
15299730Sbenno			if (c == 'u')
15399730Sbenno				kernel_only = FALSE;
15499730Sbenno			if (c == 'f')
15599730Sbenno				full = TRUE;
15699730Sbenno		}
15799730Sbenno	}
158132070Sgrehan#endif
15999730Sbenno
160132070Sgrehan	stackframe = fp;
16199730Sbenno
162160312Sjhb	while (!db_pager_quit) {
163132070Sgrehan		if (stackframe < PAGE_SIZE)
16499730Sbenno			break;
165132070Sgrehan
166132070Sgrehan		/*
167132070Sgrehan		 * Locate the next frame by grabbing the backchain ptr
168132070Sgrehan		 * from frame[0]
169132070Sgrehan		 */
170132070Sgrehan		stackframe = *(db_addr_t *)stackframe;
171132070Sgrehan
172132070Sgrehan	next_frame:
173209975Snwhitehorn	    #ifdef __powerpc64__
174209975Snwhitehorn		/* The saved arg values start at frame[6] */
175209975Snwhitehorn		args = (db_addr_t *)(stackframe + 48);
176209975Snwhitehorn	    #else
177132070Sgrehan		/* The saved arg values start at frame[2] */
178132070Sgrehan		args = (db_addr_t *)(stackframe + 8);
179209975Snwhitehorn	    #endif
180132070Sgrehan
181132070Sgrehan		if (stackframe < PAGE_SIZE)
18299730Sbenno			break;
183132070Sgrehan
18499730Sbenno	        if (count-- == 0)
18599730Sbenno			break;
18699730Sbenno
187132070Sgrehan		/*
188132070Sgrehan		 * Extract link register from frame and subtract
189132070Sgrehan		 * 4 to convert into calling address (as opposed to
190132070Sgrehan		 * return address)
191132070Sgrehan		 */
192209975Snwhitehorn	    #ifdef __powerpc64__
193209975Snwhitehorn		lr = *(db_addr_t *)(stackframe + 16) - 4;
194209975Snwhitehorn	    #else
195132070Sgrehan		lr = *(db_addr_t *)(stackframe + 4) - 4;
196209975Snwhitehorn	    #endif
19799730Sbenno		if ((lr & 3) || (lr < 0x100)) {
198209975Snwhitehorn			db_printf("saved LR(0x%zx) is invalid.", lr);
19999730Sbenno			break;
20099730Sbenno		}
20199730Sbenno
202209975Snwhitehorn		#ifdef __powerpc64__
203223470Sandreast		db_printf("0x%016lx: ", stackframe);
204209975Snwhitehorn		#else
205132070Sgrehan		db_printf("0x%08x: ", stackframe);
206209975Snwhitehorn		#endif
207132070Sgrehan
208132070Sgrehan		/*
209153685Sgrehan		 * The trap code labels the return addresses from the
210153685Sgrehan		 * call to C code as 'trapexit' and 'asttrapexit. Use this
211153685Sgrehan		 * to determine if the callframe has to traverse a saved
212153685Sgrehan		 * trap context
213132070Sgrehan		 */
214209975Snwhitehorn		if ((lr + CALLOFFSET == (db_addr_t) &trapexit) ||
215209975Snwhitehorn		    (lr + CALLOFFSET == (db_addr_t) &asttrapexit)) {
21699730Sbenno			const char *trapstr;
217209975Snwhitehorn			struct trapframe *tf = (struct trapframe *)(args);
218132070Sgrehan			db_printf("%s ", tf->srr1 & PSL_PR ? "user" : "kernel");
21999730Sbenno			switch (tf->exc) {
22099730Sbenno			case EXC_DSI:
221176742Sraj				/* XXX take advantage of the union. */
222209975Snwhitehorn				db_printf("DSI %s trap @ %#zx by ",
223176742Sraj				    (tf->cpu.aim.dsisr & DSISR_STORE) ? "write"
224176742Sraj				    : "read", tf->cpu.aim.dar);
22599730Sbenno				goto print_trap;
226132070Sgrehan			case EXC_ALI:
227176742Sraj				/* XXX take advantage of the union. */
228209975Snwhitehorn				db_printf("ALI trap @ %#zx (xSR %#x) ",
229209975Snwhitehorn				    tf->cpu.aim.dar,
230209975Snwhitehorn				    (uint32_t)tf->cpu.aim.dsisr);
231132070Sgrehan				goto print_trap;
232209975Snwhitehorn#ifdef __powerpc64__
233209975Snwhitehorn			case EXC_DSE:
234209975Snwhitehorn				db_printf("DSE trap @ %#zx by ",
235209975Snwhitehorn				    tf->cpu.aim.dar);
236209975Snwhitehorn				goto print_trap;
237209975Snwhitehorn			case EXC_ISE:
238209975Snwhitehorn				db_printf("ISE trap @ %#zx by ", tf->srr0);
239209975Snwhitehorn				goto print_trap;
240209975Snwhitehorn#endif
24199730Sbenno			case EXC_ISI: trapstr = "ISI"; break;
24299730Sbenno			case EXC_PGM: trapstr = "PGM"; break;
24399730Sbenno			case EXC_SC: trapstr = "SC"; break;
24499730Sbenno			case EXC_EXI: trapstr = "EXI"; break;
24599730Sbenno			case EXC_MCHK: trapstr = "MCHK"; break;
246236141Sraj#if !defined(BOOKE)
24799730Sbenno			case EXC_VEC: trapstr = "VEC"; break;
24899730Sbenno			case EXC_FPA: trapstr = "FPA"; break;
24999730Sbenno			case EXC_BPT: trapstr = "BPT"; break;
25099730Sbenno			case EXC_TRC: trapstr = "TRC"; break;
25199730Sbenno			case EXC_RUNMODETRC: trapstr = "RUNMODETRC"; break;
25299730Sbenno			case EXC_SMI: trapstr = "SMI"; break;
25399730Sbenno			case EXC_RST: trapstr = "RST"; break;
254176742Sraj#endif
255176742Sraj			case EXC_FPU: trapstr = "FPU"; break;
256176742Sraj			case EXC_DECR: trapstr = "DECR"; break;
257176742Sraj			case EXC_PERF: trapstr = "PERF"; break;
25899730Sbenno			default: trapstr = NULL; break;
25999730Sbenno			}
26099730Sbenno			if (trapstr != NULL) {
261132070Sgrehan				db_printf("%s trap by ", trapstr);
26299730Sbenno			} else {
263209975Snwhitehorn				db_printf("trap %#zx by ", tf->exc);
26499730Sbenno			}
265132070Sgrehan
266132070Sgrehan		   print_trap:
26799730Sbenno			lr = (db_addr_t) tf->srr0;
26899730Sbenno			diff = 0;
26999730Sbenno			symname = NULL;
270132070Sgrehan			sym = db_search_symbol(lr, DB_STGY_ANY, &diff);
27199730Sbenno			db_symbol_values(sym, &symname, 0);
27299730Sbenno			if (symname == NULL || !strcmp(symname, "end")) {
273209975Snwhitehorn				db_printf("%#zx: srr1=%#zx\n", lr, tf->srr1);
27499730Sbenno			} else {
275209975Snwhitehorn				db_printf("%s+%#zx: srr1=%#zx\n", symname, diff,
27699730Sbenno				    tf->srr1);
27799730Sbenno			}
278209975Snwhitehorn			db_printf("%-10s  r1=%#zx cr=%#x xer=%#x ctr=%#zx",
279209975Snwhitehorn			    "", tf->fixreg[1], (uint32_t)tf->cr,
280209975Snwhitehorn			    (uint32_t)tf->xer, tf->ctr);
28199730Sbenno			if (tf->exc == EXC_DSI)
282209975Snwhitehorn				db_printf(" sr=%#x",
283209975Snwhitehorn				    (uint32_t)tf->cpu.aim.dsisr);
284132070Sgrehan			db_printf("\n");
285132070Sgrehan			stackframe = (db_addr_t) tf->fixreg[1];
28699730Sbenno			if (kernel_only && (tf->srr1 & PSL_PR))
28799730Sbenno				break;
28899730Sbenno			goto next_frame;
28999730Sbenno		}
29099730Sbenno
29199730Sbenno		diff = 0;
29299730Sbenno		symname = NULL;
293132070Sgrehan		sym = db_search_symbol(lr, DB_STGY_ANY, &diff);
29499730Sbenno		db_symbol_values(sym, &symname, 0);
29599730Sbenno		if (symname == NULL || !strcmp(symname, "end"))
296209975Snwhitehorn			db_printf("at %zx", lr);
29799730Sbenno		else
298209975Snwhitehorn			db_printf("at %s+%#zx", symname, diff);
29999730Sbenno		if (full)
30099730Sbenno			/* Print all the args stored in that stackframe. */
301209975Snwhitehorn			db_printf("(%zx, %zx, %zx, %zx, %zx, %zx, %zx, %zx)",
30299730Sbenno				args[0], args[1], args[2], args[3],
30399730Sbenno				args[4], args[5], args[6], args[7]);
304132070Sgrehan		db_printf("\n");
30599730Sbenno	}
306132070Sgrehan
307132070Sgrehan	return (0);
30899730Sbenno}
30999730Sbenno
31099730Sbennovoid
311132070Sgrehandb_trace_self(void)
312103646Sjhb{
313132070Sgrehan	db_addr_t addr;
314132070Sgrehan
315132070Sgrehan	addr = (db_addr_t)__builtin_frame_address(1);
316132070Sgrehan	db_backtrace(curthread, addr, -1);
317103646Sjhb}
318132070Sgrehan
319132070Sgrehanint
320132070Sgrehandb_trace_thread(struct thread *td, int count)
321132070Sgrehan{
322132070Sgrehan	struct pcb *ctx;
323132070Sgrehan
324132070Sgrehan	ctx = kdb_thr_ctx(td);
325132070Sgrehan	return (db_backtrace(td, (db_addr_t)ctx->pcb_sp, count));
326132070Sgrehan}
327