199730Sbenno/* $FreeBSD$ */ 299730Sbenno/* $NetBSD: db_trace.c,v 1.20 2002/05/13 20:30:09 matt Exp $ */ 399730Sbenno/* $OpenBSD: db_trace.c,v 1.3 1997/03/21 02:10:48 niklas Exp $ */ 499730Sbenno 5139825Simp/*- 699730Sbenno * Mach Operating System 799730Sbenno * Copyright (c) 1992 Carnegie Mellon University 899730Sbenno * All Rights Reserved. 9132070Sgrehan * 1099730Sbenno * Permission to use, copy, modify and distribute this software and its 1199730Sbenno * documentation is hereby granted, provided that both the copyright 1299730Sbenno * notice and this permission notice appear in all copies of the 1399730Sbenno * software, derivative works or modified versions, and any portions 1499730Sbenno * thereof, and that both notices appear in supporting documentation. 15132070Sgrehan * 1699730Sbenno * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 1799730Sbenno * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 1899730Sbenno * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 19132070Sgrehan * 2099730Sbenno * Carnegie Mellon requests users of this software to return to 21132070Sgrehan * 2299730Sbenno * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 2399730Sbenno * School of Computer Science 2499730Sbenno * Carnegie Mellon University 2599730Sbenno * Pittsburgh PA 15213-3890 26132070Sgrehan * 27132070Sgrehan * any improvements or extensions that they make and grant Carnegie Mellon 2899730Sbenno * the rights to redistribute these changes. 2999730Sbenno */ 3099730Sbenno 3199730Sbenno#include <sys/param.h> 32104435Sgrehan#include <sys/systm.h> 33132070Sgrehan#include <sys/kdb.h> 3499730Sbenno#include <sys/proc.h> 35148666Sjeff#include <sys/stack.h> 3699730Sbenno 3799730Sbenno#include <vm/vm.h> 3899730Sbenno#include <vm/pmap.h> 3999730Sbenno#include <vm/vm_extern.h> 4099730Sbenno 4199730Sbenno#include <machine/db_machdep.h> 42138129Sdas#include <machine/pcb.h> 4399730Sbenno#include <machine/spr.h> 44174195Srwatson#include <machine/stack.h> 4599730Sbenno#include <machine/trap.h> 4699730Sbenno 4799730Sbenno#include <ddb/ddb.h> 4899730Sbenno#include <ddb/db_access.h> 4999730Sbenno#include <ddb/db_sym.h> 5099730Sbenno#include <ddb/db_variables.h> 5199730Sbenno 52132070Sgrehanstatic db_varfcn_t db_frame; 53132070Sgrehan 54132070Sgrehan#define DB_OFFSET(x) (db_expr_t *)offsetof(struct trapframe, x) 55132070Sgrehan 56209975Snwhitehorn#ifdef __powerpc64__ 57209975Snwhitehorn#define CALLOFFSET 8 /* Include TOC reload slot */ 58209975Snwhitehorn#else 59209975Snwhitehorn#define CALLOFFSET 4 60209975Snwhitehorn#endif 61209975Snwhitehorn 6299730Sbennostruct db_variable db_regs[] = { 63132070Sgrehan { "r0", DB_OFFSET(fixreg[0]), db_frame }, 64132070Sgrehan { "r1", DB_OFFSET(fixreg[1]), db_frame }, 65132070Sgrehan { "r2", DB_OFFSET(fixreg[2]), db_frame }, 66132070Sgrehan { "r3", DB_OFFSET(fixreg[3]), db_frame }, 67132070Sgrehan { "r4", DB_OFFSET(fixreg[4]), db_frame }, 68132070Sgrehan { "r5", DB_OFFSET(fixreg[5]), db_frame }, 69132070Sgrehan { "r6", DB_OFFSET(fixreg[6]), db_frame }, 70132070Sgrehan { "r7", DB_OFFSET(fixreg[7]), db_frame }, 71132070Sgrehan { "r8", DB_OFFSET(fixreg[8]), db_frame }, 72132070Sgrehan { "r9", DB_OFFSET(fixreg[9]), db_frame }, 73132070Sgrehan { "r10", DB_OFFSET(fixreg[10]), db_frame }, 74132070Sgrehan { "r11", DB_OFFSET(fixreg[11]), db_frame }, 75132070Sgrehan { "r12", DB_OFFSET(fixreg[12]), db_frame }, 76132070Sgrehan { "r13", DB_OFFSET(fixreg[13]), db_frame }, 77132070Sgrehan { "r14", DB_OFFSET(fixreg[14]), db_frame }, 78132070Sgrehan { "r15", DB_OFFSET(fixreg[15]), db_frame }, 79132070Sgrehan { "r16", DB_OFFSET(fixreg[16]), db_frame }, 80132070Sgrehan { "r17", DB_OFFSET(fixreg[17]), db_frame }, 81132070Sgrehan { "r18", DB_OFFSET(fixreg[18]), db_frame }, 82132070Sgrehan { "r19", DB_OFFSET(fixreg[19]), db_frame }, 83132070Sgrehan { "r20", DB_OFFSET(fixreg[20]), db_frame }, 84132070Sgrehan { "r21", DB_OFFSET(fixreg[21]), db_frame }, 85132070Sgrehan { "r22", DB_OFFSET(fixreg[22]), db_frame }, 86132070Sgrehan { "r23", DB_OFFSET(fixreg[23]), db_frame }, 87132070Sgrehan { "r24", DB_OFFSET(fixreg[24]), db_frame }, 88132070Sgrehan { "r25", DB_OFFSET(fixreg[25]), db_frame }, 89132070Sgrehan { "r26", DB_OFFSET(fixreg[26]), db_frame }, 90132070Sgrehan { "r27", DB_OFFSET(fixreg[27]), db_frame }, 91132070Sgrehan { "r28", DB_OFFSET(fixreg[28]), db_frame }, 92132070Sgrehan { "r29", DB_OFFSET(fixreg[29]), db_frame }, 93132070Sgrehan { "r30", DB_OFFSET(fixreg[30]), db_frame }, 94132070Sgrehan { "r31", DB_OFFSET(fixreg[31]), db_frame }, 95132070Sgrehan { "srr0", DB_OFFSET(srr0), db_frame }, 96132070Sgrehan { "srr1", DB_OFFSET(srr1), db_frame }, 97132070Sgrehan { "lr", DB_OFFSET(lr), db_frame }, 98132070Sgrehan { "ctr", DB_OFFSET(ctr), db_frame }, 99132070Sgrehan { "cr", DB_OFFSET(cr), db_frame }, 100132070Sgrehan { "xer", DB_OFFSET(xer), db_frame }, 101176742Sraj#ifdef AIM 102176742Sraj { "dar", DB_OFFSET(cpu.aim.dar), db_frame }, 103176742Sraj { "dsisr", DB_OFFSET(cpu.aim.dsisr), db_frame }, 104176742Sraj#endif 105236141Sraj#if defined(BOOKE) 106176742Sraj { "dear", DB_OFFSET(cpu.booke.dear), db_frame }, 107176742Sraj { "esr", DB_OFFSET(cpu.booke.esr), db_frame }, 108176742Sraj#endif 10999730Sbenno}; 11099730Sbennostruct db_variable *db_eregs = db_regs + sizeof (db_regs)/sizeof (db_regs[0]); 11199730Sbenno 11299730Sbenno/* 113132070Sgrehan * register variable handling 114132070Sgrehan */ 115132070Sgrehanstatic int 116132070Sgrehandb_frame(struct db_variable *vp, db_expr_t *valuep, int op) 117132070Sgrehan{ 118209975Snwhitehorn register_t *reg; 119132070Sgrehan 120132070Sgrehan if (kdb_frame == NULL) 121132070Sgrehan return (0); 122209975Snwhitehorn reg = (register_t*)((uintptr_t)kdb_frame + (uintptr_t)vp->valuep); 123132070Sgrehan if (op == DB_VAR_GET) 124132070Sgrehan *valuep = *reg; 125132070Sgrehan else 126132070Sgrehan *reg = *valuep; 127132070Sgrehan return (1); 128132070Sgrehan} 129132070Sgrehan 130132070Sgrehan 131132070Sgrehan/* 13299730Sbenno * Frame tracing. 13399730Sbenno */ 134132070Sgrehanstatic int 135132070Sgrehandb_backtrace(struct thread *td, db_addr_t fp, int count) 13699730Sbenno{ 137132070Sgrehan db_addr_t stackframe, lr, *args; 13899730Sbenno db_expr_t diff; 139104435Sgrehan c_db_sym_t sym; 140104435Sgrehan const char *symname; 14199730Sbenno boolean_t kernel_only = TRUE; 14299730Sbenno boolean_t full = FALSE; 14399730Sbenno 144132070Sgrehan#if 0 14599730Sbenno { 14699730Sbenno register char *cp = modif; 14799730Sbenno register char c; 14899730Sbenno 14999730Sbenno while ((c = *cp++) != 0) { 15099730Sbenno if (c == 't') 15199730Sbenno trace_thread = TRUE; 15299730Sbenno if (c == 'u') 15399730Sbenno kernel_only = FALSE; 15499730Sbenno if (c == 'f') 15599730Sbenno full = TRUE; 15699730Sbenno } 15799730Sbenno } 158132070Sgrehan#endif 15999730Sbenno 160132070Sgrehan stackframe = fp; 16199730Sbenno 162160312Sjhb while (!db_pager_quit) { 163132070Sgrehan if (stackframe < PAGE_SIZE) 16499730Sbenno break; 165132070Sgrehan 166132070Sgrehan /* 167132070Sgrehan * Locate the next frame by grabbing the backchain ptr 168132070Sgrehan * from frame[0] 169132070Sgrehan */ 170132070Sgrehan stackframe = *(db_addr_t *)stackframe; 171132070Sgrehan 172132070Sgrehan next_frame: 173209975Snwhitehorn #ifdef __powerpc64__ 174209975Snwhitehorn /* The saved arg values start at frame[6] */ 175209975Snwhitehorn args = (db_addr_t *)(stackframe + 48); 176209975Snwhitehorn #else 177132070Sgrehan /* The saved arg values start at frame[2] */ 178132070Sgrehan args = (db_addr_t *)(stackframe + 8); 179209975Snwhitehorn #endif 180132070Sgrehan 181132070Sgrehan if (stackframe < PAGE_SIZE) 18299730Sbenno break; 183132070Sgrehan 18499730Sbenno if (count-- == 0) 18599730Sbenno break; 18699730Sbenno 187132070Sgrehan /* 188132070Sgrehan * Extract link register from frame and subtract 189132070Sgrehan * 4 to convert into calling address (as opposed to 190132070Sgrehan * return address) 191132070Sgrehan */ 192209975Snwhitehorn #ifdef __powerpc64__ 193209975Snwhitehorn lr = *(db_addr_t *)(stackframe + 16) - 4; 194209975Snwhitehorn #else 195132070Sgrehan lr = *(db_addr_t *)(stackframe + 4) - 4; 196209975Snwhitehorn #endif 19799730Sbenno if ((lr & 3) || (lr < 0x100)) { 198209975Snwhitehorn db_printf("saved LR(0x%zx) is invalid.", lr); 19999730Sbenno break; 20099730Sbenno } 20199730Sbenno 202209975Snwhitehorn #ifdef __powerpc64__ 203223470Sandreast db_printf("0x%016lx: ", stackframe); 204209975Snwhitehorn #else 205132070Sgrehan db_printf("0x%08x: ", stackframe); 206209975Snwhitehorn #endif 207132070Sgrehan 208132070Sgrehan /* 209153685Sgrehan * The trap code labels the return addresses from the 210153685Sgrehan * call to C code as 'trapexit' and 'asttrapexit. Use this 211153685Sgrehan * to determine if the callframe has to traverse a saved 212153685Sgrehan * trap context 213132070Sgrehan */ 214209975Snwhitehorn if ((lr + CALLOFFSET == (db_addr_t) &trapexit) || 215209975Snwhitehorn (lr + CALLOFFSET == (db_addr_t) &asttrapexit)) { 21699730Sbenno const char *trapstr; 217209975Snwhitehorn struct trapframe *tf = (struct trapframe *)(args); 218132070Sgrehan db_printf("%s ", tf->srr1 & PSL_PR ? "user" : "kernel"); 21999730Sbenno switch (tf->exc) { 22099730Sbenno case EXC_DSI: 221176742Sraj /* XXX take advantage of the union. */ 222209975Snwhitehorn db_printf("DSI %s trap @ %#zx by ", 223176742Sraj (tf->cpu.aim.dsisr & DSISR_STORE) ? "write" 224176742Sraj : "read", tf->cpu.aim.dar); 22599730Sbenno goto print_trap; 226132070Sgrehan case EXC_ALI: 227176742Sraj /* XXX take advantage of the union. */ 228209975Snwhitehorn db_printf("ALI trap @ %#zx (xSR %#x) ", 229209975Snwhitehorn tf->cpu.aim.dar, 230209975Snwhitehorn (uint32_t)tf->cpu.aim.dsisr); 231132070Sgrehan goto print_trap; 232209975Snwhitehorn#ifdef __powerpc64__ 233209975Snwhitehorn case EXC_DSE: 234209975Snwhitehorn db_printf("DSE trap @ %#zx by ", 235209975Snwhitehorn tf->cpu.aim.dar); 236209975Snwhitehorn goto print_trap; 237209975Snwhitehorn case EXC_ISE: 238209975Snwhitehorn db_printf("ISE trap @ %#zx by ", tf->srr0); 239209975Snwhitehorn goto print_trap; 240209975Snwhitehorn#endif 24199730Sbenno case EXC_ISI: trapstr = "ISI"; break; 24299730Sbenno case EXC_PGM: trapstr = "PGM"; break; 24399730Sbenno case EXC_SC: trapstr = "SC"; break; 24499730Sbenno case EXC_EXI: trapstr = "EXI"; break; 24599730Sbenno case EXC_MCHK: trapstr = "MCHK"; break; 246236141Sraj#if !defined(BOOKE) 24799730Sbenno case EXC_VEC: trapstr = "VEC"; break; 24899730Sbenno case EXC_FPA: trapstr = "FPA"; break; 24999730Sbenno case EXC_BPT: trapstr = "BPT"; break; 25099730Sbenno case EXC_TRC: trapstr = "TRC"; break; 25199730Sbenno case EXC_RUNMODETRC: trapstr = "RUNMODETRC"; break; 25299730Sbenno case EXC_SMI: trapstr = "SMI"; break; 25399730Sbenno case EXC_RST: trapstr = "RST"; break; 254176742Sraj#endif 255176742Sraj case EXC_FPU: trapstr = "FPU"; break; 256176742Sraj case EXC_DECR: trapstr = "DECR"; break; 257176742Sraj case EXC_PERF: trapstr = "PERF"; break; 25899730Sbenno default: trapstr = NULL; break; 25999730Sbenno } 26099730Sbenno if (trapstr != NULL) { 261132070Sgrehan db_printf("%s trap by ", trapstr); 26299730Sbenno } else { 263209975Snwhitehorn db_printf("trap %#zx by ", tf->exc); 26499730Sbenno } 265132070Sgrehan 266132070Sgrehan print_trap: 26799730Sbenno lr = (db_addr_t) tf->srr0; 26899730Sbenno diff = 0; 26999730Sbenno symname = NULL; 270132070Sgrehan sym = db_search_symbol(lr, DB_STGY_ANY, &diff); 27199730Sbenno db_symbol_values(sym, &symname, 0); 27299730Sbenno if (symname == NULL || !strcmp(symname, "end")) { 273209975Snwhitehorn db_printf("%#zx: srr1=%#zx\n", lr, tf->srr1); 27499730Sbenno } else { 275209975Snwhitehorn db_printf("%s+%#zx: srr1=%#zx\n", symname, diff, 27699730Sbenno tf->srr1); 27799730Sbenno } 278209975Snwhitehorn db_printf("%-10s r1=%#zx cr=%#x xer=%#x ctr=%#zx", 279209975Snwhitehorn "", tf->fixreg[1], (uint32_t)tf->cr, 280209975Snwhitehorn (uint32_t)tf->xer, tf->ctr); 28199730Sbenno if (tf->exc == EXC_DSI) 282209975Snwhitehorn db_printf(" sr=%#x", 283209975Snwhitehorn (uint32_t)tf->cpu.aim.dsisr); 284132070Sgrehan db_printf("\n"); 285132070Sgrehan stackframe = (db_addr_t) tf->fixreg[1]; 28699730Sbenno if (kernel_only && (tf->srr1 & PSL_PR)) 28799730Sbenno break; 28899730Sbenno goto next_frame; 28999730Sbenno } 29099730Sbenno 29199730Sbenno diff = 0; 29299730Sbenno symname = NULL; 293132070Sgrehan sym = db_search_symbol(lr, DB_STGY_ANY, &diff); 29499730Sbenno db_symbol_values(sym, &symname, 0); 29599730Sbenno if (symname == NULL || !strcmp(symname, "end")) 296209975Snwhitehorn db_printf("at %zx", lr); 29799730Sbenno else 298209975Snwhitehorn db_printf("at %s+%#zx", symname, diff); 29999730Sbenno if (full) 30099730Sbenno /* Print all the args stored in that stackframe. */ 301209975Snwhitehorn db_printf("(%zx, %zx, %zx, %zx, %zx, %zx, %zx, %zx)", 30299730Sbenno args[0], args[1], args[2], args[3], 30399730Sbenno args[4], args[5], args[6], args[7]); 304132070Sgrehan db_printf("\n"); 30599730Sbenno } 306132070Sgrehan 307132070Sgrehan return (0); 30899730Sbenno} 30999730Sbenno 31099730Sbennovoid 311132070Sgrehandb_trace_self(void) 312103646Sjhb{ 313132070Sgrehan db_addr_t addr; 314132070Sgrehan 315132070Sgrehan addr = (db_addr_t)__builtin_frame_address(1); 316132070Sgrehan db_backtrace(curthread, addr, -1); 317103646Sjhb} 318132070Sgrehan 319132070Sgrehanint 320132070Sgrehandb_trace_thread(struct thread *td, int count) 321132070Sgrehan{ 322132070Sgrehan struct pcb *ctx; 323132070Sgrehan 324132070Sgrehan ctx = kdb_thr_ctx(td); 325132070Sgrehan return (db_backtrace(td, (db_addr_t)ctx->pcb_sp, count)); 326132070Sgrehan} 327