Better support for tracing stacks. From Chuck McManis.

This commit is contained in:
ragge 1999-06-20 00:58:23 +00:00
parent cb57cab9b1
commit abcc4bed15

View File

@ -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 <sys/param.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/reboot.h>
#include <sys/systm.h> /* just for boothowto --eichin */
@ -46,6 +52,7 @@
#include <machine/db_machdep.h>
#include <machine/trap.h>
#include <machine/frame.h>
#include <machine/pcb.h>
#include <machine/cpu.h>
#include <machine/../vax/gencons.h>
@ -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 <ESC> - 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;
}