+caddr_t rpb, scb;
+caddr_t intstack, eintstack;
+caddr_t ustack, eustack;
+struct frame *getframe();
+struct frame *checkintstack();
+
+/*
+ * Find the current stack frame when debugging the kernel.
+ * If we're looking at a crash dump and this was not a ``clean''
+ * crash, then we must search the interrupt stack carefully
+ * looking for a valid frame.
+ */
+findstackframe()
+{
+ char *panicstr, buf[256];
+ register struct frame *fp;
+ caddr_t addr;
+ register char *cp;
+ int mask;
+
+ if (lookup("_panicstr") == 0)
+ return;
+ lseek(fcor, KVTOPH(cursym->n_value), L_SET);
+ read(fcor, &panicstr, sizeof (panicstr));
+ if (panicstr == 0)
+ return;
+ lseek(fcor, KVTOPH((off_t)panicstr), L_SET);
+ read(fcor, buf, sizeof (buf));
+ for (cp = buf; cp < &buf[sizeof (buf)] && *cp; cp++)
+ if (!isascii(*cp) || (!isprint(*cp) && !isspace(*cp)))
+ *cp = '?';
+ if (*cp)
+ *cp = '\0';
+ printf("panic: %s\n", buf);
+ /*
+ * After a panic, look at the top of the rpb stack to
+ * find a stack frame. If this was a clean crash,
+ * i.e. one which left the interrupt and kernel stacks
+ * in a reasonable state, then we should find a pointer
+ * to the proper stack frame here (at location scb-4).
+ * If we don't find a reasonable frame here, then we
+ * must search down through the interrupt stack.
+ */
+ intstack = lookup("_intstack")->n_value;
+#define NISP 3 /* from locore.s */
+ eintstack = intstack + NISP*NBPG;
+ rpb = lookup("_rpb")->n_value;
+ scb = lookup("_scb")->n_value;
+ lookup("_u");
+ ustack = cursym->n_value + (int)&((struct user *)0)->u_stack[0];
+ eustack = cursym->n_value + ctob(UPAGES);
+ physrw(fcor, KVTOPH((int)scb - sizeof (caddr_t)), &addr, 1);
+ fp = getframe(fcor, addr);
+ if (fp == 0)
+ fp = checkintstack();
+ /* search kernel stack? */
+ if (fp == 0) {
+ printf("can't locate stack frame\n");
+ return;
+ }
+ /* probably shouldn't clobber pcb, but for now this is easy */
+ pcb.pcb_fp = addr;
+ pcb.pcb_pc = fp->fr_savpc;
+ pcb.pcb_ap = addr + sizeof (struct frame) + fp->fr_spa;
+ for (mask = fp->fr_mask; mask; mask >>= 1)
+ if (mask & 01)
+ pcb.pcb_ap += sizeof (caddr_t);
+}
+
+/*
+ * Search interrupt stack for a valid frame.
+ */
+struct frame *
+checkintstack(fcor)
+{
+ char stack[NISP*NBPG];
+ off_t off = vtophys(intstack);
+ struct frame *fp;
+ register caddr_t addr;
+
+ if (off == -1 || lseek(fcor, off, L_SET) != off ||
+ read(fcor, stack, sizeof (stack)) != sizeof (stack))
+ return ((struct frame *)0);
+ addr = eintstack;
+ do {
+ addr -= sizeof (caddr_t);
+ fp = (struct frame *)&stack[addr - intstack];
+ } while (addr >= intstack + sizeof (struct frame) &&
+ !checkframe(fp));
+ return (addr < intstack+sizeof (struct frame) ? (struct frame *)0 : fp);
+}
+
+/*
+ * Get a stack frame and verify it looks like
+ * something which might be on a kernel stack.
+ */
+struct frame *
+getframe(fcor, fp)
+ int fcor;
+ caddr_t fp;
+{
+ static struct frame frame;
+ off_t off;
+
+ if (!kstackaddr(fp) || (off = vtophys(fp)) == -1)
+ return ((struct frame *)0);
+ if (lseek(fcor, off, L_SET) != off ||
+ read(fcor, &frame, sizeof (frame)) != sizeof (frame))
+ return ((struct frame *)0);
+ if (!checkframe(&frame))
+ return ((struct frame *)0);
+ return (&frame);
+}
+
+/*
+ * Check a call frame to see if it's ok as
+ * a kernel stack frame.
+ */
+checkframe(fp)
+ register struct frame *fp;
+{
+
+ if (fp->fr_handler != 0 || fp->fr_s == 0)
+ return (0);
+ if (!kstackaddr(fp->fr_savap) || !kstackaddr(fp->fr_savfp))
+ return (0);
+ return (within(fp->fr_savpc, txtmap.b1, txtmap.e1));
+}
+
+/*
+ * Check if an address is in one of the kernel's stacks:
+ * interrupt stack, rpb stack (during restart sequence),
+ * or u. stack.
+ */
+kstackaddr(addr)
+ caddr_t addr;
+{
+
+ return (within(addr, intstack, eintstack) ||
+ within(addr, rpb + sizeof (struct rpb), scb) ||
+ within(addr, ustack, eustack));
+}
+