Commit | Line | Data |
---|---|---|
2222b6d9 KB |
1 | #ifndef lint |
2 | static 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 | ||
16 | struct pte *sbr; | |
17 | int slr; | |
18 | struct pcb pcb; | |
19 | ||
20 | static caddr_t rpb; | |
21 | static caddr_t scb; | |
22 | static caddr_t intstack, eintstack; | |
23 | static caddr_t ustack, eustack; | |
24 | ||
25 | char *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 | */ | |
48 | getkcore() { | |
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 | */ | |
71 | static caddr_t | |
72 | xlookup(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 | */ | |
90 | findstackframe() | |
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 | */ | |
143 | checkintstack(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 | */ | |
173 | getframe(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 | */ | |
193 | goodframe(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 | } |