summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgrehan <grehan@FreeBSD.org>2004-07-12 22:21:34 +0000
committergrehan <grehan@FreeBSD.org>2004-07-12 22:21:34 +0000
commit7ab8fbe2ac96491a915e26dceb6d3323f9dc67f8 (patch)
treefd30990dbab9e9b0c83177eee8ff5047b4f379fc
parent2312a73897f4672fc0a8e2f1ea6fbdefdc5ed7ee (diff)
downloadFreeBSD-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.
-rw-r--r--sys/powerpc/powerpc/db_trace.c304
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));
}
+
OpenPOWER on IntegriCloud