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 (at) 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 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