1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <mach.h>
5 #include <ctype.h>
6
7 static int rtrace(uvlong, uvlong, uvlong);
8 static int ctrace(uvlong, uvlong, uvlong);
9 static int i386trace(uvlong, uvlong, uvlong);
10 static int amd64trace(uvlong, uvlong, uvlong);
11 static uvlong getval(uvlong);
12 static void inithdr(int);
13 static void fatal(char*, ...);
14 static void readstack(void);
15
16 static Fhdr fhdr;
17 static int interactive;
18
19 #define FRAMENAME ".frame"
20
21 static void
usage(void)22 usage(void)
23 {
24 fprint(2, "usage: ktrace [-i] kernel pc sp [link]\n");
25 exits("usage");
26 }
27
28 static void
printaddr(char * addr,uvlong pc)29 printaddr(char *addr, uvlong pc)
30 {
31 int i;
32 char *p;
33
34 /*
35 * reformat the following.
36 *
37 * foo+1a1 -> src(foo+0x1a1);
38 * 10101010 -> src(0x10101010);
39 */
40
41 if(strlen(addr) == 8 && strchr(addr, '+') == nil){
42 for(i=0; i<8; i++)
43 if(!isxdigit(addr[i]))
44 break;
45 if(i == 8){
46 print("src(%#.8llux); // 0x%s\n", pc, addr);
47 return;
48 }
49 }
50
51 if(p=strchr(addr, '+')){
52 *p++ = 0;
53 print("src(%#.8llux); // %s+0x%s\n", pc, addr, p);
54 }else
55 print("src(%#.8llux); // %s\n", pc, addr);
56 }
57
58 static void (*fmt)(char*, uvlong) = printaddr;
59
60 void
main(int argc,char * argv[])61 main(int argc, char *argv[])
62 {
63 int (*t)(uvlong, uvlong, uvlong);
64 uvlong pc, sp, link;
65 int fd;
66
67 ARGBEGIN{
68 case 'i':
69 interactive++;
70 break;
71 default:
72 usage();
73 }ARGEND
74
75 link = 0;
76 t = ctrace;
77 switch(argc){
78 case 4:
79 t = rtrace;
80 link = strtoull(argv[3], 0, 16);
81 break;
82 case 3:
83 break;
84 default:
85 usage();
86 }
87 pc = strtoull(argv[1], 0, 16);
88 sp = strtoull(argv[2], 0, 16);
89 if(!interactive)
90 readstack();
91
92 fd = open(argv[0], OREAD);
93 if(fd < 0)
94 fatal("can't open %s: %r", argv[0]);
95 inithdr(fd);
96 switch(fhdr.magic){
97 case I_MAGIC: /* intel 386 */
98 t = i386trace;
99 break;
100 case S_MAGIC: /* amd64 */
101 t = amd64trace;
102 break;
103 case A_MAGIC: /* 68020 */
104 case J_MAGIC: /* intel 960 */
105 t = ctrace;
106 break;
107 case K_MAGIC: /* sparc */
108 case D_MAGIC: /* amd 29000 */
109 case V_MAGIC: /* mips 3000 */
110 case M_MAGIC: /* mips 4000 */
111 case E_MAGIC: /* arm 7-something */
112 case Q_MAGIC: /* powerpc */
113 case N_MAGIC: /* mips 4000 LE */
114 case L_MAGIC: /* dec alpha */
115 t = rtrace;
116 break;
117 case X_MAGIC: /* att dsp 3210 */
118 sysfatal("can't ktrace %s", argv[0]);
119 break;
120 default:
121 fprint(2, "%s: warning: can't tell what type of stack %s uses; assuming it's %s\n",
122 argv0, argv[0], argc == 4 ? "risc" : "cisc");
123 break;
124 }
125 (*t)(pc, sp, link);
126 exits(0);
127 }
128
129 static void
inithdr(int fd)130 inithdr(int fd)
131 {
132 seek(fd, 0, 0);
133 if(!crackhdr(fd, &fhdr))
134 fatal("read text header");
135
136 if(syminit(fd, &fhdr) < 0)
137 fatal("%r\n");
138 }
139
140 static int
rtrace(uvlong pc,uvlong sp,uvlong link)141 rtrace(uvlong pc, uvlong sp, uvlong link)
142 {
143 Symbol s, f;
144 char buf[128];
145 uvlong oldpc;
146 int i;
147
148 i = 0;
149 while(findsym(pc, CTEXT, &s)) {
150 if(pc == s.value) /* at first instruction */
151 f.value = 0;
152 else if(findlocal(&s, FRAMENAME, &f) == 0)
153 break;
154
155 symoff(buf, sizeof buf, pc, CANY);
156 fmt(buf, pc);
157
158 oldpc = pc;
159 if(s.type == 'L' || s.type == 'l' || pc <= s.value+mach->pcquant){
160 if(link == 0)
161 fprint(2, "%s: need to supply a valid link register\n", argv0);
162 pc = link;
163 }else{
164 pc = getval(sp);
165 if(pc == 0)
166 break;
167 }
168
169 if(pc == 0 || (pc == oldpc && f.value == 0))
170 break;
171
172 sp += f.value;
173
174 if(++i > 40)
175 break;
176 }
177 return i;
178 }
179
180 static int
ctrace(uvlong pc,uvlong sp,uvlong link)181 ctrace(uvlong pc, uvlong sp, uvlong link)
182 {
183 Symbol s;
184 char buf[128];
185 int found;
186 uvlong opc, moved;
187 long j;
188
189 USED(link);
190 j = 0;
191 opc = 0;
192 while(pc && opc != pc) {
193 moved = pc2sp(pc);
194 if (moved == ~0){
195 print("pc2sp(%#.8llux) = -1 %r\n", pc);
196 break;
197 }
198 found = findsym(pc, CTEXT, &s);
199 if (!found){
200 print("findsym fails\n");
201 break;
202 }
203 symoff(buf, sizeof buf, pc, CANY);
204 fmt(buf, pc);
205
206 sp += moved;
207 opc = pc;
208 pc = getval(sp);
209 if(pc == 0)
210 break;
211 sp += mach->szaddr; /*assumes address size = stack width*/
212 if(++j > 40)
213 break;
214 }
215 return j;
216 }
217
218 static int
i386trace(uvlong pc,uvlong sp,uvlong link)219 i386trace(uvlong pc, uvlong sp, uvlong link)
220 {
221 int i;
222 uvlong osp;
223 Symbol s, f;
224 char buf[128];
225
226 USED(link);
227 i = 0;
228 osp = 0;
229 while(findsym(pc, CTEXT, &s)) {
230
231 symoff(buf, sizeof buf, pc, CANY);
232 fmt(buf, pc);
233
234 //XXX s.value &= ~(uintptr)0;
235 if(pc != s.value) { /* not at first instruction */
236 if(findlocal(&s, FRAMENAME, &f) == 0)
237 break;
238 sp += f.value-mach->szaddr;
239 }else if(strcmp(s.name, "forkret") == 0){
240 //XXX
241 print("//passing interrupt frame; last pc found at sp=%#llux\n", osp);
242
243 sp += 15 * mach->szaddr; /* pop interrupt frame */
244 }
245
246 pc = getval(sp);
247 //XXX
248 if(pc == 0 && strcmp(s.name, "forkret") == 0){
249 sp += 3 * mach->szaddr; /* pop iret eip, cs, eflags */
250 print("//guessing call through invalid pointer, try again at sp=%#llux\n", sp);
251 s.name = "";
252 pc = getval(sp);
253 }
254 if(pc == 0) {
255 print("//didn't find pc at sp=%#llux, last pc found at sp=%#llux\n", sp, osp);
256 break;
257 }
258 osp = sp;
259
260 sp += mach->szaddr;
261 //XXX
262 if(strcmp(s.name, "forkret") == 0)
263 sp += 2 * mach->szaddr; /* pop iret cs, eflags */
264
265 if(++i > 40)
266 break;
267 }
268 return i;
269 }
270
271 static int
amd64trace(uvlong pc,uvlong sp,uvlong link)272 amd64trace(uvlong pc, uvlong sp, uvlong link)
273 {
274 int i, isintrr;
275 uvlong osp;
276 Symbol s, f;
277 char buf[128];
278
279 USED(link);
280 i = 0;
281 osp = 0;
282 while(findsym(pc, CTEXT, &s)) {
283
284 symoff(buf, sizeof buf, pc, CANY);
285 fmt(buf, pc);
286
287 if(strcmp(s.name, "_intrr") == 0)
288 isintrr = 1;
289 else
290 isintrr = 0;
291 if(pc != s.value) { /* not at first instruction */
292 if(findlocal(&s, FRAMENAME, &f) == 0)
293 break;
294 sp += f.value-mach->szaddr;
295 }
296 else if(isintrr){
297 print("//passing interrupt frame; last pc found at sp=%#llux\n", osp);
298 /*
299 * Pop interrupt frame (ureg.h) up to the IP value.
300 */
301 sp += 19 * mach->szaddr;
302 }
303
304 pc = getval(sp);
305 if(pc == 0 && isintrr){
306 /*
307 * Pop IP, CS and FLAGS to get to the SP.
308 * The AMD64 aligns the interrupt stack on
309 * a 16-byte boundary so have the get the
310 * SP from the saved frame.
311 */
312 sp += 3 * mach->szaddr;
313 print("//guessing call through invalid pointer; try again at sp=%#llux\n", sp);
314 s.name = "";
315 sp = getval(sp);
316 pc = getval(sp);
317 }
318 if(pc == 0) {
319 print("//didn't find pc at sp=%#llux, last pc found at sp=%#llux\n", sp, osp);
320 break;
321 }
322 osp = sp;
323
324 if(!isintrr)
325 sp += mach->szaddr;
326
327 if(++i > 40)
328 break;
329 }
330 return i;
331 }
332
333 int naddr;
334 uvlong addr[1024];
335 uvlong val[1024];
336
337 static void
putval(uvlong a,uvlong v)338 putval(uvlong a, uvlong v)
339 {
340 if(naddr < nelem(addr)){
341 addr[naddr] = a;
342 val[naddr] = v;
343 naddr++;
344 }
345 }
346
347 static void
readstack(void)348 readstack(void)
349 {
350 Biobuf b;
351 char *p;
352 char *f[64];
353 int nf, i;
354
355 Binit(&b, 0, OREAD);
356 while(p=Brdline(&b, '\n')){
357 p[Blinelen(&b)-1] = 0;
358 nf = tokenize(p, f, nelem(f));
359 for(i=0; i<nf; i++){
360 if(p=strchr(f[i], '=')){
361 *p++ = 0;
362 putval(strtoull(f[i], 0, 16), strtoull(p, 0, 16));
363 }
364 }
365 }
366 }
367
368 static uvlong
getval(uvlong a)369 getval(uvlong a)
370 {
371 char buf[256];
372 int i, n;
373 uvlong r;
374
375 if(interactive){
376 print("// data at %#8.8llux? ", a);
377 n = read(0, buf, sizeof(buf)-1);
378 if(n <= 0)
379 return 0;
380 buf[n] = '\0';
381 r = strtoull(buf, 0, 16);
382 }else{
383 r = 0;
384 for(i=0; i<naddr; i++)
385 if(addr[i] == a)
386 r = val[i];
387 }
388
389 return r;
390 }
391
392 static void
fatal(char * fmt,...)393 fatal(char *fmt, ...)
394 {
395 char buf[4096];
396 va_list arg;
397
398 va_start(arg, fmt);
399 vseprint(buf, buf+sizeof(buf), fmt, arg);
400 va_end(arg);
401 fprint(2, "ktrace: %s\n", buf);
402 exits(buf);
403 }
404