BSD 4_4 release
[unix-history] / usr / src / old / adb / adb.tahoe / kstack.c
CommitLineData
6f7a3ac3
KB
1/*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
ad787160
C
5 * This module is believed to contain source code proprietary to AT&T.
6 * Use and redistribution is subject to the Berkeley Software License
7 * Agreement and your Software Agreement with AT&T (Western Electric).
6f7a3ac3
KB
8 */
9
f582ecdc 10#ifndef lint
ad787160 11static char sccsid[] = "@(#)kstack.c 5.4 (Berkeley) 4/4/91";
6f7a3ac3 12#endif /* not lint */
f582ecdc
KB
13
14/*
15 * adb - routines to probe the kernel stack when debugging post-mortem
16 * crash dumps.
17 */
18
19#include "defs.h"
20#include <ctype.h>
21#include <machine/pte.h>
22#include <machine/frame.h>
71a2bd59 23#include <tahoe/tahoe/rpb.h>
f582ecdc
KB
24
25struct pte *sbr;
26int slr;
27struct pcb pcb;
28
29static caddr_t rpb, erpb;
30static caddr_t intstack, eintstack;
31static caddr_t ustack, eustack;
32
33char *malloc();
34
35/*
36 * Convert a kernel virtual address to an (off_t) physical offset.
37 */
38#define kvtooff(a) ((off_t)(a) & ~KERNBASE)
39
40/*
41 * Check if an address is in one of the kernel's stacks:
42 * interrupt stack, rpb stack (during restart sequence),
43 * or u. stack.
44 */
45#define within(a, b, e) \
46 ((addr_t)(a) >= (addr_t)(b) && (addr_t)(a) < (addr_t)(e))
47#define kstackaddr(a) \
48 (within(a, intstack, eintstack) || \
49 within(a, rpb + sizeof(struct rpb), erpb) || \
50 within(a, ustack, eustack))
51
52/*
53 * Determine whether we are looking at a kernel core dump, and if so,
54 * set sbr and slr and the current pcb.
55 */
56getkcore() {
57 struct nlist *sm, *ss, *mp;
58
59 if ((sm = lookup("_Sysmap")) == NULL ||
60 (ss = lookup("_Syssize")) == NULL ||
61 (mp = lookup("_masterpaddr")) == NULL)
62 return (0); /* a.out is not a vmunix */
63 datmap.m1.b = 0;
64 datmap.m1.e = -1L;
65 /* must set sbr, slr before setpcb() */
66 sbr = (struct pte *)sm->n_value;
67 slr = ss->n_value;
68 adbprintf("sbr %X slr %X\n", sbr, slr);
69 setpcb((addr_t)mp->n_value);
70 getpcb();
71 findstackframe();
72 return (1);
73}
74
75/*
76 * A version of lookup that never returns failure, and which returns
77 * the n_value field of the symbol found.
78 */
79static caddr_t
80xlookup(sym)
81 char *sym;
82{
83 struct nlist *sp;
84
85 if ((sp = lookup(sym)) == NULL) {
86 adbprintf("symbol %s not found ... bad kernel core?\n", sym);
87 exit(1);
88 }
89 return ((caddr_t)sp->n_value);
90}
91
92/*
93 * Find the current stack frame when debugging the kernel.
94 * If we're looking at a crash dump and this was not a ``clean''
95 * crash, then we must search the interrupt stack carefully
96 * looking for a valid frame.
97 */
98findstackframe()
99{
100 register char *cp;
101 register int n;
102 caddr_t addr;
103 struct frame fr;
104 char buf[256];
105
106 if (readcore(kvtooff(xlookup("_panicstr")), (caddr_t)&addr,
107 sizeof(addr)) != sizeof(addr) || addr == 0)
108 return;
109 n = readcore(kvtooff(addr), buf, sizeof(buf));
110 for (cp = buf; --n > 0 && *cp != 0; cp++)
111 if (!isascii(*cp) || (!isprint(*cp) && !isspace(*cp)))
112 *cp = '?';
113 *cp = '\0';
114 adbprintf("panic: %s\n", buf);
115
116 /*
117 * After a panic, look at the top of the rpb stack to find a stack
118 * frame. If this was a clean crash, i.e. one which left the
119 * interrupt and kernel stacks in a reasonable state, then we should
120 * find a pointer to the proper stack frame here (at location
121 * intstack-8). If we don't find a reasonable frame here, then we
122 * must search down through the interrupt stack.
123 */
124 intstack = xlookup("_intstack");
125 eintstack = xlookup("_Xdoadump"); /* XXX */
126 rpb = xlookup("_rsstk"); /* XXX */
127 erpb = rpb + NBPG - 2 * sizeof(long);
128 ustack = xlookup("_u");
129 eustack = ustack + ctob(UPAGES);
130 ustack += (int)((struct user *)0)->u_stack;
131 (void) readcore(kvtooff(intstack - 8), (caddr_t)&addr, sizeof(addr));
132 if (!getframe(addr, &fr) && !checkintstack(&addr, &fr)) {
133 /* search kernel stack? */
134 prints("can't locate stack frame\n");
135 return;
136 }
137 /* probably shouldn't clobber pcb, but for now this is easy */
138 pcb.pcb_fp = (int)addr;
139 pcb.pcb_pc = fr.fr_savpc;
140}
141
142/*
143 * Search interrupt stack for a valid frame. Return 1 if found,
144 * also setting *addr to the kernel address of the frame, and *frame
145 * to the frame at that address.
146 */
147checkintstack(addr, frame)
148 caddr_t *addr;
149 struct frame *frame;
150{
151 register int ssize;
152 register char *stack;
153
154 ssize = eintstack - intstack;
155 if ((stack = malloc((u_int)ssize)) == NULL)
156 return (0);
157 if (readcore(kvtooff(intstack), stack, ssize) != ssize) {
158 free(stack);
159 return (0);
160 }
161 for (ssize -= sizeof(*frame); ssize >= 0; ssize -= 4) {
162 if (goodframe((struct frame *)&stack[ssize])) {
163 *addr = &intstack[ssize] + FRAMEOFF;
164 *frame = *(struct frame *)&stack[ssize];
165 free(stack);
166 return (1);
167 }
168 }
169 free(stack);
170 return (0);
171}
172
173/*
174 * Get a stack frame and verify that it looks like
175 * something which might be on a kernel stack. Return 1 if OK.
176 */
177getframe(addr, fp)
178 caddr_t addr;
179 struct frame *fp;
180{
181 off_t off;
182 char *err = NULL;
183
184 if (!kstackaddr(addr))
185 return (0);
186 off = vtophys((addr_t)(addr - FRAMEOFF), &err);
187 if (err || readcore(off, (caddr_t)fp, sizeof(*fp)) != sizeof(*fp))
188 return (0);
189 return (goodframe(fp));
190}
191
192/*
193 * Check a call frame to see if it's ok as a kernel stack frame.
194 * It should have its parent frame in the kernel stack, and should
195 * return to kernel code.
196 */
197goodframe(fr)
198 register struct frame *fr;
199{
200
201 return (kstackaddr(fr->fr_savfp) &&
202 within(fr->fr_savpc, txtmap.m1.b, txtmap.m1.e));
203}