1*47821Sbostic /*- 2*47821Sbostic * Copyright (c) 1991 The Regents of the University of California. 3*47821Sbostic * All rights reserved. 4*47821Sbostic * 5*47821Sbostic * %sccs.include.proprietary.c% 6*47821Sbostic */ 7*47821Sbostic 836565Sbostic #ifndef lint 9*47821Sbostic static char sccsid[] = "@(#)kstack.c 5.2 (Berkeley) 04/04/91"; 10*47821Sbostic #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> 2136565Sbostic #include <machine/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 */ 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 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 */ 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 */ 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 */ 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 */ 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