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);