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