Module Name: src
Committed By: hans
Date: Sat Mar 22 10:37:19 UTC 2025
Modified Files:
src/sys/arch/vax/include: db_machdep.h
src/sys/arch/vax/vax: db_disasm.c db_machdep.c trap.c
Log Message:
vax/ddb(4): clean up machine dependent code and improve usability
First, let's garbage collect some dead code wrapped in #if 0/#endif
that were introduced in back in 1999 in revision 1.17 of db_machdep.c,
when VAX stack tracing was last reworked. There's also an unused
argument "stackbase" in db_dump_stack() that can go away.
Next, fix stack tracing on panic. The panicstr has already been printed
by the time we get here from db_panic(), and at least on !MULTIPROCESSOR
the panic stack trace caused a recursive panic immediately. While here,
add tracing by lwp and proc addresses. The code for tracing a process or
lwp should live in its own function, and we can rearrange the logic in
db_stack_trace_print() to be a bit clearer.
While here, add some basic memory access checks so we don't suffer
from recursive panics all the time. For the same reason, get the
process with db_find_proc() rather than proc_find_raw().
To generate a diff of this commit:
cvs rdiff -u -r1.20 -r1.21 src/sys/arch/vax/include/db_machdep.h
cvs rdiff -u -r1.25 -r1.26 src/sys/arch/vax/vax/db_disasm.c
cvs rdiff -u -r1.60 -r1.61 src/sys/arch/vax/vax/db_machdep.c
cvs rdiff -u -r1.139 -r1.140 src/sys/arch/vax/vax/trap.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/vax/include/db_machdep.h
diff -u src/sys/arch/vax/include/db_machdep.h:1.20 src/sys/arch/vax/include/db_machdep.h:1.21
--- src/sys/arch/vax/include/db_machdep.h:1.20 Mon Nov 6 03:47:48 2017
+++ src/sys/arch/vax/include/db_machdep.h Sat Mar 22 10:37:19 2025
@@ -1,4 +1,4 @@
-/* $NetBSD: db_machdep.h,v 1.20 2017/11/06 03:47:48 christos Exp $ */
+/* $NetBSD: db_machdep.h,v 1.21 2025/03/22 10:37:19 hans Exp $ */
/*
* Mach Operating System
@@ -34,6 +34,7 @@
* Modified for vax out of i386 code.
*/
+#include <sys/stdbool.h>
#include <sys/param.h>
#include <uvm/uvm.h>
#include <machine/trap.h>
@@ -77,6 +78,7 @@ extern db_regs_t ddb_regs; /* register s
/* Prototypes */
void kdb_trap(struct trapframe *);
+bool db_validate_address(vaddr_t);
/*
* We use a.out symbols in DDB (unless we are ELF then we use ELF symbols).
Index: src/sys/arch/vax/vax/db_disasm.c
diff -u src/sys/arch/vax/vax/db_disasm.c:1.25 src/sys/arch/vax/vax/db_disasm.c:1.26
--- src/sys/arch/vax/vax/db_disasm.c:1.25 Fri Feb 28 18:08:51 2025
+++ src/sys/arch/vax/vax/db_disasm.c Sat Mar 22 10:37:19 2025
@@ -1,4 +1,4 @@
-/* $NetBSD: db_disasm.c,v 1.25 2025/02/28 18:08:51 hans Exp $ */
+/* $NetBSD: db_disasm.c,v 1.26 2025/03/22 10:37:19 hans Exp $ */
/*
* Copyright (c) 1996 Ludd, University of Lule}, Sweden.
* All rights reserved.
@@ -28,7 +28,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: db_disasm.c,v 1.25 2025/02/28 18:08:51 hans Exp $");
+__KERNEL_RCSID(0, "$NetBSD: db_disasm.c,v 1.26 2025/03/22 10:37:19 hans Exp $");
#include <sys/param.h>
#include <sys/proc.h>
@@ -40,6 +40,7 @@ __KERNEL_RCSID(0, "$NetBSD: db_disasm.c,
#include <ddb/db_variables.h>
#include <ddb/db_interface.h>
#include <ddb/db_output.h>
+#include <ddb/db_command.h>
#include <vax/vax/db_disasm.h>
@@ -146,6 +147,12 @@ db_disasm(db_addr_t loc, bool altfmt)
inst_buffer ib;
+ if (!db_validate_address(loc)) {
+ db_printf("location 0x%lx inaccessible\n", loc);
+ db_error(NULL);
+ /*NOTREACHED*/
+ }
+
memset(&ib, 0, sizeof(ib));
ib.ppc = (void *) loc;
ib.curp = ib.dasm;
Index: src/sys/arch/vax/vax/db_machdep.c
diff -u src/sys/arch/vax/vax/db_machdep.c:1.60 src/sys/arch/vax/vax/db_machdep.c:1.61
--- src/sys/arch/vax/vax/db_machdep.c:1.60 Wed Oct 26 23:38:09 2022
+++ src/sys/arch/vax/vax/db_machdep.c Sat Mar 22 10:37:19 2025
@@ -1,4 +1,4 @@
-/* $NetBSD: db_machdep.c,v 1.60 2022/10/26 23:38:09 riastradh Exp $ */
+/* $NetBSD: db_machdep.c,v 1.61 2025/03/22 10:37:19 hans Exp $ */
/*
* :set tabs=4
@@ -39,7 +39,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: db_machdep.c,v 1.60 2022/10/26 23:38:09 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: db_machdep.c,v 1.61 2025/03/22 10:37:19 hans Exp $");
#include "opt_multiprocessor.h"
@@ -67,6 +67,7 @@ __KERNEL_RCSID(0, "$NetBSD: db_machdep.c
#include <ddb/db_access.h>
#include <ddb/db_interface.h>
#include <ddb/db_variables.h>
+#include <ddb/db_proc.h>
#include "ioconf.h"
@@ -239,11 +240,35 @@ kdbprinttrap(int type, int code)
}
/*
+ * Check whether an address is accessible.
+ */
+bool
+db_validate_address(vaddr_t addr)
+{
+ struct proc *p = curproc;
+ struct pmap *pmap;
+
+ if (!p || !p->p_vmspace || !p->p_vmspace->vm_map.pmap ||
+ addr >= VM_MIN_KERNEL_ADDRESS)
+ pmap = pmap_kernel();
+ else
+ pmap = p->p_vmspace->vm_map.pmap;
+
+ return (pmap_extract(pmap, addr, NULL));
+}
+
+/*
* Read bytes from kernel address space for debugger.
*/
void
db_read_bytes(vaddr_t addr, size_t size, char *data)
{
+ if (!db_validate_address(addr)) {
+ db_printf("address 0x%lx is inaccessible\n", addr);
+ db_error(NULL);
+ /*NOTREACHED*/
+ }
+
memcpy(data, (void *)addr, size);
}
@@ -253,6 +278,12 @@ db_read_bytes(vaddr_t addr, size_t size,
void
db_write_bytes(vaddr_t addr, size_t size, const char *data)
{
+ if (!db_validate_address(addr)) {
+ db_printf("address 0x%lx is inaccessible\n", addr);
+ db_error(NULL);
+ /*NOTREACHED*/
+ }
+
memcpy((void *)addr, data, size);
}
@@ -293,12 +324,12 @@ const struct db_variable * const db_ereg
/*
* Dump a stack traceback. Takes two arguments:
* fp - CALL FRAME pointer
- * stackbase - Lowest stack value
+ * pr - printf-like function pointer for output
*/
static void
-db_dump_stack(VAX_CALLFRAME *fp, u_int stackbase,
- void (*pr)(const char *, ...)) {
- u_int nargs, arg_base, regs;
+db_dump_stack(VAX_CALLFRAME *fp, void (*pr)(const char *, ...))
+{
+ u_int nargs, arg_base;
VAX_CALLFRAME *tmp_frame;
db_expr_t diff;
db_sym_t sym;
@@ -306,17 +337,19 @@ db_dump_stack(VAX_CALLFRAME *fp, u_int s
extern int sret;
extern unsigned int etext;
- (*pr)("Stack traceback : \n");
+ (*pr)("Stack traceback:\n");
if (IN_USERLAND(fp)) {
- (*pr)(" Process is executing in user space.\n");
+ (*pr)("\t Process is executing in user space.\n");
return;
}
-#if 0
- while (((u_int)(fp->vax_fp) > stackbase - 0x100) &&
- ((u_int)(fp->vax_fp) < (stackbase + USPACE))) {
-#endif
- while (!IN_USERLAND(fp->vax_fp)) {
+ if (!db_validate_address((vaddr_t)fp)) {
+ (*pr)("\t frame 0x%x inaccessible.\n", fp);
+ return;
+ }
+
+ while (!IN_USERLAND(fp->vax_fp) &&
+ db_validate_address((vaddr_t)fp->vax_fp)) {
u_int pc = fp->vax_pc;
/*
@@ -324,37 +357,39 @@ db_dump_stack(VAX_CALLFRAME *fp, u_int s
* As the argument pointer may have been used as a temporary
* by the callee ... recreate what it would have pointed to
* as follows:
- * The vax_regs value has a 12 bit bitmask of the registers
- * that were saved on the stack.
- * Store that in 'regs' and then for every bit that is
- * on (indicates the register contents are on the stack)
- * increment the argument base (arg_base) by one.
- * When that is done, args[arg_base] points to the longword
- * that identifies the number of arguments.
- * arg_base+1 - arg_base+n are the argument pointers/contents.
+ * The vax_regs value is a 12 bit bitmask of the registers
+ * that were saved on the stack, corresponding to R0 to R11.
+ * By counting those bits, we get a value for arg_base so that
+ * args[arg_base] points to the longword that identifies the
+ * number of arguments.
+ * arg_base+1 - arg_base+n are the argument pointers/contents.
*/
-
- /* If this was due to a trap/fault, pull the correct pc
- * out of the trap frame. */
+ /*
+ * If this was due to a trap/fault, pull the correct pc
+ * out of the trap frame.
+ */
if (pc == (u_int) &sret && fp->vax_fp != 0) {
struct trapframe *tf;
- /* Isolate the saved register bits, and count them */
- regs = fp->vax_regs;
- for (arg_base = 0; regs != 0; regs >>= 1) {
- if (regs & 1)
- arg_base++;
- }
+
+ /* Count saved register bits */
+ arg_base = popcount(fp->vax_regs);
+
tf = (struct trapframe *) &fp->vax_args[arg_base + 2];
- (*pr)("0x%lx: trap type=0x%lx code=0x%lx pc=0x%lx psl=0x%lx\n",
- tf, tf->tf_trap, tf->tf_code,
- tf->tf_pc, tf->tf_psl);
+ if (!db_validate_address((vaddr_t)tf)) {
+ (*pr)("0x%lx: trap frame inaccessible.\n", tf);
+ return;
+ }
+
+ (*pr)("0x%lx: trap type=0x%lx code=0x%lx pc=0x%lx "
+ "psl=0x%lx\n", tf, tf->tf_trap, tf->tf_code,
+ tf->tf_pc, tf->tf_psl);
pc = tf->tf_pc;
}
diff = INT_MAX;
symname = NULL;
- if (pc >= 0x80000000 && pc < (u_int) &etext) {
+ if (pc >= VM_MIN_KERNEL_ADDRESS && pc < (u_int) &etext) {
sym = db_search_symbol(pc, DB_STGY_ANY, &diff);
db_symbol_values(sym, &symname, 0);
}
@@ -366,12 +401,8 @@ db_dump_stack(VAX_CALLFRAME *fp, u_int s
/* First get the frame that called this function ... */
tmp_frame = fp->vax_fp;
- /* Isolate the saved register bits, and count them */
- regs = tmp_frame->vax_regs;
- for (arg_base = 0; regs != 0; regs >>= 1) {
- if (regs & 1)
- arg_base++;
- }
+ /* Count saved register bits */
+ arg_base = popcount(tmp_frame->vax_regs);
/* number of arguments is then pointed to by vax_args[arg_base] */
nargs = tmp_frame->vax_args[arg_base];
@@ -390,6 +421,59 @@ db_dump_stack(VAX_CALLFRAME *fp, u_int s
}
}
+static void
+db_trace_process(struct lwp *l, struct proc *p, void (*pr)(const char *, ...))
+{
+ struct pcb *pcb;
+
+ KASSERT(l != NULL);
+ KASSERT(p != NULL);
+
+ if (!db_validate_address((vaddr_t)l)) {
+ (*pr)("LWP at %p inaccessible\n", l);
+ return;
+ }
+
+ if (!db_validate_address((vaddr_t)p)) {
+ (*pr)("Process at %p inaccessible\n", p);
+ return;
+ }
+
+ pcb = lwp_getpcb(l);
+ if (!db_validate_address((vaddr_t)pcb)) {
+ (*pr)("PCB at %p inaccessible\n", pcb);
+ return;
+ }
+
+ (*pr)("Process %d.%d\n", p->p_pid, l->l_lid);
+ (*pr)("\t PCB contents:\n");
+ (*pr)(" KSP = 0x%x\n", (unsigned int)(pcb->KSP));
+ (*pr)(" ESP = 0x%x\n", (unsigned int)(pcb->ESP));
+ (*pr)(" SSP = 0x%x\n", (unsigned int)(pcb->SSP));
+ (*pr)(" USP = 0x%x\n", (unsigned int)(pcb->USP));
+ (*pr)(" R[00] = 0x%08x R[06] = 0x%08x\n",
+ (unsigned int)(pcb->R[0]), (unsigned int)(pcb->R[6]));
+ (*pr)(" R[01] = 0x%08x R[07] = 0x%08x\n",
+ (unsigned int)(pcb->R[1]), (unsigned int)(pcb->R[7]));
+ (*pr)(" R[02] = 0x%08x R[08] = 0x%08x\n",
+ (unsigned int)(pcb->R[2]), (unsigned int)(pcb->R[8]));
+ (*pr)(" R[03] = 0x%08x R[09] = 0x%08x\n",
+ (unsigned int)(pcb->R[3]), (unsigned int)(pcb->R[9]));
+ (*pr)(" R[04] = 0x%08x R[10] = 0x%08x\n",
+ (unsigned int)(pcb->R[4]), (unsigned int)(pcb->R[10]));
+ (*pr)(" R[05] = 0x%08x R[11] = 0x%08x\n",
+ (unsigned int)(pcb->R[5]), (unsigned int)(pcb->R[11]));
+ (*pr)(" AP = 0x%x\n", (unsigned int)(pcb->AP));
+ (*pr)(" FP = 0x%x\n", (unsigned int)(pcb->FP));
+ (*pr)(" PC = 0x%x\n", (unsigned int)(pcb->PC));
+ (*pr)(" PSL = 0x%x\n", (unsigned int)(pcb->PSL));
+ (*pr)(" Trap frame pointer: 0x%x\n", l->l_md.md_utf);
+
+ db_dump_stack((VAX_CALLFRAME *)(pcb->FP), pr);
+
+ return;
+}
+
/*
* Implement the trace command which has the form:
*
@@ -408,39 +492,48 @@ db_stack_trace_print(
{
struct lwp *l = curlwp;
struct proc *p = l->l_proc;
- struct pcb *pcb;
int trace_proc;
- pid_t curpid;
+ int trace_lwp;
const char *s;
- /* Check to see if we're tracing a process */
+ /* Check to see if we're tracing a process or lwp */
trace_proc = 0;
s = modif;
- while (!trace_proc && *s) {
- if (*s++ == 't')
- trace_proc++; /* why yes we are */
- }
-
- /* Trace a panic */
- if (panicstr) {
- (*pr)("panic: %s\n", panicstr);
- /* xxx ? where did we panic and whose stack are we using? */
-#ifdef MULTIPROCESSOR
- db_dump_stack((VAX_CALLFRAME *)(ddb_regs.tf_fp), ddb_regs.tf_ap, pr);
-#else
- db_dump_stack((VAX_CALLFRAME *)(ddb_regs.tf_sp), ddb_regs.tf_ap, pr);
-#endif
- return;
- }
+ do {
+ switch (*s) {
+ case 't':
+ trace_proc++;
+ break;
+
+ case 'a':
+ trace_lwp++;
+ break;
+ }
+ } while (*s++ && !(trace_proc || trace_lwp));
/*
- * If user typed an address its either a PID, or a Frame
- * if no address then either current proc or panic
+ * If we're here because of a panic, we'll always have an address of a
+ * frame.
+ *
+ * If the user typed an address, it can be one of the following:
+ * - the address of a struct lwp
+ * - the address of a struct proc
+ * - a PID, hex or decimal
+ * - the address of a frame
*/
if (have_addr) {
- if (trace_proc) {
- p = proc_find_raw((int)addr);
- /* Try to be helpful by looking at it as if it were decimal */
+ if (trace_lwp) {
+ l = (struct lwp *)addr;
+ p = l->l_proc;
+ db_trace_process(l, p, pr);
+ return;
+ } else if (trace_proc) {
+ p = db_proc_find((int)addr);
+
+ /*
+ * Try to be helpful by looking at it as if it were
+ * decimal.
+ */
if (p == NULL) {
u_int tpid = 0;
u_int foo = addr;
@@ -448,133 +541,38 @@ db_stack_trace_print(
while (foo != 0) {
int digit = (foo >> 28) & 0xf;
if (digit > 9) {
- (*pr)(" No such process.\n");
- return;
+ tpid = -1;
+ break;
}
tpid = tpid * 10 + digit;
foo = foo << 4;
}
- p = proc_find_raw(tpid);
- if (p == NULL) {
- (*pr)(" No such process.\n");
+ p = db_proc_find(tpid);
+ }
+
+ /* Not a PID. If accessible, assume it's an address. */
+ if (p == NULL) {
+ if (db_validate_address(addr)) {
+ p = (struct proc *)addr;
+ } else {
+ (*pr)("\t No such process.\n");
return;
}
}
- } else {
- db_dump_stack((VAX_CALLFRAME *)addr, 0, pr);
- return;
- }
-#if 0
- } else {
- if (!trace_proc) {
- l = curlwp;
- if (l == NULL) {
- (*pr)("trace: no current process! (ignored)\n");
- return;
- }
- } else {
- if (! panicstr) {
- (*pr)("Not a panic, no active process, ignored.\n");
- return;
- }
- }
-#endif
- }
- KASSERT(l != NULL);
- pcb = lwp_getpcb(l);
- curpid = p->p_pid;
- (*pr)("Process %d.%d\n", curpid, l->l_lid);
- (*pr)(" PCB contents:\n");
- (*pr)(" KSP = 0x%x\n", (unsigned int)(pcb->KSP));
- (*pr)(" ESP = 0x%x\n", (unsigned int)(pcb->ESP));
- (*pr)(" SSP = 0x%x\n", (unsigned int)(pcb->SSP));
- (*pr)(" USP = 0x%x\n", (unsigned int)(pcb->USP));
- (*pr)(" R[00] = 0x%08x R[06] = 0x%08x\n",
- (unsigned int)(pcb->R[0]), (unsigned int)(pcb->R[6]));
- (*pr)(" R[01] = 0x%08x R[07] = 0x%08x\n",
- (unsigned int)(pcb->R[1]), (unsigned int)(pcb->R[7]));
- (*pr)(" R[02] = 0x%08x R[08] = 0x%08x\n",
- (unsigned int)(pcb->R[2]), (unsigned int)(pcb->R[8]));
- (*pr)(" R[03] = 0x%08x R[09] = 0x%08x\n",
- (unsigned int)(pcb->R[3]), (unsigned int)(pcb->R[9]));
- (*pr)(" R[04] = 0x%08x R[10] = 0x%08x\n",
- (unsigned int)(pcb->R[4]), (unsigned int)(pcb->R[10]));
- (*pr)(" R[05] = 0x%08x R[11] = 0x%08x\n",
- (unsigned int)(pcb->R[5]), (unsigned int)(pcb->R[11]));
- (*pr)(" AP = 0x%x\n", (unsigned int)(pcb->AP));
- (*pr)(" FP = 0x%x\n", (unsigned int)(pcb->FP));
- (*pr)(" PC = 0x%x\n", (unsigned int)(pcb->PC));
- (*pr)(" PSL = 0x%x\n", (unsigned int)(pcb->PSL));
- (*pr)(" Trap frame pointer: %o\n", l->l_md.md_utf);
- db_dump_stack((VAX_CALLFRAME *)(pcb->FP), (u_int)pcb->KSP, pr);
- return;
-#if 0
- while (((u_int)(cur_frame->vax_fp) > stackbase) &&
- ((u_int)(cur_frame->vax_fp) < (stackbase + USPACE))) {
- u_int nargs;
- VAX_CALLFRAME *tmp_frame;
-
- diff = INT_MAX;
- symname = NULL;
- sym = db_search_symbol(cur_frame->vax_pc, DB_STGY_ANY, &diff);
- db_symbol_values(sym, &symname, 0);
- (*pr)("%s+0x%lx(", symname, diff);
-
- /*
- * Figure out the arguments by using a bit of subterfuge
- * since the argument pointer may have been used as a temporary
- * by the callee ... recreate what it would have pointed to
- * as follows:
- * The vax_regs value has a 12 bit bitmask of the registers
- * that were saved on the stack.
- * Store that in 'regs' and then for every bit that is
- * on (indicates the register contents are on the stack)
- * increment the argument base (arg_base) by one.
- * When that is done, args[arg_base] points to the longword
- * that identifies the number of arguments.
- * arg_base+1 - arg_base+n are the argument pointers/contents.
- */
-
- /* First get the frame that called this function ... */
- tmp_frame = cur_frame->vax_fp;
-
- /* Isolate the saved register bits, and count them */
- regs = tmp_frame->vax_regs;
- for (arg_base = 0; regs != 0; regs >>= 1) {
- if (regs & 1)
- arg_base++;
- }
-
- /* number of arguments is then pointed to by vax_args[arg_base] */
- nargs = tmp_frame->vax_args[arg_base];
- if (nargs) {
- nargs--; /* reduce by one for formatting niceties */
- arg_base++; /* skip past the actual number of arguments */
- while (nargs--)
- (*pr)("0x%x,", tmp_frame->vax_args[arg_base++]);
-
- /* now print out the last arg with closing brace and \n */
- (*pr)("0x%x)\n", tmp_frame->vax_args[++arg_base]);
- } else
- (*pr)("void)\n");
- /* move to the next frame */
- cur_frame = cur_frame->vax_fp;
- }
- /*
- * DEAD CODE, previous panic tracing code.
- */
- if (! have_addr) {
- printf("Trace default\n");
- if (panicstr) {
- cf = (int *)ddb_regs.sp;
+ db_trace_process(p->p_lwps.lh_first, p, pr);
+ return;
} else {
- printf("Don't know what to do without panic\n");
+ db_dump_stack((VAX_CALLFRAME *)addr, pr);
return;
}
- stackbase = (ddb_regs.psl & PSL_IS ? istack : pcb);
+ } else {
+ /* We got no address. Grab stuff from ddb_regs. */
+ if (panicstr)
+ db_dump_stack((VAX_CALLFRAME *)ddb_regs.tf_fp, pr);
+ else
+ (*pr)("\t trace what?\n");
}
-#endif
}
static int ddbescape = 0;
Index: src/sys/arch/vax/vax/trap.c
diff -u src/sys/arch/vax/vax/trap.c:1.139 src/sys/arch/vax/vax/trap.c:1.140
--- src/sys/arch/vax/vax/trap.c:1.139 Sun Mar 16 15:35:00 2025
+++ src/sys/arch/vax/vax/trap.c Sat Mar 22 10:37:19 2025
@@ -1,4 +1,4 @@
-/* $NetBSD: trap.c,v 1.139 2025/03/16 15:35:00 riastradh Exp $ */
+/* $NetBSD: trap.c,v 1.140 2025/03/22 10:37:19 hans Exp $ */
/*
* Copyright (c) 1994 Ludd, University of Lule}, Sweden.
@@ -28,7 +28,7 @@
/* All bugs are subject to removal without further notice */
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.139 2025/03/16 15:35:00 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.140 2025/03/22 10:37:19 hans Exp $");
#include "opt_ddb.h"
#include "opt_multiprocessor.h"
@@ -225,7 +225,7 @@ if(faultdebug)printf("trap accflt type %
tf->tf_r0 = rv;
return;
}
- printf("r0=%08lx r1=%08lx r2=%08lx r3=%08lx ",
+ printf("r0=%08lx r1=%08lx r2=%08lx r3=%08lx\n",
tf->tf_r0, tf->tf_r1, tf->tf_r2, tf->tf_r3);
printf("r4=%08lx r5=%08lx r6=%08lx r7=%08lx\n",
tf->tf_r4, tf->tf_r5, tf->tf_r6, tf->tf_r7);