xref: /csrg-svn/old/adb/adb.vax/kstack.c (revision 47877)
147821Sbostic /*-
247821Sbostic  * Copyright (c) 1991 The Regents of the University of California.
347821Sbostic  * All rights reserved.
447821Sbostic  *
547821Sbostic  * %sccs.include.proprietary.c%
647821Sbostic  */
747821Sbostic 
836565Sbostic #ifndef lint
9*47877Ssklower static char sccsid[] = "@(#)kstack.c	5.3 (Berkeley) 04/11/91";
1047821Sbostic #endif /* not lint */
1136565Sbostic 
1236565Sbostic /*
1336565Sbostic  * adb - routines to probe the kernel stack when debugging post-mortem
1436565Sbostic  * crash dumps.
1536565Sbostic  */
1636565Sbostic 
1736565Sbostic #include "defs.h"
1836565Sbostic #include <ctype.h>
1936565Sbostic #include <machine/pte.h>
2036565Sbostic #include <machine/frame.h>
21*47877Ssklower #include <vax/vax/rpb.h>
2236565Sbostic 
2336565Sbostic struct	pte *sbr;
2436565Sbostic int	slr;
2536565Sbostic struct	pcb pcb;
2636565Sbostic 
2736565Sbostic static caddr_t rpb;
2836565Sbostic static caddr_t scb;
2936565Sbostic static caddr_t intstack, eintstack;
3036565Sbostic static caddr_t ustack, eustack;
3136565Sbostic 
3236565Sbostic char	*malloc();
3336565Sbostic 
3436565Sbostic /*
3536565Sbostic  * Convert a kernel virtual address to an (off_t) physical offset.
3636565Sbostic  */
3736565Sbostic #define	kvtooff(a)	((off_t)(a) & ~KERNBASE)
3836565Sbostic 
3936565Sbostic /*
4036565Sbostic  * Check if an address is in one of the kernel's stacks:
4136565Sbostic  * interrupt stack, rpb stack (during restart sequence),
4236565Sbostic  * or u. stack.
4336565Sbostic  */
4436565Sbostic #define	within(a, b, e) \
4536565Sbostic 	((addr_t)(a) >= (addr_t)(b) && (addr_t)(a) < (addr_t)(e))
4636565Sbostic #define	kstackaddr(a) \
4736565Sbostic 	(within(a, intstack, eintstack) || \
4836565Sbostic 	 within(a, rpb + sizeof(struct rpb), scb) || \
4936565Sbostic 	 within(a, ustack, eustack))
5036565Sbostic 
5136565Sbostic /*
5236565Sbostic  * Determine whether we are looking at a kernel core dump, and if so,
5336565Sbostic  * set sbr and slr and the current pcb.
5436565Sbostic  */
getkcore()5536565Sbostic getkcore() {
5636565Sbostic 	struct nlist *sm, *ss, *mp;
5736565Sbostic 
5836565Sbostic 	if ((sm = lookup("_Sysmap")) == NULL ||
5936565Sbostic 	    (ss = lookup("_Syssize")) == NULL ||
6036565Sbostic 	    (mp = lookup("_masterpaddr")) == NULL)
6136565Sbostic 		return (0);	/* a.out is not a vmunix */
6236565Sbostic 	datmap.m1.b = 0;
6336565Sbostic 	datmap.m1.e = -1L;
6436565Sbostic 	/* must set sbr, slr before setpcb() */
6536565Sbostic 	sbr = (struct pte *)sm->n_value;
6636565Sbostic 	slr = ss->n_value;
6736565Sbostic 	adbprintf("sbr %X slr %X\n", sbr, slr);
6836565Sbostic 	setpcb((addr_t)mp->n_value);
6936565Sbostic 	getpcb();
7036565Sbostic 	findstackframe();
7136565Sbostic 	return (1);
7236565Sbostic }
7336565Sbostic 
7436565Sbostic /*
7536565Sbostic  * A version of lookup that never returns failure, and which returns
7636565Sbostic  * the n_value field of the symbol found.
7736565Sbostic  */
7836565Sbostic static caddr_t
xlookup(sym)7936565Sbostic xlookup(sym)
8036565Sbostic 	char *sym;
8136565Sbostic {
8236565Sbostic 	struct nlist *sp;
8336565Sbostic 
8436565Sbostic 	if ((sp = lookup(sym)) == NULL) {
8536565Sbostic 		adbprintf("symbol %s not found ... bad kernel core?\n", sym);
8636565Sbostic 		exit(1);
8736565Sbostic 	}
8836565Sbostic 	return ((caddr_t)sp->n_value);
8936565Sbostic }
9036565Sbostic 
9136565Sbostic /*
9236565Sbostic  * Find the current stack frame when debugging the kernel.
9336565Sbostic  * If we're looking at a crash dump and this was not a ``clean''
9436565Sbostic  * crash, then we must search the interrupt stack carefully
9536565Sbostic  * looking for a valid frame.
9636565Sbostic  */
findstackframe()9736565Sbostic findstackframe()
9836565Sbostic {
9936565Sbostic 	register char *cp;
10036565Sbostic 	register int n;
10136565Sbostic 	caddr_t addr;
10236565Sbostic 	struct frame fr;
10336565Sbostic 	char buf[256];
10436565Sbostic 
10536565Sbostic 	if (readcore(kvtooff(xlookup("_panicstr")), (caddr_t)&addr,
10636565Sbostic 			sizeof(addr)) != sizeof(addr) || addr == 0)
10736565Sbostic 		return;
10836565Sbostic 	n = readcore(kvtooff(addr), buf, sizeof(buf));
10936565Sbostic 	for (cp = buf; --n > 0 && *cp != 0; cp++)
11036565Sbostic 		if (!isascii(*cp) || (!isprint(*cp) && !isspace(*cp)))
11136565Sbostic 			*cp = '?';
11236565Sbostic 	*cp = '\0';
11336565Sbostic 	adbprintf("panic: %s\n", buf);
11436565Sbostic 
11536565Sbostic 	/*
11636565Sbostic 	 * After a panic, look at the top of the rpb stack to find a stack
11736565Sbostic 	 * frame.  If this was a clean crash, i.e. one which left the
11836565Sbostic 	 * interrupt and kernel stacks in a reasonable state, then we should
11936565Sbostic 	 * find a pointer to the proper stack frame here (at location scb-4).
12036565Sbostic 	 * If we don't find a reasonable frame here, then we must search down
12136565Sbostic 	 * through the interrupt stack.
12236565Sbostic 	 */
12336565Sbostic 	intstack = xlookup("_intstack");
12436565Sbostic 	eintstack = xlookup("_doadump");		/* XXX */
12536565Sbostic 	rpb = xlookup("_rpb");
12636565Sbostic 	scb = xlookup("_scb");
12736565Sbostic 	ustack = xlookup("_u");
12836565Sbostic 	eustack = ustack + ctob(UPAGES);
12936565Sbostic 	ustack += (int)((struct user *)0)->u_stack;
13036565Sbostic 	(void) readcore(kvtooff(scb - 4), (caddr_t)&addr, sizeof(addr));
13136565Sbostic 	if (!getframe(addr, &fr) && !checkintstack(&addr, &fr)) {
13236565Sbostic 		/* search kernel stack? */
13336565Sbostic 		prints("can't locate stack frame\n");
13436565Sbostic 		return;
13536565Sbostic 	}
13636565Sbostic 	/* probably shouldn't clobber pcb, but for now this is easy */
13736565Sbostic 	pcb.pcb_fp = (int)addr;
13836565Sbostic 	pcb.pcb_pc = fr.fr_savpc;
13936565Sbostic 	pcb.pcb_ap = (int)addr + sizeof(fr) + fr.fr_spa;
14036565Sbostic 	for (n = fr.fr_mask; n != 0; n >>= 1)
14136565Sbostic 		if (n & 1)
14236565Sbostic 			pcb.pcb_ap += 4;
14336565Sbostic }
14436565Sbostic 
14536565Sbostic /*
14636565Sbostic  * Search interrupt stack for a valid frame.  Return 1 if found,
14736565Sbostic  * also setting *addr to the kernel address of the frame, and *frame
14836565Sbostic  * to the frame at that address.
14936565Sbostic  */
checkintstack(addr,frame)15036565Sbostic checkintstack(addr, frame)
15136565Sbostic 	caddr_t *addr;
15236565Sbostic 	struct frame *frame;
15336565Sbostic {
15436565Sbostic 	register int ssize;
15536565Sbostic 	register char *stack;
15636565Sbostic 
15736565Sbostic 	ssize = eintstack - intstack;
15836565Sbostic 	if ((stack = malloc((u_int)ssize)) == NULL)
15936565Sbostic 		return (0);
16036565Sbostic 	if (readcore(kvtooff(intstack), stack, ssize) != ssize) {
16136565Sbostic 		free(stack);
16236565Sbostic 		return (0);
16336565Sbostic 	}
16436565Sbostic 	for (ssize -= sizeof(*frame); ssize >= 0; ssize -= 4) {
16536565Sbostic 		if (goodframe((struct frame *)&stack[ssize])) {
16636565Sbostic 			*addr = &intstack[ssize];
16736565Sbostic 			*frame = *(struct frame *)&stack[ssize];
16836565Sbostic 			free(stack);
16936565Sbostic 			return (1);
17036565Sbostic 		}
17136565Sbostic 	}
17236565Sbostic 	free(stack);
17336565Sbostic 	return (0);
17436565Sbostic }
17536565Sbostic 
17636565Sbostic /*
17736565Sbostic  * Get a stack frame and verify that it looks like
17836565Sbostic  * something which might be on a kernel stack.  Return 1 if OK.
17936565Sbostic  */
getframe(addr,fp)18036565Sbostic getframe(addr, fp)
18136565Sbostic 	caddr_t addr;
18236565Sbostic 	struct frame *fp;
18336565Sbostic {
18436565Sbostic 	off_t off;
18536565Sbostic 	char *err = NULL;
18636565Sbostic 
18736565Sbostic 	if (!kstackaddr(addr))
18836565Sbostic 		return (0);
18936565Sbostic 	off = vtophys((addr_t)addr, &err);
19036565Sbostic 	if (err || readcore(off, (caddr_t)fp, sizeof(*fp)) != sizeof(*fp))
19136565Sbostic 		return (0);
19236565Sbostic 	return (goodframe(fp));
19336565Sbostic }
19436565Sbostic 
19536565Sbostic /*
19636565Sbostic  * Check a call frame to see if it's ok as a kernel stack frame.
19736565Sbostic  * It should be a calls, should have its parent within the kernel stack,
19836565Sbostic  * and should return to kernel code.
19936565Sbostic  */
goodframe(fr)20036565Sbostic goodframe(fr)
20136565Sbostic 	register struct frame *fr;
20236565Sbostic {
20336565Sbostic 
20436565Sbostic 	return (fr->fr_handler == 0 && fr->fr_s &&
20536565Sbostic 		kstackaddr(fr->fr_savap) && kstackaddr(fr->fr_savfp) &&
20636565Sbostic 		within(fr->fr_savpc, txtmap.m1.b, txtmap.m1.e));
20736565Sbostic }
208