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