db_trace.c revision 103646
199730Sbenno/* $FreeBSD: head/sys/powerpc/powerpc/db_trace.c 103646 2002-09-19 18:46:29Z jhb $ */ 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 599730Sbenno/* 699730Sbenno * Mach Operating System 799730Sbenno * Copyright (c) 1992 Carnegie Mellon University 899730Sbenno * All Rights Reserved. 999730Sbenno * 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. 1599730Sbenno * 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. 1999730Sbenno * 2099730Sbenno * Carnegie Mellon requests users of this software to return to 2199730Sbenno * 2299730Sbenno * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 2399730Sbenno * School of Computer Science 2499730Sbenno * Carnegie Mellon University 2599730Sbenno * Pittsburgh PA 15213-3890 2699730Sbenno * 2799730Sbenno * 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> 3299730Sbenno#include <sys/proc.h> 3399730Sbenno#include <sys/user.h> 3499730Sbenno 3599730Sbenno#include <vm/vm.h> 3699730Sbenno#include <vm/pmap.h> 3799730Sbenno#include <vm/vm_extern.h> 3899730Sbenno 3999730Sbenno#include <machine/db_machdep.h> 4099730Sbenno#include <machine/spr.h> 4199730Sbenno#include <machine/trap.h> 4299730Sbenno 4399730Sbenno#include <ddb/ddb.h> 4499730Sbenno#include <ddb/db_access.h> 4599730Sbenno#include <ddb/db_sym.h> 4699730Sbenno#include <ddb/db_variables.h> 4799730Sbenno 4899730Sbennostruct db_variable db_regs[] = { 4999730Sbenno { "r0", (long *)&ddb_regs.r[0], FCN_NULL }, 5099730Sbenno { "r1", (long *)&ddb_regs.r[1], FCN_NULL }, 5199730Sbenno { "r2", (long *)&ddb_regs.r[2], FCN_NULL }, 5299730Sbenno { "r3", (long *)&ddb_regs.r[3], FCN_NULL }, 5399730Sbenno { "r4", (long *)&ddb_regs.r[4], FCN_NULL }, 5499730Sbenno { "r5", (long *)&ddb_regs.r[5], FCN_NULL }, 5599730Sbenno { "r6", (long *)&ddb_regs.r[6], FCN_NULL }, 5699730Sbenno { "r7", (long *)&ddb_regs.r[7], FCN_NULL }, 5799730Sbenno { "r8", (long *)&ddb_regs.r[8], FCN_NULL }, 5899730Sbenno { "r9", (long *)&ddb_regs.r[9], FCN_NULL }, 5999730Sbenno { "r10", (long *)&ddb_regs.r[10], FCN_NULL }, 6099730Sbenno { "r11", (long *)&ddb_regs.r[11], FCN_NULL }, 6199730Sbenno { "r12", (long *)&ddb_regs.r[12], FCN_NULL }, 6299730Sbenno { "r13", (long *)&ddb_regs.r[13], FCN_NULL }, 6399730Sbenno { "r14", (long *)&ddb_regs.r[14], FCN_NULL }, 6499730Sbenno { "r15", (long *)&ddb_regs.r[15], FCN_NULL }, 6599730Sbenno { "r16", (long *)&ddb_regs.r[16], FCN_NULL }, 6699730Sbenno { "r17", (long *)&ddb_regs.r[17], FCN_NULL }, 6799730Sbenno { "r18", (long *)&ddb_regs.r[18], FCN_NULL }, 6899730Sbenno { "r19", (long *)&ddb_regs.r[19], FCN_NULL }, 6999730Sbenno { "r20", (long *)&ddb_regs.r[20], FCN_NULL }, 7099730Sbenno { "r21", (long *)&ddb_regs.r[21], FCN_NULL }, 7199730Sbenno { "r22", (long *)&ddb_regs.r[22], FCN_NULL }, 7299730Sbenno { "r23", (long *)&ddb_regs.r[23], FCN_NULL }, 7399730Sbenno { "r24", (long *)&ddb_regs.r[24], FCN_NULL }, 7499730Sbenno { "r25", (long *)&ddb_regs.r[25], FCN_NULL }, 7599730Sbenno { "r26", (long *)&ddb_regs.r[26], FCN_NULL }, 7699730Sbenno { "r27", (long *)&ddb_regs.r[27], FCN_NULL }, 7799730Sbenno { "r28", (long *)&ddb_regs.r[28], FCN_NULL }, 7899730Sbenno { "r29", (long *)&ddb_regs.r[29], FCN_NULL }, 7999730Sbenno { "r30", (long *)&ddb_regs.r[30], FCN_NULL }, 8099730Sbenno { "r31", (long *)&ddb_regs.r[31], FCN_NULL }, 8199730Sbenno { "iar", (long *)&ddb_regs.iar, FCN_NULL }, 8299730Sbenno { "msr", (long *)&ddb_regs.msr, FCN_NULL }, 8399730Sbenno { "lr", (long *)&ddb_regs.lr, FCN_NULL }, 8499730Sbenno { "ctr", (long *)&ddb_regs.ctr, FCN_NULL }, 8599730Sbenno { "cr", (long *)&ddb_regs.cr, FCN_NULL }, 8699730Sbenno { "xer", (long *)&ddb_regs.xer, FCN_NULL }, 8799730Sbenno#ifdef PPC_IBM4XX 8899730Sbenno { "dear", (long *)&ddb_regs.dear, FCN_NULL }, 8999730Sbenno { "esr", (long *)&ddb_regs.esr, FCN_NULL }, 9099730Sbenno { "pid", (long *)&ddb_regs.pid, FCN_NULL }, 9199730Sbenno#endif 9299730Sbenno}; 9399730Sbennostruct db_variable *db_eregs = db_regs + sizeof (db_regs)/sizeof (db_regs[0]); 9499730Sbenno 9599730Sbennoextern int trapexit[]; 9699730Sbennoextern int end[]; 9799730Sbenno 9899730Sbenno/* 9999730Sbenno * Frame tracing. 10099730Sbenno */ 10199730Sbennovoid 10299730Sbennodb_stack_trace_print(addr, have_addr, count, modif, pr) 10399730Sbenno db_expr_t addr; 10499730Sbenno int have_addr; 10599730Sbenno db_expr_t count; 10699730Sbenno char *modif; 10799730Sbenno void (*pr) __P((const char *, ...)); 10899730Sbenno{ 10999730Sbenno db_addr_t frame, lr, caller, *args; 11099730Sbenno db_addr_t fakeframe[2]; 11199730Sbenno db_expr_t diff; 11299730Sbenno db_sym_t sym; 11399730Sbenno char *symname; 11499730Sbenno boolean_t kernel_only = TRUE; 11599730Sbenno boolean_t trace_thread = FALSE; 11699730Sbenno boolean_t full = FALSE; 11799730Sbenno 11899730Sbenno { 11999730Sbenno register char *cp = modif; 12099730Sbenno register char c; 12199730Sbenno 12299730Sbenno while ((c = *cp++) != 0) { 12399730Sbenno if (c == 't') 12499730Sbenno trace_thread = TRUE; 12599730Sbenno if (c == 'u') 12699730Sbenno kernel_only = FALSE; 12799730Sbenno if (c == 'f') 12899730Sbenno full = TRUE; 12999730Sbenno } 13099730Sbenno } 13199730Sbenno 13299730Sbenno if (have_addr) { 13399730Sbenno#if 0 13499730Sbenno if (trace_thread) { 13599730Sbenno struct proc *p; 13699730Sbenno struct user *u; 13799730Sbenno 13899730Sbenno (*pr)("trace: pid %d ", (int)addr); 13999730Sbenno p = pfind(addr); 14099730Sbenno if (p == NULL) { 14199730Sbenno (*pr)("not found\n"); 14299730Sbenno return; 14399730Sbenno } 14499730Sbenno if (!(p->p_flag&P_INMEM)) { 14599730Sbenno (*pr)("swapped out\n"); 14699730Sbenno return; 14799730Sbenno } 14899730Sbenno u = p->p_addr; 14999730Sbenno frame = (db_addr_t)u->u_pcb.pcb_sp; 15099730Sbenno (*pr)("at %p\n", frame); 15199730Sbenno } else 15299730Sbenno#endif 15399730Sbenno frame = (db_addr_t)addr; 15499730Sbenno } else { 15599730Sbenno frame = (db_addr_t)ddb_regs.r[1]; 15699730Sbenno } 15799730Sbenno for (;;) { 15899730Sbenno if (frame < PAGE_SIZE) 15999730Sbenno break; 16099730Sbenno#ifdef PPC_MPC6XX 16199730Sbenno if (kernel_only && 16299730Sbenno ((frame > (db_addr_t) end && 16399730Sbenno frame < VM_MIN_KERNEL_ADDRESS) || 16499730Sbenno frame >= VM_MAX_KERNEL_ADDRESS)) 16599730Sbenno break; 16699730Sbenno#endif 16799730Sbenno frame = *(db_addr_t *)frame; 16899730Sbenno next_frame: 16999730Sbenno args = (db_addr_t *)(frame + 8); 17099730Sbenno if (frame < PAGE_SIZE) 17199730Sbenno break; 17299730Sbenno#ifdef PPC_MPC6XX 17399730Sbenno if (kernel_only && 17499730Sbenno ((frame > (db_addr_t) end && 17599730Sbenno frame < VM_MIN_KERNEL_ADDRESS) || 17699730Sbenno frame >= VM_MAX_KERNEL_ADDRESS)) 17799730Sbenno break; 17899730Sbenno#endif 17999730Sbenno if (count-- == 0) 18099730Sbenno break; 18199730Sbenno 18299730Sbenno lr = *(db_addr_t *)(frame + 4) - 4; 18399730Sbenno if ((lr & 3) || (lr < 0x100)) { 18499730Sbenno (*pr)("saved LR(0x%x) is invalid.", lr); 18599730Sbenno break; 18699730Sbenno } 18799730Sbenno if ((caller = (db_addr_t)vtophys(lr)) == 0) 18899730Sbenno caller = lr; 18999730Sbenno 19099730Sbenno if (frame != (db_addr_t) fakeframe) { 19199730Sbenno (*pr)("0x%08lx: ", frame); 19299730Sbenno } else { 19399730Sbenno (*pr)(" <?> : "); 19499730Sbenno } 19599730Sbenno if (caller + 4 == (db_addr_t) &trapexit) { 19699730Sbenno const char *trapstr; 19799730Sbenno struct trapframe *tf = (struct trapframe *) (frame+8); 19899730Sbenno (*pr)("%s ", tf->srr1 & PSL_PR ? "user" : "kernel"); 19999730Sbenno switch (tf->exc) { 20099730Sbenno case EXC_DSI: 20199730Sbenno#ifdef PPC_MPC6XX 20299730Sbenno (*pr)("DSI %s trap @ %#x by ", 20399730Sbenno tf->dsisr & DSISR_STORE ? "write" : "read", 20499730Sbenno tf->dar); 20599730Sbenno#endif 20699730Sbenno#ifdef PPC_IBM4XX 20799730Sbenno (*pr)("DSI %s trap @ %#x by ", 20899730Sbenno tf->esr & ESR_DST ? "write" : "read", 20999730Sbenno tf->dear); 21099730Sbenno#endif 21199730Sbenno goto print_trap; 21299730Sbenno case EXC_ISI: trapstr = "ISI"; break; 21399730Sbenno case EXC_PGM: trapstr = "PGM"; break; 21499730Sbenno case EXC_SC: trapstr = "SC"; break; 21599730Sbenno case EXC_EXI: trapstr = "EXI"; break; 21699730Sbenno case EXC_MCHK: trapstr = "MCHK"; break; 21799730Sbenno case EXC_VEC: trapstr = "VEC"; break; 21899730Sbenno case EXC_FPU: trapstr = "FPU"; break; 21999730Sbenno case EXC_FPA: trapstr = "FPA"; break; 22099730Sbenno case EXC_DECR: trapstr = "DECR"; break; 22199730Sbenno case EXC_ALI: trapstr = "ALI"; break; 22299730Sbenno case EXC_BPT: trapstr = "BPT"; break; 22399730Sbenno case EXC_TRC: trapstr = "TRC"; break; 22499730Sbenno case EXC_RUNMODETRC: trapstr = "RUNMODETRC"; break; 22599730Sbenno case EXC_PERF: trapstr = "PERF"; break; 22699730Sbenno case EXC_SMI: trapstr = "SMI"; break; 22799730Sbenno case EXC_RST: trapstr = "RST"; break; 22899730Sbenno default: trapstr = NULL; break; 22999730Sbenno } 23099730Sbenno if (trapstr != NULL) { 23199730Sbenno (*pr)("%s trap by ", trapstr); 23299730Sbenno } else { 23399730Sbenno (*pr)("trap %#x by ", tf->exc); 23499730Sbenno } 23599730Sbenno print_trap: 23699730Sbenno lr = (db_addr_t) tf->srr0; 23799730Sbenno if ((caller = (db_addr_t)vtophys(lr)) == 0) 23899730Sbenno caller = lr; 23999730Sbenno diff = 0; 24099730Sbenno symname = NULL; 24199730Sbenno sym = db_search_symbol(caller, DB_STGY_ANY, &diff); 24299730Sbenno db_symbol_values(sym, &symname, 0); 24399730Sbenno if (symname == NULL || !strcmp(symname, "end")) { 24499730Sbenno (*pr)("%p: srr1=%#x\n", caller, tf->srr1); 24599730Sbenno } else { 24699730Sbenno (*pr)("%s+%x: srr1=%#x\n", symname, diff, 24799730Sbenno tf->srr1); 24899730Sbenno } 24999730Sbenno (*pr)("%-10s r1=%#x cr=%#x xer=%#x ctr=%#x", 25099730Sbenno "", tf->fixreg[1], tf->cr, tf->xer, tf->ctr); 25199730Sbenno#ifdef PPC_MPC6XX 25299730Sbenno if (tf->exc == EXC_DSI) 25399730Sbenno (*pr)(" dsisr=%#x", tf->dsisr); 25499730Sbenno#endif 25599730Sbenno#ifdef PPC_IBM4XX 25699730Sbenno if (tf->exc == EXC_DSI) 25799730Sbenno (*pr)(" dear=%#x", tf->dear); 25899730Sbenno (*pr)(" esr=%#x pid=%#x", tf->esr, tf->pid); 25999730Sbenno#endif 26099730Sbenno (*pr)("\n"); 26199730Sbenno fakeframe[0] = (db_addr_t) tf->fixreg[1]; 26299730Sbenno fakeframe[1] = (db_addr_t) tf->lr; 26399730Sbenno frame = (db_addr_t) fakeframe; 26499730Sbenno if (kernel_only && (tf->srr1 & PSL_PR)) 26599730Sbenno break; 26699730Sbenno goto next_frame; 26799730Sbenno } 26899730Sbenno 26999730Sbenno diff = 0; 27099730Sbenno symname = NULL; 27199730Sbenno sym = db_search_symbol(caller, DB_STGY_ANY, &diff); 27299730Sbenno db_symbol_values(sym, &symname, 0); 27399730Sbenno if (symname == NULL || !strcmp(symname, "end")) 27499730Sbenno (*pr)("at %p", caller); 27599730Sbenno else 27699730Sbenno (*pr)("at %s+%#x", symname, diff); 27799730Sbenno if (full) 27899730Sbenno /* Print all the args stored in that stackframe. */ 27999730Sbenno (*pr)("(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)", 28099730Sbenno args[0], args[1], args[2], args[3], 28199730Sbenno args[4], args[5], args[6], args[7]); 28299730Sbenno (*pr)("\n"); 28399730Sbenno } 28499730Sbenno} 28599730Sbenno 28699730Sbennovoid 28799730Sbennodb_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, 28899730Sbenno char *modif) 28999730Sbenno{ 29099730Sbenno 29199730Sbenno db_stack_trace_print(addr, have_addr, count, modif, db_printf); 29299730Sbenno} 29399730Sbenno 294103646Sjhbvoid 295103646Sjhbdb_print_backtrace(void) 296103646Sjhb{ 297103646Sjhb} 298