Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
22
usage(void)
23
{
24
	fprint(2, "usage: ktrace [-i] kernel pc sp [link]\n");
25
	exits("usage");
26
}
27
 
28
static void
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
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
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
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
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
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
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
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
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
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
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
}