1/* $FreeBSD: releng/10.3/sys/powerpc/powerpc/db_trace.c 236141 2012-05-27 10:25:20Z raj $ */ 2/* $NetBSD: db_trace.c,v 1.20 2002/05/13 20:30:09 matt Exp $ */ 3/* $OpenBSD: db_trace.c,v 1.3 1997/03/21 02:10:48 niklas Exp $ */ 4 5/*- 6 * Mach Operating System 7 * Copyright (c) 1992 Carnegie Mellon University 8 * All Rights Reserved. 9 * 10 * Permission to use, copy, modify and distribute this software and its 11 * documentation is hereby granted, provided that both the copyright 12 * notice and this permission notice appear in all copies of the 13 * software, derivative works or modified versions, and any portions 14 * thereof, and that both notices appear in supporting documentation. 15 * 16 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 17 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 18 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 19 * 20 * Carnegie Mellon requests users of this software to return to 21 * 22 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 23 * School of Computer Science 24 * Carnegie Mellon University 25 * Pittsburgh PA 15213-3890 26 * 27 * any improvements or extensions that they make and grant Carnegie Mellon 28 * the rights to redistribute these changes. 29 */ 30 31#include <sys/param.h> 32#include <sys/systm.h> 33#include <sys/kdb.h> 34#include <sys/proc.h> 35#include <sys/stack.h> 36 37#include <vm/vm.h> 38#include <vm/pmap.h> 39#include <vm/vm_extern.h> 40 41#include <machine/db_machdep.h> 42#include <machine/pcb.h> 43#include <machine/spr.h> 44#include <machine/stack.h> 45#include <machine/trap.h> 46 47#include <ddb/ddb.h> 48#include <ddb/db_access.h> 49#include <ddb/db_sym.h> 50#include <ddb/db_variables.h> 51 52static db_varfcn_t db_frame; 53 54#define DB_OFFSET(x) (db_expr_t *)offsetof(struct trapframe, x) 55 56#ifdef __powerpc64__ 57#define CALLOFFSET 8 /* Include TOC reload slot */ 58#else 59#define CALLOFFSET 4 60#endif 61 62struct db_variable db_regs[] = { 63 { "r0", DB_OFFSET(fixreg[0]), db_frame }, 64 { "r1", DB_OFFSET(fixreg[1]), db_frame }, 65 { "r2", DB_OFFSET(fixreg[2]), db_frame }, 66 { "r3", DB_OFFSET(fixreg[3]), db_frame }, 67 { "r4", DB_OFFSET(fixreg[4]), db_frame }, 68 { "r5", DB_OFFSET(fixreg[5]), db_frame }, 69 { "r6", DB_OFFSET(fixreg[6]), db_frame }, 70 { "r7", DB_OFFSET(fixreg[7]), db_frame }, 71 { "r8", DB_OFFSET(fixreg[8]), db_frame }, 72 { "r9", DB_OFFSET(fixreg[9]), db_frame }, 73 { "r10", DB_OFFSET(fixreg[10]), db_frame }, 74 { "r11", DB_OFFSET(fixreg[11]), db_frame }, 75 { "r12", DB_OFFSET(fixreg[12]), db_frame }, 76 { "r13", DB_OFFSET(fixreg[13]), db_frame }, 77 { "r14", DB_OFFSET(fixreg[14]), db_frame }, 78 { "r15", DB_OFFSET(fixreg[15]), db_frame }, 79 { "r16", DB_OFFSET(fixreg[16]), db_frame }, 80 { "r17", DB_OFFSET(fixreg[17]), db_frame }, 81 { "r18", DB_OFFSET(fixreg[18]), db_frame }, 82 { "r19", DB_OFFSET(fixreg[19]), db_frame }, 83 { "r20", DB_OFFSET(fixreg[20]), db_frame }, 84 { "r21", DB_OFFSET(fixreg[21]), db_frame }, 85 { "r22", DB_OFFSET(fixreg[22]), db_frame }, 86 { "r23", DB_OFFSET(fixreg[23]), db_frame }, 87 { "r24", DB_OFFSET(fixreg[24]), db_frame }, 88 { "r25", DB_OFFSET(fixreg[25]), db_frame }, 89 { "r26", DB_OFFSET(fixreg[26]), db_frame }, 90 { "r27", DB_OFFSET(fixreg[27]), db_frame }, 91 { "r28", DB_OFFSET(fixreg[28]), db_frame }, 92 { "r29", DB_OFFSET(fixreg[29]), db_frame }, 93 { "r30", DB_OFFSET(fixreg[30]), db_frame }, 94 { "r31", DB_OFFSET(fixreg[31]), db_frame }, 95 { "srr0", DB_OFFSET(srr0), db_frame }, 96 { "srr1", DB_OFFSET(srr1), db_frame }, 97 { "lr", DB_OFFSET(lr), db_frame }, 98 { "ctr", DB_OFFSET(ctr), db_frame }, 99 { "cr", DB_OFFSET(cr), db_frame }, 100 { "xer", DB_OFFSET(xer), db_frame }, 101#ifdef AIM 102 { "dar", DB_OFFSET(cpu.aim.dar), db_frame }, 103 { "dsisr", DB_OFFSET(cpu.aim.dsisr), db_frame }, 104#endif 105#if defined(BOOKE) 106 { "dear", DB_OFFSET(cpu.booke.dear), db_frame }, 107 { "esr", DB_OFFSET(cpu.booke.esr), db_frame }, 108#endif 109}; 110struct db_variable *db_eregs = db_regs + sizeof (db_regs)/sizeof (db_regs[0]); 111 112/* 113 * register variable handling 114 */ 115static int 116db_frame(struct db_variable *vp, db_expr_t *valuep, int op) 117{ 118 register_t *reg; 119 120 if (kdb_frame == NULL) 121 return (0); 122 reg = (register_t*)((uintptr_t)kdb_frame + (uintptr_t)vp->valuep); 123 if (op == DB_VAR_GET) 124 *valuep = *reg; 125 else 126 *reg = *valuep; 127 return (1); 128} 129 130 131/* 132 * Frame tracing. 133 */ 134static int 135db_backtrace(struct thread *td, db_addr_t fp, int count) 136{ 137 db_addr_t stackframe, lr, *args; 138 db_expr_t diff; 139 c_db_sym_t sym; 140 const char *symname; 141 boolean_t kernel_only = TRUE; 142 boolean_t full = FALSE; 143 144#if 0 145 { 146 register char *cp = modif; 147 register char c; 148 149 while ((c = *cp++) != 0) { 150 if (c == 't') 151 trace_thread = TRUE; 152 if (c == 'u') 153 kernel_only = FALSE; 154 if (c == 'f') 155 full = TRUE; 156 } 157 } 158#endif 159 160 stackframe = fp; 161 162 while (!db_pager_quit) { 163 if (stackframe < PAGE_SIZE) 164 break; 165 166 /* 167 * Locate the next frame by grabbing the backchain ptr 168 * from frame[0] 169 */ 170 stackframe = *(db_addr_t *)stackframe; 171 172 next_frame: 173 #ifdef __powerpc64__ 174 /* The saved arg values start at frame[6] */ 175 args = (db_addr_t *)(stackframe + 48); 176 #else 177 /* The saved arg values start at frame[2] */ 178 args = (db_addr_t *)(stackframe + 8); 179 #endif 180 181 if (stackframe < PAGE_SIZE) 182 break; 183 184 if (count-- == 0) 185 break; 186 187 /* 188 * Extract link register from frame and subtract 189 * 4 to convert into calling address (as opposed to 190 * return address) 191 */ 192 #ifdef __powerpc64__ 193 lr = *(db_addr_t *)(stackframe + 16) - 4; 194 #else 195 lr = *(db_addr_t *)(stackframe + 4) - 4; 196 #endif 197 if ((lr & 3) || (lr < 0x100)) { 198 db_printf("saved LR(0x%zx) is invalid.", lr); 199 break; 200 } 201 202 #ifdef __powerpc64__ 203 db_printf("0x%016lx: ", stackframe); 204 #else 205 db_printf("0x%08x: ", stackframe); 206 #endif 207 208 /* 209 * The trap code labels the return addresses from the 210 * call to C code as 'trapexit' and 'asttrapexit. Use this 211 * to determine if the callframe has to traverse a saved 212 * trap context 213 */ 214 if ((lr + CALLOFFSET == (db_addr_t) &trapexit) || 215 (lr + CALLOFFSET == (db_addr_t) &asttrapexit)) { 216 const char *trapstr; 217 struct trapframe *tf = (struct trapframe *)(args); 218 db_printf("%s ", tf->srr1 & PSL_PR ? "user" : "kernel"); 219 switch (tf->exc) { 220 case EXC_DSI: 221 /* XXX take advantage of the union. */ 222 db_printf("DSI %s trap @ %#zx by ", 223 (tf->cpu.aim.dsisr & DSISR_STORE) ? "write" 224 : "read", tf->cpu.aim.dar); 225 goto print_trap; 226 case EXC_ALI: 227 /* XXX take advantage of the union. */ 228 db_printf("ALI trap @ %#zx (xSR %#x) ", 229 tf->cpu.aim.dar, 230 (uint32_t)tf->cpu.aim.dsisr); 231 goto print_trap; 232#ifdef __powerpc64__ 233 case EXC_DSE: 234 db_printf("DSE trap @ %#zx by ", 235 tf->cpu.aim.dar); 236 goto print_trap; 237 case EXC_ISE: 238 db_printf("ISE trap @ %#zx by ", tf->srr0); 239 goto print_trap; 240#endif 241 case EXC_ISI: trapstr = "ISI"; break; 242 case EXC_PGM: trapstr = "PGM"; break; 243 case EXC_SC: trapstr = "SC"; break; 244 case EXC_EXI: trapstr = "EXI"; break; 245 case EXC_MCHK: trapstr = "MCHK"; break; 246#if !defined(BOOKE) 247 case EXC_VEC: trapstr = "VEC"; break; 248 case EXC_FPA: trapstr = "FPA"; break; 249 case EXC_BPT: trapstr = "BPT"; break; 250 case EXC_TRC: trapstr = "TRC"; break; 251 case EXC_RUNMODETRC: trapstr = "RUNMODETRC"; break; 252 case EXC_SMI: trapstr = "SMI"; break; 253 case EXC_RST: trapstr = "RST"; break; 254#endif 255 case EXC_FPU: trapstr = "FPU"; break; 256 case EXC_DECR: trapstr = "DECR"; break; 257 case EXC_PERF: trapstr = "PERF"; break; 258 default: trapstr = NULL; break; 259 } 260 if (trapstr != NULL) { 261 db_printf("%s trap by ", trapstr); 262 } else { 263 db_printf("trap %#zx by ", tf->exc); 264 } 265 266 print_trap: 267 lr = (db_addr_t) tf->srr0; 268 diff = 0; 269 symname = NULL; 270 sym = db_search_symbol(lr, DB_STGY_ANY, &diff); 271 db_symbol_values(sym, &symname, 0); 272 if (symname == NULL || !strcmp(symname, "end")) { 273 db_printf("%#zx: srr1=%#zx\n", lr, tf->srr1); 274 } else { 275 db_printf("%s+%#zx: srr1=%#zx\n", symname, diff, 276 tf->srr1); 277 } 278 db_printf("%-10s r1=%#zx cr=%#x xer=%#x ctr=%#zx", 279 "", tf->fixreg[1], (uint32_t)tf->cr, 280 (uint32_t)tf->xer, tf->ctr); 281 if (tf->exc == EXC_DSI) 282 db_printf(" sr=%#x", 283 (uint32_t)tf->cpu.aim.dsisr); 284 db_printf("\n"); 285 stackframe = (db_addr_t) tf->fixreg[1]; 286 if (kernel_only && (tf->srr1 & PSL_PR)) 287 break; 288 goto next_frame; 289 } 290 291 diff = 0; 292 symname = NULL; 293 sym = db_search_symbol(lr, DB_STGY_ANY, &diff); 294 db_symbol_values(sym, &symname, 0); 295 if (symname == NULL || !strcmp(symname, "end")) 296 db_printf("at %zx", lr); 297 else 298 db_printf("at %s+%#zx", symname, diff); 299 if (full) 300 /* Print all the args stored in that stackframe. */ 301 db_printf("(%zx, %zx, %zx, %zx, %zx, %zx, %zx, %zx)", 302 args[0], args[1], args[2], args[3], 303 args[4], args[5], args[6], args[7]); 304 db_printf("\n"); 305 } 306 307 return (0); 308} 309 310void 311db_trace_self(void) 312{ 313 db_addr_t addr; 314 315 addr = (db_addr_t)__builtin_frame_address(1); 316 db_backtrace(curthread, addr, -1); 317} 318 319int 320db_trace_thread(struct thread *td, int count) 321{ 322 struct pcb *ctx; 323 324 ctx = kdb_thr_ctx(td); 325 return (db_backtrace(td, (db_addr_t)ctx->pcb_sp, count)); 326} 327