xref: /netbsd-src/sys/arch/powerpc/powerpc/db_trace.c (revision 0989b3cfd0bd01e4ff435f4cf4d4db2cd159a7a6)
1 /*	$NetBSD: db_trace.c,v 1.63 2023/04/13 06:39:23 riastradh 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 <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: db_trace.c,v 1.63 2023/04/13 06:39:23 riastradh Exp $");
32 
33 #ifdef _KERNEL_OPT
34 #include "opt_ppcarch.h"
35 #endif
36 
37 #include <sys/param.h>
38 #include <sys/proc.h>
39 #include <sys/kernel.h>
40 
41 #include <uvm/uvm_extern.h>
42 
43 #include <machine/db_machdep.h>
44 #include <machine/pmap.h>
45 
46 #include <powerpc/pcb.h>
47 #include <powerpc/psl.h>
48 #include <powerpc/spr.h>
49 #if defined (PPC_OEA) || defined(PPC_OEA64) || defined (PPC_OEA64_BRIDGE)
50 #include <powerpc/oea/spr.h>
51 #elif defined(PPC_IBM4XX)
52 #include <powerpc/ibm4xx/spr.h>
53 #elif defined(PPC_BOOKE)
54 #include <powerpc/booke/spr.h>
55 #else
56 #ifdef _KERNEL
57 #error unknown powerpc variants
58 #endif
59 #endif
60 
61 #ifndef _KERNEL			/* crash(8) */
62 #include <unistd.h>
63 #define	PAGE_SIZE	((unsigned)sysconf(_SC_PAGESIZE))
64 #endif
65 
66 #include <ddb/db_access.h>
67 #include <ddb/db_interface.h>
68 #include <ddb/db_proc.h>
69 #include <ddb/db_sym.h>
70 #include <ddb/db_variables.h>
71 
72 #define	R(P)								      \
73 ({									      \
74 	__typeof__(*(P)) __db_tmp;					      \
75 	db_read_bytes((db_addr_t)(P), sizeof(*(P)), (char *)&__db_tmp);	      \
76 	__db_tmp;							      \
77 })
78 
79 const struct db_variable db_regs[] = {
80 	{ "r0",  (long *)&ddb_regs.r[0],  FCN_NULL, NULL },
81 	{ "r1",  (long *)&ddb_regs.r[1],  FCN_NULL, NULL },
82 	{ "r2",  (long *)&ddb_regs.r[2],  FCN_NULL, NULL },
83 	{ "r3",  (long *)&ddb_regs.r[3],  FCN_NULL, NULL },
84 	{ "r4",  (long *)&ddb_regs.r[4],  FCN_NULL, NULL },
85 	{ "r5",  (long *)&ddb_regs.r[5],  FCN_NULL, NULL },
86 	{ "r6",  (long *)&ddb_regs.r[6],  FCN_NULL, NULL },
87 	{ "r7",  (long *)&ddb_regs.r[7],  FCN_NULL, NULL },
88 	{ "r8",  (long *)&ddb_regs.r[8],  FCN_NULL, NULL },
89 	{ "r9",  (long *)&ddb_regs.r[9],  FCN_NULL, NULL },
90 	{ "r10", (long *)&ddb_regs.r[10], FCN_NULL, NULL },
91 	{ "r11", (long *)&ddb_regs.r[11], FCN_NULL, NULL },
92 	{ "r12", (long *)&ddb_regs.r[12], FCN_NULL, NULL },
93 	{ "r13", (long *)&ddb_regs.r[13], FCN_NULL, NULL },
94 	{ "r14", (long *)&ddb_regs.r[14], FCN_NULL, NULL },
95 	{ "r15", (long *)&ddb_regs.r[15], FCN_NULL, NULL },
96 	{ "r16", (long *)&ddb_regs.r[16], FCN_NULL, NULL },
97 	{ "r17", (long *)&ddb_regs.r[17], FCN_NULL, NULL },
98 	{ "r18", (long *)&ddb_regs.r[18], FCN_NULL, NULL },
99 	{ "r19", (long *)&ddb_regs.r[19], FCN_NULL, NULL },
100 	{ "r20", (long *)&ddb_regs.r[20], FCN_NULL, NULL },
101 	{ "r21", (long *)&ddb_regs.r[21], FCN_NULL, NULL },
102 	{ "r22", (long *)&ddb_regs.r[22], FCN_NULL, NULL },
103 	{ "r23", (long *)&ddb_regs.r[23], FCN_NULL, NULL },
104 	{ "r24", (long *)&ddb_regs.r[24], FCN_NULL, NULL },
105 	{ "r25", (long *)&ddb_regs.r[25], FCN_NULL, NULL },
106 	{ "r26", (long *)&ddb_regs.r[26], FCN_NULL, NULL },
107 	{ "r27", (long *)&ddb_regs.r[27], FCN_NULL, NULL },
108 	{ "r28", (long *)&ddb_regs.r[28], FCN_NULL, NULL },
109 	{ "r29", (long *)&ddb_regs.r[29], FCN_NULL, NULL },
110 	{ "r30", (long *)&ddb_regs.r[30], FCN_NULL, NULL },
111 	{ "r31", (long *)&ddb_regs.r[31], FCN_NULL, NULL },
112 	{ "iar", (long *)&ddb_regs.iar,   FCN_NULL, NULL },
113 	{ "msr", (long *)&ddb_regs.msr,   FCN_NULL, NULL },
114 	{ "lr",  (long *)&ddb_regs.lr,    FCN_NULL, NULL },
115 	{ "ctr", (long *)&ddb_regs.ctr,   FCN_NULL, NULL },
116 	{ "cr",  (long *)&ddb_regs.cr,    FCN_NULL, NULL },
117 	{ "xer", (long *)&ddb_regs.xer,   FCN_NULL, NULL },
118 	{ "mq",  (long *)&ddb_regs.mq,    FCN_NULL, NULL },
119 #ifdef PPC_IBM4XX		/* XXX crash(8) */
120 	{ "dear", (long *)&ddb_regs.dear, FCN_NULL, NULL },
121 	{ "esr", (long *)&ddb_regs.esr,   FCN_NULL, NULL },
122 	{ "pid", (long *)&ddb_regs.pid,   FCN_NULL, NULL },
123 #endif
124 };
125 const struct db_variable * const db_eregs = db_regs + sizeof (db_regs)/sizeof (db_regs[0]);
126 
127 /*
128  *	Frame tracing.
129  */
130 void
db_stack_trace_print(db_expr_t addr,bool have_addr,db_expr_t count,const char * modif,void (* pr)(const char *,...))131 db_stack_trace_print(db_expr_t addr, bool have_addr, db_expr_t count,
132 	const char *modif, void (*pr)(const char *, ...))
133 {
134 	db_addr_t frame, lr, *args;
135 	db_expr_t diff;
136 	db_sym_t sym;
137 	const char *symname;
138 	const char *cp = modif;
139 	char c;
140 	bool kernel_only = true;
141 	bool trace_thread = false;
142 	bool lwpaddr = false;
143 #ifdef _KERNEL
144 	extern int trapexit[], sctrapexit[];
145 #ifdef PPC_BOOKE
146 	extern int intrcall[];
147 #endif
148 #else
149 	extern void *trapexit, *sctrapexit, *intrcall;
150 #endif
151 	bool full = false;
152 	bool in_kernel = true;
153 
154 	while ((c = *cp++) != 0) {
155 		if (c == 'a') {
156 			lwpaddr = true;
157 			trace_thread = true;
158 		}
159 		if (c == 't')
160 			trace_thread = true;
161 		if (c == 'u')
162 			kernel_only = false;
163 		if (c == 'f')
164 			full = true;
165 	}
166 
167 	if (have_addr) {
168 		if (trace_thread) {
169 			struct proc *p;
170 			struct lwp *l;
171 			struct pcb *pcb;
172 
173 			if (lwpaddr) {
174 				l = (struct lwp *)addr;
175 				p = R(&l->l_proc);
176 				(*pr)("trace: pid %d ", R(&p->p_pid));
177 			} else {
178 				(*pr)("trace: pid %d ", (int)addr);
179 				p = db_proc_find((pid_t)addr);
180 				if (p == NULL) {
181 					(*pr)("not found\n");
182 					return;
183 				}
184 				l = R(&LIST_FIRST(&p->p_lwps));
185 				if (l == NULL) {
186 					(*pr)("trace: no LWP?\n");
187 					return;
188 				}
189 			}
190 			(*pr)("lid %d ", R(&l->l_lid));
191 			pcb = R(&l->l_addr); /* lwp_getpcb */
192 			frame = (db_addr_t)R(&pcb->pcb_sp);
193 			(*pr)("at %p\n", frame);
194 		} else
195 			frame = (db_addr_t)addr;
196 	} else {
197 		frame = (db_addr_t)ddb_regs.r[1];
198 	}
199 	for (;;) {
200 		if (frame < PAGE_SIZE)
201 			break;
202 		frame = R((db_addr_t *)frame);
203 	    next_frame:
204 		args = (db_addr_t *)(frame + 8);
205 		if (frame < PAGE_SIZE)
206 			break;
207 	        if (count-- == 0)
208 			break;
209 
210 		lr = R((db_addr_t *)(frame + 4)) - 4;
211 		if ((lr & 3) || (lr < 0x100)) {
212 			(*pr)("saved LR(0x%x) is invalid.", lr);
213 			break;
214 		}
215 
216 		(*pr)("0x%08lx: ", frame);
217 		if (lr + 4 == (db_addr_t) trapexit ||
218 #if !defined(_KERNEL) || defined(PPC_BOOKE) /* XXX crash(8) */
219 		    lr + 4 == (db_addr_t) intrcall ||
220 #endif
221 		    lr + 4 == (db_addr_t) sctrapexit) {
222 			const char *trapstr;
223 			struct trapframe *tf =
224 			    &((struct ktrapframe *)frame)->ktf_tf;
225 			(*pr)("%s ",
226 			    R(&tf->tf_srr1) & PSL_PR ? "user" : "kernel");
227 			if (lr + 4 == (db_addr_t) sctrapexit) {
228 				(*pr)("SC trap #%d by ", R(&tf->tf_fixreg[0]));
229 				goto print_trap;
230 			}
231 			switch (R(&tf->tf_exc)) {
232 			case EXC_DSI:
233 #ifdef PPC_OEA			/* XXX crash(8) */
234 				(*pr)("DSI %s trap @ %#x by ",
235 				    (R(&tf->tf_dsisr) & DSISR_STORE
236 					? "write"
237 					: "read"),
238 				    R(&tf->tf_dar));
239 #endif
240 #ifdef PPC_IBM4XX		/* XXX crash(8) */
241 				trapstr = "DSI";
242 dsi:
243 				(*pr)("%s %s trap @ %#x by ", trapstr,
244 				    (R(&tf->tf_esr) & ESR_DST
245 					? "write"
246 					: "read"),
247 				    R(&tf->tf_dear));
248 #endif
249 				goto print_trap;
250 			case EXC_ALI:
251 #ifdef PPC_OEA			/* XXX crash(8) */
252 				(*pr)("ALI trap @ %#x (DSISR %#x) ",
253 				    R(&tf->tf_dar), R(&tf->tf_dsisr));
254 				goto print_trap;
255 #else
256 				trapstr = "ALI"; break;
257 #endif
258 			case EXC_ISI: trapstr = "ISI"; break;
259 			case EXC_PGM: trapstr = "PGM"; break;
260 			case EXC_SC: trapstr = "SC"; break;
261 			case EXC_EXI: trapstr = "EXI"; break;
262 			case EXC_MCHK: trapstr = "MCHK"; break;
263 			case EXC_VEC: trapstr = "VEC"; break;
264 			case EXC_FPU: trapstr = "FPU"; break;
265 			case EXC_FPA: trapstr = "FPA"; break;
266 			case EXC_DECR: trapstr = "DECR"; break;
267 			case EXC_BPT: trapstr = "BPT"; break;
268 			case EXC_TRC: trapstr = "TRC"; break;
269 			case EXC_RUNMODETRC: trapstr = "RUNMODETRC"; break;
270 			case EXC_PERF: trapstr = "PERF"; break;
271 			case EXC_SMI: trapstr = "SMI"; break;
272 			case EXC_RST: trapstr = "RST"; break;
273 			case EXC_DTMISS: trapstr = "DTMISS";
274 #ifdef PPC_IBM4XX		/* XXX crash(8) */
275 				goto dsi;
276 #endif
277 				break;
278 			case EXC_ITMISS: trapstr = "ITMISS"; break;
279 			case EXC_FIT: trapstr = "FIT"; break;
280 			case EXC_PIT: trapstr = "PIT"; break;
281 			case EXC_WDOG: trapstr = "WDOG"; break;
282 			default: trapstr = NULL; break;
283 			}
284 			if (trapstr != NULL) {
285 				(*pr)("%s trap by ", trapstr);
286 			} else {
287 				(*pr)("trap %#x by ", R(&tf->tf_exc));
288 			}
289 		   print_trap:
290 			lr = (db_addr_t)R(&tf->tf_srr0);
291 			diff = 0;
292 			symname = NULL;
293 			if (in_kernel && (R(&tf->tf_srr1) & PSL_PR) == 0) {
294 				sym = db_search_symbol(lr, DB_STGY_ANY, &diff);
295 				db_symbol_values(sym, &symname, 0);
296 			}
297 			if (symname == NULL || !strcmp(symname, "end")) {
298 				(*pr)("%p: srr1=%#x\n", lr, R(&tf->tf_srr1));
299 			} else {
300 				(*pr)("%s+%#x: srr1=%#x\n", symname,
301 				    diff, R(&tf->tf_srr1));
302 			}
303 			(*pr)("%-10s  r1=%#x cr=%#x xer=%#x ctr=%#x",
304 			    "",
305 			    R(&tf->tf_fixreg[1]),
306 			    R(&tf->tf_cr),
307 			    R(&tf->tf_xer),
308 			    R(&tf->tf_ctr));
309 #ifdef PPC_OEA			/* XXX crash(8) */
310 			if (R(&tf->tf_exc) == EXC_DSI)
311 				(*pr)(" dsisr=%#x", R(&tf->tf_dsisr));
312 #ifdef PPC_OEA601		/* XXX crash(8) */
313 			if ((mfpvr() >> 16) == MPC601) /* XXX crash(8) */
314 				(*pr)(" mq=%#x", R(&tf->tf_mq));
315 #endif /* PPC_OEA601 */
316 #endif /* PPC_OEA */
317 #ifdef PPC_IBM4XX		/* XXX crash(8) */
318 			if (R(&tf->tf_exc) == EXC_DSI ||
319 			    R(&tf->tf_exc) == EXC_DTMISS)
320 				(*pr)(" dear=%#x", R(&tf->tf_dear));
321 			(*pr)(" esr=%#x pid=%#x", R(&tf->tf_esr),
322 			    R(&tf->tf_pid));
323 #endif
324 			(*pr)("\n");
325 			frame = (db_addr_t)R(&tf->tf_fixreg[1]);
326 			in_kernel = !(R(&tf->tf_srr1) & PSL_PR);
327 			if (kernel_only && !in_kernel)
328 				break;
329 			goto next_frame;
330 		}
331 
332 		diff = 0;
333 		symname = NULL;
334 		if (in_kernel) {
335 			sym = db_search_symbol(lr, DB_STGY_ANY, &diff);
336 			db_symbol_values(sym, &symname, 0);
337 		}
338 		if (symname == NULL || !strcmp(symname, "end"))
339 			(*pr)("at %p", lr);
340 		else
341 			(*pr)("at %s+%#x", symname, diff);
342 		if (full)
343 			/* Print all the args stored in that stackframe. */
344 			(*pr)("(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)",
345 			    R(&args[0]), R(&args[1]), R(&args[2]), R(&args[3]),
346 			    R(&args[4]), R(&args[5]), R(&args[6]), R(&args[7]));
347 		(*pr)("\n");
348 	}
349 }
350