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