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