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