]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ktrace.c
merge
[plan9front.git] / sys / src / cmd / ktrace.c
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 }