diff options
author | grehan <grehan@FreeBSD.org> | 2004-07-12 22:21:34 +0000 |
---|---|---|
committer | grehan <grehan@FreeBSD.org> | 2004-07-12 22:21:34 +0000 |
commit | 7ab8fbe2ac96491a915e26dceb6d3323f9dc67f8 (patch) | |
tree | fd30990dbab9e9b0c83177eee8ff5047b4f379fc /sys/powerpc | |
parent | 2312a73897f4672fc0a8e2f1ea6fbdefdc5ed7ee (diff) | |
download | FreeBSD-src-7ab8fbe2ac96491a915e26dceb6d3323f9dc67f8.zip FreeBSD-src-7ab8fbe2ac96491a915e26dceb6d3323f9dc67f8.tar.gz |
Bring into line with KDB. Bring in NetBSD updates for backtrace routine,
although it really needs a decent re-work.
Diffstat (limited to 'sys/powerpc')
-rw-r--r-- | sys/powerpc/powerpc/db_trace.c | 304 |
1 files changed, 155 insertions, 149 deletions
diff --git a/sys/powerpc/powerpc/db_trace.c b/sys/powerpc/powerpc/db_trace.c index 014990d..a4291d9 100644 --- a/sys/powerpc/powerpc/db_trace.c +++ b/sys/powerpc/powerpc/db_trace.c @@ -2,34 +2,35 @@ /* $NetBSD: db_trace.c,v 1.20 2002/05/13 20:30:09 matt Exp $ */ /* $OpenBSD: db_trace.c,v 1.3 1997/03/21 02:10:48 niklas Exp $ */ -/* +/* * Mach Operating System * Copyright (c) 1992 Carnegie Mellon University * All Rights Reserved. - * + * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. - * + * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * + * * Carnegie Mellon requests users of this software to return to - * + * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 - * - * any improvements or extensions that they make and grant Carnegie Mellon + * + * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ #include <sys/param.h> #include <sys/systm.h> +#include <sys/kdb.h> #include <sys/proc.h> #include <sys/user.h> @@ -46,50 +47,51 @@ #include <ddb/db_sym.h> #include <ddb/db_variables.h> +static db_varfcn_t db_frame; + +#define DB_OFFSET(x) (db_expr_t *)offsetof(struct trapframe, x) + struct db_variable db_regs[] = { - { "r0", &ddb_regs.r[0], FCN_NULL }, - { "r1", &ddb_regs.r[1], FCN_NULL }, - { "r2", &ddb_regs.r[2], FCN_NULL }, - { "r3", &ddb_regs.r[3], FCN_NULL }, - { "r4", &ddb_regs.r[4], FCN_NULL }, - { "r5", &ddb_regs.r[5], FCN_NULL }, - { "r6", &ddb_regs.r[6], FCN_NULL }, - { "r7", &ddb_regs.r[7], FCN_NULL }, - { "r8", &ddb_regs.r[8], FCN_NULL }, - { "r9", &ddb_regs.r[9], FCN_NULL }, - { "r10", &ddb_regs.r[10], FCN_NULL }, - { "r11", &ddb_regs.r[11], FCN_NULL }, - { "r12", &ddb_regs.r[12], FCN_NULL }, - { "r13", &ddb_regs.r[13], FCN_NULL }, - { "r14", &ddb_regs.r[14], FCN_NULL }, - { "r15", &ddb_regs.r[15], FCN_NULL }, - { "r16", &ddb_regs.r[16], FCN_NULL }, - { "r17", &ddb_regs.r[17], FCN_NULL }, - { "r18", &ddb_regs.r[18], FCN_NULL }, - { "r19", &ddb_regs.r[19], FCN_NULL }, - { "r20", &ddb_regs.r[20], FCN_NULL }, - { "r21", &ddb_regs.r[21], FCN_NULL }, - { "r22", &ddb_regs.r[22], FCN_NULL }, - { "r23", &ddb_regs.r[23], FCN_NULL }, - { "r24", &ddb_regs.r[24], FCN_NULL }, - { "r25", &ddb_regs.r[25], FCN_NULL }, - { "r26", &ddb_regs.r[26], FCN_NULL }, - { "r27", &ddb_regs.r[27], FCN_NULL }, - { "r28", &ddb_regs.r[28], FCN_NULL }, - { "r29", &ddb_regs.r[29], FCN_NULL }, - { "r30", &ddb_regs.r[30], FCN_NULL }, - { "r31", &ddb_regs.r[31], FCN_NULL }, - { "iar", &ddb_regs.iar, FCN_NULL }, - { "msr", &ddb_regs.msr, FCN_NULL }, - { "lr", &ddb_regs.lr, FCN_NULL }, - { "ctr", &ddb_regs.ctr, FCN_NULL }, - { "cr", &ddb_regs.cr, FCN_NULL }, - { "xer", &ddb_regs.xer, FCN_NULL }, -#ifdef PPC_IBM4XX - { "dear", &ddb_regs.dear, FCN_NULL }, - { "esr", &ddb_regs.esr, FCN_NULL }, - { "pid", &ddb_regs.pid, FCN_NULL }, -#endif + { "r0", DB_OFFSET(fixreg[0]), db_frame }, + { "r1", DB_OFFSET(fixreg[1]), db_frame }, + { "r2", DB_OFFSET(fixreg[2]), db_frame }, + { "r3", DB_OFFSET(fixreg[3]), db_frame }, + { "r4", DB_OFFSET(fixreg[4]), db_frame }, + { "r5", DB_OFFSET(fixreg[5]), db_frame }, + { "r6", DB_OFFSET(fixreg[6]), db_frame }, + { "r7", DB_OFFSET(fixreg[7]), db_frame }, + { "r8", DB_OFFSET(fixreg[8]), db_frame }, + { "r9", DB_OFFSET(fixreg[9]), db_frame }, + { "r10", DB_OFFSET(fixreg[10]), db_frame }, + { "r11", DB_OFFSET(fixreg[11]), db_frame }, + { "r12", DB_OFFSET(fixreg[12]), db_frame }, + { "r13", DB_OFFSET(fixreg[13]), db_frame }, + { "r14", DB_OFFSET(fixreg[14]), db_frame }, + { "r15", DB_OFFSET(fixreg[15]), db_frame }, + { "r16", DB_OFFSET(fixreg[16]), db_frame }, + { "r17", DB_OFFSET(fixreg[17]), db_frame }, + { "r18", DB_OFFSET(fixreg[18]), db_frame }, + { "r19", DB_OFFSET(fixreg[19]), db_frame }, + { "r20", DB_OFFSET(fixreg[20]), db_frame }, + { "r21", DB_OFFSET(fixreg[21]), db_frame }, + { "r22", DB_OFFSET(fixreg[22]), db_frame }, + { "r23", DB_OFFSET(fixreg[23]), db_frame }, + { "r24", DB_OFFSET(fixreg[24]), db_frame }, + { "r25", DB_OFFSET(fixreg[25]), db_frame }, + { "r26", DB_OFFSET(fixreg[26]), db_frame }, + { "r27", DB_OFFSET(fixreg[27]), db_frame }, + { "r28", DB_OFFSET(fixreg[28]), db_frame }, + { "r29", DB_OFFSET(fixreg[29]), db_frame }, + { "r30", DB_OFFSET(fixreg[30]), db_frame }, + { "r31", DB_OFFSET(fixreg[31]), db_frame }, + { "srr0", DB_OFFSET(srr0), db_frame }, + { "srr1", DB_OFFSET(srr1), db_frame }, + { "lr", DB_OFFSET(lr), db_frame }, + { "ctr", DB_OFFSET(ctr), db_frame }, + { "cr", DB_OFFSET(cr), db_frame }, + { "xer", DB_OFFSET(xer), db_frame }, + { "dar", DB_OFFSET(dar), db_frame }, + { "dsisr", DB_OFFSET(dsisr), db_frame }, }; struct db_variable *db_eregs = db_regs + sizeof (db_regs)/sizeof (db_regs[0]); @@ -97,21 +99,38 @@ extern int trapexit[]; extern int end[]; /* + * register variable handling + */ +static int +db_frame(struct db_variable *vp, db_expr_t *valuep, int op) +{ + uint32_t *reg; + + if (kdb_frame == NULL) + return (0); + reg = (uint32_t*)((uintptr_t)kdb_frame + (uintptr_t)vp->valuep); + if (op == DB_VAR_GET) + *valuep = *reg; + else + *reg = *valuep; + return (1); +} + + +/* * Frame tracing. */ -static void -db_stack_trace_print(db_expr_t addr, int have_addr, db_expr_t count, - char *modif, void (*pr)(const char *, ...)) +static int +db_backtrace(struct thread *td, db_addr_t fp, int count) { - db_addr_t frame, lr, caller, *args; - db_addr_t fakeframe[2]; + db_addr_t stackframe, lr, *args; db_expr_t diff; c_db_sym_t sym; const char *symname; boolean_t kernel_only = TRUE; - boolean_t trace_thread = FALSE; boolean_t full = FALSE; +#if 0 { register char *cp = modif; register char c; @@ -125,86 +144,62 @@ db_stack_trace_print(db_expr_t addr, int have_addr, db_expr_t count, full = TRUE; } } - - if (have_addr) { -#if 0 - if (trace_thread) { - struct proc *p; - struct user *u; - - (*pr)("trace: pid %d ", (int)addr); - p = pfind(addr); - if (p == NULL) { - (*pr)("not found\n"); - return; - } - if (!(p->p_flag&P_INMEM)) { - (*pr)("swapped out\n"); - return; - } - u = p->p_addr; - frame = (db_addr_t)u->u_pcb.pcb_sp; - (*pr)("at %p\n", frame); - } else #endif - frame = (db_addr_t)addr; - } else { - frame = (db_addr_t)ddb_regs.r[1]; - } + + stackframe = fp; + for (;;) { - if (frame < PAGE_SIZE) - break; -#ifdef PPC_MPC6XX - if (kernel_only && - ((frame > (db_addr_t) end && - frame < VM_MIN_KERNEL_ADDRESS) || - frame >= VM_MAX_KERNEL_ADDRESS)) + if (stackframe < PAGE_SIZE) break; -#endif - frame = *(db_addr_t *)frame; - next_frame: - args = (db_addr_t *)(frame + 8); - if (frame < PAGE_SIZE) - break; -#ifdef PPC_MPC6XX - if (kernel_only && - ((frame > (db_addr_t) end && - frame < VM_MIN_KERNEL_ADDRESS) || - frame >= VM_MAX_KERNEL_ADDRESS)) + + /* + * Locate the next frame by grabbing the backchain ptr + * from frame[0] + */ + stackframe = *(db_addr_t *)stackframe; + + next_frame: + /* The saved arg values start at frame[2] */ + args = (db_addr_t *)(stackframe + 8); + + if (stackframe < PAGE_SIZE) break; -#endif + if (count-- == 0) break; - lr = *(db_addr_t *)(frame + 4) - 4; + /* + * Extract link register from frame and subtract + * 4 to convert into calling address (as opposed to + * return address) + */ + lr = *(db_addr_t *)(stackframe + 4) - 4; if ((lr & 3) || (lr < 0x100)) { - (*pr)("saved LR(0x%x) is invalid.", lr); + db_printf("saved LR(0x%x) is invalid.", lr); break; } - if ((caller = (db_addr_t)vtophys(lr)) == 0) - caller = lr; - if (frame != (db_addr_t) fakeframe) { - (*pr)("0x%08lx: ", frame); - } else { - (*pr)(" <?> : "); - } - if (caller + 4 == (db_addr_t) &trapexit) { + db_printf("0x%08x: ", stackframe); + + /* + * The trap code labels the return address from the + * call to C code as 'trapexit'. Use this to determine + * if the callframe has to traverse a saved trap context + */ + if (lr + 4 == (db_addr_t) &trapexit) { const char *trapstr; - struct trapframe *tf = (struct trapframe *) (frame+8); - (*pr)("%s ", tf->srr1 & PSL_PR ? "user" : "kernel"); + struct trapframe *tf = (struct trapframe *) + (stackframe+8); + db_printf("%s ", tf->srr1 & PSL_PR ? "user" : "kernel"); switch (tf->exc) { case EXC_DSI: -#ifdef PPC_MPC6XX - (*pr)("DSI %s trap @ %#x by ", + db_printf("DSI %s trap @ %#x by ", tf->dsisr & DSISR_STORE ? "write" : "read", tf->dar); -#endif -#ifdef PPC_IBM4XX - (*pr)("DSI %s trap @ %#x by ", - tf->esr & ESR_DST ? "write" : "read", - tf->dear); -#endif + goto print_trap; + case EXC_ALI: + db_printf("ALI trap @ %#x (DSISR %#x) ", + tf->dar, tf->dsisr); goto print_trap; case EXC_ISI: trapstr = "ISI"; break; case EXC_PGM: trapstr = "PGM"; break; @@ -215,7 +210,6 @@ db_stack_trace_print(db_expr_t addr, int have_addr, db_expr_t count, case EXC_FPU: trapstr = "FPU"; break; case EXC_FPA: trapstr = "FPA"; break; case EXC_DECR: trapstr = "DECR"; break; - case EXC_ALI: trapstr = "ALI"; break; case EXC_BPT: trapstr = "BPT"; break; case EXC_TRC: trapstr = "TRC"; break; case EXC_RUNMODETRC: trapstr = "RUNMODETRC"; break; @@ -225,39 +219,29 @@ db_stack_trace_print(db_expr_t addr, int have_addr, db_expr_t count, default: trapstr = NULL; break; } if (trapstr != NULL) { - (*pr)("%s trap by ", trapstr); + db_printf("%s trap by ", trapstr); } else { - (*pr)("trap %#x by ", tf->exc); + db_printf("trap %#x by ", tf->exc); } - print_trap: + + print_trap: lr = (db_addr_t) tf->srr0; - if ((caller = (db_addr_t)vtophys(lr)) == 0) - caller = lr; diff = 0; symname = NULL; - sym = db_search_symbol(caller, DB_STGY_ANY, &diff); + sym = db_search_symbol(lr, DB_STGY_ANY, &diff); db_symbol_values(sym, &symname, 0); if (symname == NULL || !strcmp(symname, "end")) { - (*pr)("%p: srr1=%#x\n", caller, tf->srr1); + db_printf("%#x: srr1=%#x\n", lr, tf->srr1); } else { - (*pr)("%s+%x: srr1=%#x\n", symname, diff, + db_printf("%s+%#x: srr1=%#x\n", symname, diff, tf->srr1); } - (*pr)("%-10s r1=%#x cr=%#x xer=%#x ctr=%#x", + db_printf("%-10s r1=%#x cr=%#x xer=%#x ctr=%#x", "", tf->fixreg[1], tf->cr, tf->xer, tf->ctr); -#ifdef PPC_MPC6XX if (tf->exc == EXC_DSI) - (*pr)(" dsisr=%#x", tf->dsisr); -#endif -#ifdef PPC_IBM4XX - if (tf->exc == EXC_DSI) - (*pr)(" dear=%#x", tf->dear); - (*pr)(" esr=%#x pid=%#x", tf->esr, tf->pid); -#endif - (*pr)("\n"); - fakeframe[0] = (db_addr_t) tf->fixreg[1]; - fakeframe[1] = (db_addr_t) tf->lr; - frame = (db_addr_t) fakeframe; + db_printf(" dsisr=%#x", tf->dsisr); + db_printf("\n"); + stackframe = (db_addr_t) tf->fixreg[1]; if (kernel_only && (tf->srr1 & PSL_PR)) break; goto next_frame; @@ -265,30 +249,52 @@ db_stack_trace_print(db_expr_t addr, int have_addr, db_expr_t count, diff = 0; symname = NULL; - sym = db_search_symbol(caller, DB_STGY_ANY, &diff); + sym = db_search_symbol(lr, DB_STGY_ANY, &diff); db_symbol_values(sym, &symname, 0); if (symname == NULL || !strcmp(symname, "end")) - (*pr)("at %p", caller); + db_printf("at %x", lr); else - (*pr)("at %s+%#x", symname, diff); + db_printf("at %s+%#x", symname, diff); if (full) /* Print all the args stored in that stackframe. */ - (*pr)("(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)", + db_printf("(%x, %x, %x, %x, %x, %x, %x, %x)", args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); - (*pr)("\n"); + db_printf("\n"); } + + return (0); } void db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, char *modif) { + struct thread *td; - db_stack_trace_print(addr, have_addr, count, modif, db_printf); + td = (have_addr) ? kdb_thr_lookup(addr) : kdb_thread; + if (td == NULL) { + db_printf("Thread %d not found\n", (int)addr); + return; + } + db_trace_thread(td, count); } void -db_print_backtrace(void) +db_trace_self(void) +{ + db_addr_t addr; + + addr = (db_addr_t)__builtin_frame_address(1); + db_backtrace(curthread, addr, -1); +} + +int +db_trace_thread(struct thread *td, int count) { + struct pcb *ctx; + + ctx = kdb_thr_ctx(td); + return (db_backtrace(td, (db_addr_t)ctx->pcb_sp, count)); } + |