xref: /plan9/sys/src/cmd/ktrace.c (revision 14cc0f535177405a84c5b73603a98e5db6674719)
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