diff --git a/sys/arch/vax/vax/db_machdep.c b/sys/arch/vax/vax/db_machdep.c index d222ccd4100d..f9f00c67c32f 100644 --- a/sys/arch/vax/vax/db_machdep.c +++ b/sys/arch/vax/vax/db_machdep.c @@ -1,6 +1,8 @@ -/* $NetBSD: db_machdep.c,v 1.16 1999/04/12 20:38:20 pk Exp $ */ +/* $NetBSD: db_machdep.c,v 1.17 1999/06/20 00:58:23 ragge Exp $ */ /* + * :set tabs=4 + * * Mach Operating System * Copyright (c) 1991,1990 Carnegie Mellon University * All Rights Reserved. @@ -26,6 +28,9 @@ * rights to redistribute these changes. * * db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU) + * + * VAX enhancements by cmcmanis@mcmanis.com no rights reserved :-) + * */ /* @@ -36,6 +41,7 @@ #include #include +#include #include #include /* just for boothowto --eichin */ @@ -46,6 +52,7 @@ #include #include #include +#include #include #include @@ -66,6 +73,25 @@ int db_active = 0; extern int qdpolling; static int splsave; /* IPL before entering debugger */ +/* + * VAX Call frame on the stack, this from + * "Computer Programming and Architecture, The VAX-11" + * Henry Levy & Richard Eckhouse Jr. + * ISBN 0-932376-07-X + */ +typedef struct __vax_frame { + u_int vax_cond; /* condition handler */ + u_int vax_psw:16; /* 16 bit processor status word */ + u_int vax_regs:12; /* Register save mask. */ + u_int vax_zero:1; /* Always zero */ + u_int vax_calls:1; /* True if CALLS, false if CALLG */ + u_int vax_spa:2; /* Stack pointer alignment */ + u_int *vax_ap; /* argument pointer */ + struct __vax_frame *vax_fp; /* frame pointer of previous frame */ + u_int vax_pc; /* program counter */ + u_int vax_args[1]; /* 0 or more arguments */ +} VAX_CALLFRAME; + /* * DDB is called by either - D on keyboard, via a TRACE or * BPT trap or from kernel, normally as a result of a panic. @@ -83,6 +109,7 @@ kdb_trap(frame) case T_TRCTRAP: /* single_step */ break; + /* XXX todo: should be migrated to use VAX_CALLFRAME at some point */ case T_KDBTRAP: if (panicstr) { struct callsframe *pf, *df; @@ -116,12 +143,12 @@ kdb_trap(frame) /* XXX Should switch to interrupt stack here, if needed. */ - s = splddb(); + s = splimp(); db_active++; - cnpollc(TRUE); - db_trap(frame->trap, frame->code); - cnpollc(FALSE); - db_active--; + cnpollc(TRUE); + db_trap(frame->trap, frame->code); + cnpollc(FALSE); + db_active--; splx(s); if (!panicstr) @@ -207,58 +234,275 @@ struct db_variable db_regs[] = { }; struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]); -void -db_stack_trace_cmd(addr, have_addr, count, modif) - db_expr_t addr; - boolean_t have_addr; - db_expr_t count; - char *modif; -{ - extern vaddr_t proc0paddr, istack; - struct proc *p = curproc; - db_expr_t diff; - db_sym_t sym; - vaddr_t paddr; - u_int *cf, *tcf, abase, loop, i, stackbase; - char *symname; - - if (panicstr) { - cf = (int *)ddb_regs.sp; - } else { - printf("Don't know what to do without panic\n"); - cf = (int *)ddb_regs.fp; /* XXX */ +#define IN_USERLAND(x) (((u_int)(x) & 0x80000000) == 0) + +/* + * Dump a stack traceback. Takes two arguments: + * fp - CALL FRAME pointer + * stackbase - Lowest stack value + */ +static void +db_dump_stack(VAX_CALLFRAME *fp, u_int stackbase) { + u_int nargs, arg_base, regs; + VAX_CALLFRAME *tmp_frame; + db_expr_t diff; + db_sym_t sym; + char *symname; + + db_printf("Stack traceback : \n"); + if (IN_USERLAND(fp)) { + db_printf(" Process is executing in user space.\n"); + return; } - if (p) - paddr = (u_int)p->p_addr; - else - paddr = proc0paddr; - stackbase = (ddb_regs.psl & PSL_IS ? istack : paddr); - while ((cf[3] > stackbase) && (cf[3] < (stackbase + USPACE))) { + + while (((u_int)(fp->vax_fp) > stackbase) && + ((u_int)(fp->vax_fp) < (stackbase + USPACE))) { + diff = INT_MAX; symname = NULL; - abase = 0; - sym = db_search_symbol(cf[4], DB_STGY_ANY, &diff); + sym = db_search_symbol(fp->vax_pc, DB_STGY_ANY, &diff); db_symbol_values(sym, &symname, 0); - db_printf("%s+0x%lx(", symname, diff); - /* Pass all saved regs */ - tcf = (int *)cf[3]; - loop = (tcf[1] >> 16) & 0xfff; - while (loop) { - if (loop & 1) - abase++; - loop >>= 1; + + /* + * Figure out the arguments by using a bit of subtlety. + * 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. + */ + + /* 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++; } - if (tcf[5+abase]) { - for (i = 0; i < (tcf[5+abase] - 1); i++) - db_printf("0x%x,", tcf[6+abase+i]); - db_printf("0x%x)\n", tcf[6+abase+i]); + + /* 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--) + db_printf("0x%x,", tmp_frame->vax_args[arg_base++]); + + /* now print out the last arg with closing brace and \n */ + db_printf("0x%x)\n", tmp_frame->vax_args[++arg_base]); } else db_printf("void)\n"); - cf = (u_int *)cf[3]; + /* move to the next frame */ + fp = fp->vax_fp; } } +/* + * Implement the trace command which has the form: + * + * trace <-- Trace panic (same as before) + * trace 0x88888 <-- Trace process whose address is 888888 + * trace/t <-- Trace current process (0 if no current proc) + * trace/t 0tnn <-- Trace process nn (0t for decimal) + */ +void +db_stack_trace_cmd(addr, have_addr, count, modif) + db_expr_t addr; /* Address parameter */ + boolean_t have_addr; /* True if addr is valid */ + db_expr_t count; /* Optional count */ + char *modif; /* pointer to flag modifier 't' */ +{ + extern vaddr_t proc0paddr; + struct proc *p = curproc; + struct user *uarea; + int trace_proc; + pid_t curpid; + char *s; + + /* Check to see if we're tracing a process */ + trace_proc = 0; + s = modif; + while (!trace_proc && *s) { + if (*s++ == 't') + trace_proc++; /* why yes we are */ + } + + /* Trace a panic */ + if (! trace_proc) { + if (! panicstr) { + db_printf("Not a panic, use trace/t to trace a process.\n"); + return; + } + db_printf("panic: %s\n", panicstr); + /* xxx ? where did we panic and whose stack are we using? */ + db_dump_stack((VAX_CALLFRAME *)(ddb_regs.sp), ddb_regs.ap); + return; + } + + /* + * If user typed an address its either a PID, or a Frame + * if no address then either current proc or panic + */ + if (have_addr) { + if (trace_proc) { + p = pfind((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; + + while (foo != 0) { + int digit = (foo >> 28) & 0xf; + if (digit > 9) { + db_printf(" No such process.\n"); + return; + } + tpid = tpid * 10 + digit; + foo = foo << 4; + } + p = pfind(tpid); + if (p == NULL) { + db_printf(" No such process.\n"); + return; + } + } + } else { + p = (struct proc *)(addr); + if (pfind(p->p_pid) != p) { + db_printf(" This address does not point to a valid process.\n"); + return; + } + } + } else { + if (trace_proc) { + p = curproc; + if (p == NULL) { + db_printf("trace: no current process! (ignored)\n"); + return; + } + } else { + if (! panicstr) { + db_printf("Not a panic, no active process, ignored.\n"); + return; + } + } + } + if (p == NULL) { + uarea = (struct user *)proc0paddr; + curpid = 0; + } else { + uarea = p->p_addr; + curpid = p->p_pid; + } + db_printf("Process %d\n", curpid); + db_printf(" PCB contents:\n"); + db_printf(" KSP = 0x%x\n", (unsigned int)(uarea->u_pcb.KSP)); + db_printf(" ESP = 0x%x\n", (unsigned int)(uarea->u_pcb.ESP)); + db_printf(" SSP = 0x%x\n", (unsigned int)(uarea->u_pcb.SSP)); + db_printf(" USP = 0x%x\n", (unsigned int)(uarea->u_pcb.USP)); + db_printf(" R[00] = 0x%08x R[06] = 0x%08x\n", + (unsigned int)(uarea->u_pcb.R[0]), (unsigned int)(uarea->u_pcb.R[6])); + db_printf(" R[01] = 0x%08x R[07] = 0x%08x\n", + (unsigned int)(uarea->u_pcb.R[1]), (unsigned int)(uarea->u_pcb.R[7])); + db_printf(" R[02] = 0x%08x R[08] = 0x%08x\n", + (unsigned int)(uarea->u_pcb.R[2]), (unsigned int)(uarea->u_pcb.R[8])); + db_printf(" R[03] = 0x%08x R[09] = 0x%08x\n", + (unsigned int)(uarea->u_pcb.R[3]), (unsigned int)(uarea->u_pcb.R[9])); + db_printf(" R[04] = 0x%08x R[10] = 0x%08x\n", + (unsigned int)(uarea->u_pcb.R[4]), (unsigned int)(uarea->u_pcb.R[10])); + db_printf(" R[05] = 0x%08x R[11] = 0x%08x\n", + (unsigned int)(uarea->u_pcb.R[5]), (unsigned int)(uarea->u_pcb.R[11])); + db_printf(" AP = 0x%x\n", (unsigned int)(uarea->u_pcb.AP)); + db_printf(" FP = 0x%x\n", (unsigned int)(uarea->u_pcb.FP)); + db_printf(" PC = 0x%x\n", (unsigned int)(uarea->u_pcb.PC)); + db_printf(" PSL = 0x%x\n", (unsigned int)(uarea->u_pcb.PSL)); + db_printf(" Trap frame pointer: 0x%x\n", + (unsigned int)(uarea->u_pcb.framep)); + db_dump_stack((VAX_CALLFRAME *)(uarea->u_pcb.FP), (u_int) uarea->u_pcb.KSP); + 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); + db_printf("%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--) + db_printf("0x%x,", tmp_frame->vax_args[arg_base++]); + + /* now print out the last arg with closing brace and \n */ + db_printf("0x%x)\n", tmp_frame->vax_args[++arg_base]); + } else + db_printf("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; + } else { + printf("Don't know what to do without panic\n"); + return; + } + if (p) + paddr = (u_int)p->p_addr; + else + paddr = proc0paddr; + + stackbase = (ddb_regs.psl & PSL_IS ? istack : paddr); + } +#endif +} + static int ddbescape = 0; int @@ -286,4 +530,3 @@ kdbrint(tkn) return 0; } -