]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ktrace.c
cwfs: fix listen filedescriptor leaks
[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 R_MAGIC:   /* arm64 */
113         case Q_MAGIC:   /* powerpc */
114         case N_MAGIC:   /* mips 4000 LE */
115         case L_MAGIC:   /* dec alpha */
116                 t = rtrace;
117                 break;
118         case X_MAGIC:   /* att dsp 3210 */
119                 sysfatal("can't ktrace %s", argv[0]);
120                 break;
121         default:
122                 fprint(2, "%s: warning: can't tell what type of stack %s uses; assuming it's %s\n",
123                         argv0, argv[0], argc == 4 ? "risc" : "cisc");
124                 break;
125         }
126         (*t)(pc, sp, link);
127         exits(0);
128 }
129
130 static void
131 inithdr(int fd)
132 {
133         seek(fd, 0, 0);
134         if(!crackhdr(fd, &fhdr))
135                 fatal("read text header");
136
137         if(syminit(fd, &fhdr) < 0)
138                 fatal("%r\n");
139 }
140
141 static int
142 rtrace(uvlong pc, uvlong sp, uvlong link)
143 {
144         Symbol s, f;
145         char buf[128];
146         uvlong oldpc;
147         int i;
148
149         i = 0;
150         while(findsym(pc, CTEXT, &s)) {
151                 if(pc == s.value)       /* at first instruction */
152                         f.value = 0;
153                 else if(findlocal(&s, FRAMENAME, &f) == 0)
154                         break;
155
156                 symoff(buf, sizeof buf, pc, CANY);
157                 fmt(buf, pc);
158
159                 oldpc = pc;
160                 if(s.type == 'L' || s.type == 'l' || pc <= s.value+mach->pcquant){
161                         if(link == 0)
162                                 fprint(2, "%s: need to supply a valid link register\n", argv0);
163                         pc = link;
164                 }else{
165                         pc = getval(sp);
166                         if(pc == 0)
167                                 break;
168                 }
169
170                 if(pc == 0 || (pc == oldpc && f.value == 0))
171                         break;
172
173                 sp += f.value;
174
175                 if(++i > 40)
176                         break;
177         }
178         return i;
179 }
180
181 static int
182 ctrace(uvlong pc, uvlong sp, uvlong link)
183 {
184         Symbol s;
185         char buf[128];
186         int found;
187         uvlong opc, moved;
188         long j;
189
190         USED(link);
191         j = 0;
192         opc = 0;
193         while(pc && opc != pc) {
194                 moved = pc2sp(pc);
195                 if (moved == ~0){
196                         print("pc2sp(%#.8llux) = -1 %r\n", pc);
197                         break;
198                 }
199                 found = findsym(pc, CTEXT, &s);
200                 if (!found){
201                         print("findsym fails\n");
202                         break;
203                 }
204                 symoff(buf, sizeof buf, pc, CANY);
205                 fmt(buf, pc);
206
207                 sp += moved;
208                 opc = pc;
209                 pc = getval(sp);
210                 if(pc == 0)
211                         break;
212                 sp += mach->szaddr;     /*assumes address size = stack width*/
213                 if(++j > 40)
214                         break;
215         }
216         return j;
217 }
218
219 static int
220 i386trace(uvlong pc, uvlong sp, uvlong link)
221 {
222         int i;
223         uvlong osp;
224         Symbol s, f;
225         char buf[128];
226
227         USED(link);
228         i = 0;
229         osp = 0;
230         while(findsym(pc, CTEXT, &s)) {
231
232                 symoff(buf, sizeof buf, pc, CANY);
233                 fmt(buf, pc);
234
235 //XXX           s.value &= ~(uintptr)0;
236                 if(pc != s.value) {     /* not at first instruction */
237                         if(findlocal(&s, FRAMENAME, &f) == 0)
238                                 break;
239                         sp += f.value-mach->szaddr;
240                 }else if(strcmp(s.name, "forkret") == 0){
241 //XXX
242                         print("//passing interrupt frame; last pc found at sp=%#llux\n", osp);
243
244                         sp +=  15 * mach->szaddr;               /* pop interrupt frame */
245                 }
246
247                 pc = getval(sp);
248 //XXX
249                 if(pc == 0 && strcmp(s.name, "forkret") == 0){
250                         sp += 3 * mach->szaddr;                 /* pop iret eip, cs, eflags */
251                         print("//guessing call through invalid pointer, try again at sp=%#llux\n", sp);
252                         s.name = "";
253                         pc = getval(sp);
254                 }
255                 if(pc == 0) {
256                         print("//didn't find pc at sp=%#llux, last pc found at sp=%#llux\n", sp, osp);
257                         break;
258                 }
259                 osp = sp;
260
261                 sp += mach->szaddr;
262 //XXX
263                 if(strcmp(s.name, "forkret") == 0)
264                         sp += 2 * mach->szaddr;                 /* pop iret cs, eflags */
265
266                 if(++i > 40)
267                         break;
268         }
269         return i;
270 }
271
272 static int
273 amd64trace(uvlong pc, uvlong sp, uvlong link)
274 {
275         int i, isintrr;
276         uvlong osp;
277         Symbol s, f;
278         char buf[128];
279
280         USED(link);
281         i = 0;
282         osp = 0;
283         while(findsym(pc, CTEXT, &s)) {
284
285                 symoff(buf, sizeof buf, pc, CANY);
286                 fmt(buf, pc);
287
288                 if(strcmp(s.name, "_intrr") == 0)
289                         isintrr = 1;
290                 else
291                         isintrr = 0;
292                 if(pc != s.value) {     /* not at first instruction */
293                         if(findlocal(&s, FRAMENAME, &f) == 0)
294                                 break;
295                         sp += f.value-mach->szaddr;
296                 }
297                 else if(isintrr){
298                         print("//passing interrupt frame; last pc found at sp=%#llux\n", osp);
299                         /*
300                          * Pop interrupt frame (ureg.h) up to the IP value.
301                          */
302                         sp += 19 * mach->szaddr;
303                 }
304
305                 pc = getval(sp);
306                 if(pc == 0 && isintrr){
307                         /*
308                          * Pop IP, CS and FLAGS to get to the SP.
309                          * The AMD64 aligns the interrupt stack on
310                          * a 16-byte boundary so have the get the
311                          * SP from the saved frame.
312                          */
313                         sp += 3 * mach->szaddr;
314                         print("//guessing call through invalid pointer; try again at sp=%#llux\n", sp);
315                         s.name = "";
316                         sp = getval(sp);
317                         pc = getval(sp);
318                 }
319                 if(pc == 0) {
320                         print("//didn't find pc at sp=%#llux, last pc found at sp=%#llux\n", sp, osp);
321                         break;
322                 }
323                 osp = sp;
324
325                 if(!isintrr)
326                         sp += mach->szaddr;
327
328                 if(++i > 40)
329                         break;
330         }
331         return i;
332 }
333
334 int naddr;
335 uvlong addr[1024];
336 uvlong val[1024];
337
338 static void
339 putval(uvlong a, uvlong v)
340 {
341         if(naddr < nelem(addr)){
342                 addr[naddr] = a;
343                 val[naddr] = v;
344                 naddr++;
345         }
346 }
347
348 static void
349 readstack(void)
350 {
351         Biobuf b;
352         char *p;
353         char *f[64];
354         int nf, i;
355
356         Binit(&b, 0, OREAD);
357         while(p=Brdline(&b, '\n')){
358                 p[Blinelen(&b)-1] = 0;
359                 nf = tokenize(p, f, nelem(f));
360                 for(i=0; i<nf; i++){
361                         if(p=strchr(f[i], '=')){
362                                 *p++ = 0;
363                                 putval(strtoull(f[i], 0, 16), strtoull(p, 0, 16));
364                         }
365                 }
366         }
367 }
368
369 static uvlong
370 getval(uvlong a)
371 {
372         char buf[256];
373         int i, n;
374         uvlong r, m;
375
376         if(interactive){
377                 print("// data at %#8.8llux? ", a);
378                 n = read(0, buf, sizeof(buf)-1);
379                 if(n <= 0)
380                         return 0;
381                 buf[n] = '\0';
382                 r = strtoull(buf, 0, 16);
383         }else{
384                 r = 0;
385                 switch(fhdr.magic){
386                 case S_MAGIC:
387                 case R_MAGIC:
388                         m = 0xffffffff00000000ULL;
389                         break;
390                 default:
391                         m = 0;
392                 }
393                 for(i=0; i<naddr; i++)
394                         if((addr[i]|m) == a)
395                                 r = val[i];
396         }
397         switch(fhdr.magic){
398         case S_MAGIC:
399         case R_MAGIC:
400                 r = (long)r;    // sign extend
401                 break;
402         }
403
404
405         return r;
406 }
407
408 static void
409 fatal(char *fmt, ...)
410 {
411         char buf[4096];
412         va_list arg;
413
414         va_start(arg, fmt);
415         vseprint(buf, buf+sizeof(buf), fmt, arg);
416         va_end(arg);
417         fprint(2, "ktrace: %s\n", buf);
418         exits(buf);
419 }