db_trace.c revision 104435
1/*	$FreeBSD: head/sys/powerpc/powerpc/db_trace.c 104435 2002-10-04 01:19:18Z grehan $ */
2/*	$NetBSD: db_trace.c,v 1.20 2002/05/13 20:30:09 matt Exp $	*/
3/*	$OpenBSD: db_trace.c,v 1.3 1997/03/21 02:10:48 niklas Exp $	*/
4
5/*
6 * Mach Operating System
7 * Copyright (c) 1992 Carnegie Mellon University
8 * All Rights Reserved.
9 *
10 * Permission to use, copy, modify and distribute this software and its
11 * documentation is hereby granted, provided that both the copyright
12 * notice and this permission notice appear in all copies of the
13 * software, derivative works or modified versions, and any portions
14 * thereof, and that both notices appear in supporting documentation.
15 *
16 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
17 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
18 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
19 *
20 * Carnegie Mellon requests users of this software to return to
21 *
22 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
23 *  School of Computer Science
24 *  Carnegie Mellon University
25 *  Pittsburgh PA 15213-3890
26 *
27 * any improvements or extensions that they make and grant Carnegie Mellon
28 * the rights to redistribute these changes.
29 */
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/proc.h>
34#include <sys/user.h>
35
36#include <vm/vm.h>
37#include <vm/pmap.h>
38#include <vm/vm_extern.h>
39
40#include <machine/db_machdep.h>
41#include <machine/spr.h>
42#include <machine/trap.h>
43
44#include <ddb/ddb.h>
45#include <ddb/db_access.h>
46#include <ddb/db_sym.h>
47#include <ddb/db_variables.h>
48
49struct db_variable db_regs[] = {
50	{ "r0",  &ddb_regs.r[0],  FCN_NULL },
51	{ "r1",  &ddb_regs.r[1],  FCN_NULL },
52	{ "r2",  &ddb_regs.r[2],  FCN_NULL },
53	{ "r3",  &ddb_regs.r[3],  FCN_NULL },
54	{ "r4",  &ddb_regs.r[4],  FCN_NULL },
55	{ "r5",  &ddb_regs.r[5],  FCN_NULL },
56	{ "r6",  &ddb_regs.r[6],  FCN_NULL },
57	{ "r7",  &ddb_regs.r[7],  FCN_NULL },
58	{ "r8",  &ddb_regs.r[8],  FCN_NULL },
59	{ "r9",  &ddb_regs.r[9],  FCN_NULL },
60	{ "r10", &ddb_regs.r[10], FCN_NULL },
61	{ "r11", &ddb_regs.r[11], FCN_NULL },
62	{ "r12", &ddb_regs.r[12], FCN_NULL },
63	{ "r13", &ddb_regs.r[13], FCN_NULL },
64	{ "r14", &ddb_regs.r[14], FCN_NULL },
65	{ "r15", &ddb_regs.r[15], FCN_NULL },
66	{ "r16", &ddb_regs.r[16], FCN_NULL },
67	{ "r17", &ddb_regs.r[17], FCN_NULL },
68	{ "r18", &ddb_regs.r[18], FCN_NULL },
69	{ "r19", &ddb_regs.r[19], FCN_NULL },
70	{ "r20", &ddb_regs.r[20], FCN_NULL },
71	{ "r21", &ddb_regs.r[21], FCN_NULL },
72	{ "r22", &ddb_regs.r[22], FCN_NULL },
73	{ "r23", &ddb_regs.r[23], FCN_NULL },
74	{ "r24", &ddb_regs.r[24], FCN_NULL },
75	{ "r25", &ddb_regs.r[25], FCN_NULL },
76	{ "r26", &ddb_regs.r[26], FCN_NULL },
77	{ "r27", &ddb_regs.r[27], FCN_NULL },
78	{ "r28", &ddb_regs.r[28], FCN_NULL },
79	{ "r29", &ddb_regs.r[29], FCN_NULL },
80	{ "r30", &ddb_regs.r[30], FCN_NULL },
81	{ "r31", &ddb_regs.r[31], FCN_NULL },
82	{ "iar", &ddb_regs.iar,   FCN_NULL },
83	{ "msr", &ddb_regs.msr,   FCN_NULL },
84	{ "lr",  &ddb_regs.lr,    FCN_NULL },
85	{ "ctr", &ddb_regs.ctr,   FCN_NULL },
86	{ "cr",  &ddb_regs.cr,    FCN_NULL },
87	{ "xer", &ddb_regs.xer,   FCN_NULL },
88#ifdef PPC_IBM4XX
89	{ "dear", &ddb_regs.dear, FCN_NULL },
90	{ "esr", &ddb_regs.esr,   FCN_NULL },
91	{ "pid", &ddb_regs.pid,   FCN_NULL },
92#endif
93};
94struct db_variable *db_eregs = db_regs + sizeof (db_regs)/sizeof (db_regs[0]);
95
96extern int trapexit[];
97extern int end[];
98
99/*
100 *	Frame tracing.
101 */
102static void
103db_stack_trace_print(db_expr_t addr, int have_addr, db_expr_t count,
104		     char *modif, void (*pr)(const char *, ...))
105{
106	db_addr_t frame, lr, caller, *args;
107	db_addr_t fakeframe[2];
108	db_expr_t diff;
109	c_db_sym_t sym;
110	const char *symname;
111	boolean_t kernel_only = TRUE;
112	boolean_t trace_thread = FALSE;
113	boolean_t full = FALSE;
114
115	{
116		register char *cp = modif;
117		register char c;
118
119		while ((c = *cp++) != 0) {
120			if (c == 't')
121				trace_thread = TRUE;
122			if (c == 'u')
123				kernel_only = FALSE;
124			if (c == 'f')
125				full = TRUE;
126		}
127	}
128
129	if (have_addr) {
130#if 0
131		if (trace_thread) {
132			struct proc *p;
133			struct user *u;
134
135			(*pr)("trace: pid %d ", (int)addr);
136			p = pfind(addr);
137			if (p == NULL) {
138				(*pr)("not found\n");
139				return;
140			}
141			if (!(p->p_flag&P_INMEM)) {
142				(*pr)("swapped out\n");
143				return;
144			}
145			u = p->p_addr;
146			frame = (db_addr_t)u->u_pcb.pcb_sp;
147			(*pr)("at %p\n", frame);
148		} else
149#endif
150			frame = (db_addr_t)addr;
151	} else {
152		frame = (db_addr_t)ddb_regs.r[1];
153	}
154	for (;;) {
155		if (frame < PAGE_SIZE)
156			break;
157#ifdef PPC_MPC6XX
158		if (kernel_only &&
159		    ((frame > (db_addr_t) end &&
160		      frame < VM_MIN_KERNEL_ADDRESS) ||
161		     frame >= VM_MAX_KERNEL_ADDRESS))
162			break;
163#endif
164		frame = *(db_addr_t *)frame;
165	    next_frame:
166		args = (db_addr_t *)(frame + 8);
167		if (frame < PAGE_SIZE)
168			break;
169#ifdef PPC_MPC6XX
170		if (kernel_only &&
171		    ((frame > (db_addr_t) end &&
172		      frame < VM_MIN_KERNEL_ADDRESS) ||
173		     frame >= VM_MAX_KERNEL_ADDRESS))
174			break;
175#endif
176	        if (count-- == 0)
177			break;
178
179		lr = *(db_addr_t *)(frame + 4) - 4;
180		if ((lr & 3) || (lr < 0x100)) {
181			(*pr)("saved LR(0x%x) is invalid.", lr);
182			break;
183		}
184		if ((caller = (db_addr_t)vtophys(lr)) == 0)
185			caller = lr;
186
187		if (frame != (db_addr_t) fakeframe) {
188			(*pr)("0x%08lx: ", frame);
189		} else {
190			(*pr)("     <?>  : ");
191		}
192		if (caller + 4 == (db_addr_t) &trapexit) {
193			const char *trapstr;
194			struct trapframe *tf = (struct trapframe *) (frame+8);
195			(*pr)("%s ", tf->srr1 & PSL_PR ? "user" : "kernel");
196			switch (tf->exc) {
197			case EXC_DSI:
198#ifdef PPC_MPC6XX
199				(*pr)("DSI %s trap @ %#x by ",
200				    tf->dsisr & DSISR_STORE ? "write" : "read",
201				    tf->dar);
202#endif
203#ifdef PPC_IBM4XX
204				(*pr)("DSI %s trap @ %#x by ",
205				    tf->esr & ESR_DST ? "write" : "read",
206				    tf->dear);
207#endif
208				goto print_trap;
209			case EXC_ISI: trapstr = "ISI"; break;
210			case EXC_PGM: trapstr = "PGM"; break;
211			case EXC_SC: trapstr = "SC"; break;
212			case EXC_EXI: trapstr = "EXI"; break;
213			case EXC_MCHK: trapstr = "MCHK"; break;
214			case EXC_VEC: trapstr = "VEC"; break;
215			case EXC_FPU: trapstr = "FPU"; break;
216			case EXC_FPA: trapstr = "FPA"; break;
217			case EXC_DECR: trapstr = "DECR"; break;
218			case EXC_ALI: trapstr = "ALI"; break;
219			case EXC_BPT: trapstr = "BPT"; break;
220			case EXC_TRC: trapstr = "TRC"; break;
221			case EXC_RUNMODETRC: trapstr = "RUNMODETRC"; break;
222			case EXC_PERF: trapstr = "PERF"; break;
223			case EXC_SMI: trapstr = "SMI"; break;
224			case EXC_RST: trapstr = "RST"; break;
225			default: trapstr = NULL; break;
226			}
227			if (trapstr != NULL) {
228				(*pr)("%s trap by ", trapstr);
229			} else {
230				(*pr)("trap %#x by ", tf->exc);
231			}
232		   print_trap:
233			lr = (db_addr_t) tf->srr0;
234			if ((caller = (db_addr_t)vtophys(lr)) == 0)
235				caller = lr;
236			diff = 0;
237			symname = NULL;
238			sym = db_search_symbol(caller, DB_STGY_ANY, &diff);
239			db_symbol_values(sym, &symname, 0);
240			if (symname == NULL || !strcmp(symname, "end")) {
241				(*pr)("%p: srr1=%#x\n", caller, tf->srr1);
242			} else {
243				(*pr)("%s+%x: srr1=%#x\n", symname, diff,
244				    tf->srr1);
245			}
246			(*pr)("%-10s  r1=%#x cr=%#x xer=%#x ctr=%#x",
247			    "", tf->fixreg[1], tf->cr, tf->xer, tf->ctr);
248#ifdef PPC_MPC6XX
249			if (tf->exc == EXC_DSI)
250				(*pr)(" dsisr=%#x", tf->dsisr);
251#endif
252#ifdef PPC_IBM4XX
253			if (tf->exc == EXC_DSI)
254				(*pr)(" dear=%#x", tf->dear);
255			(*pr)(" esr=%#x pid=%#x", tf->esr, tf->pid);
256#endif
257			(*pr)("\n");
258			fakeframe[0] = (db_addr_t) tf->fixreg[1];
259			fakeframe[1] = (db_addr_t) tf->lr;
260			frame = (db_addr_t) fakeframe;
261			if (kernel_only && (tf->srr1 & PSL_PR))
262				break;
263			goto next_frame;
264		}
265
266		diff = 0;
267		symname = NULL;
268		sym = db_search_symbol(caller, DB_STGY_ANY, &diff);
269		db_symbol_values(sym, &symname, 0);
270		if (symname == NULL || !strcmp(symname, "end"))
271			(*pr)("at %p", caller);
272		else
273			(*pr)("at %s+%#x", symname, diff);
274		if (full)
275			/* Print all the args stored in that stackframe. */
276			(*pr)("(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)",
277				args[0], args[1], args[2], args[3],
278				args[4], args[5], args[6], args[7]);
279		(*pr)("\n");
280	}
281}
282
283void
284db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count,
285    char *modif)
286{
287
288	db_stack_trace_print(addr, have_addr, count, modif, db_printf);
289}
290
291void
292db_print_backtrace(void)
293{
294}
295