]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/dtracy/act.c
adding dtracy (crude early version)
[plan9front.git] / sys / src / cmd / dtracy / act.c
1 #include <u.h>
2 #include <libc.h>
3 #include <ctype.h>
4 #include <dtracy.h>
5 #include <bio.h>
6 #include "dat.h"
7 #include "fns.h"
8
9 /* this contains the code to prepare the kernel data structures and to parse records */
10
11 Clause *clause;
12 Clause **clauses;
13 int nclauses;
14
15 /* we could just rely on the types in the expression tree but i'm paranoid */
16 typedef struct Val Val;
17 struct Val {
18         enum {
19                 VALINT,
20                 VALSTR,
21         } type;
22         union {
23                 vlong v;
24                 char *s;
25         };
26 };
27
28 Val
29 mkval(int type, ...)
30 {
31         Val r;
32         va_list va;
33         
34         r.type = type;
35         va_start(va, type);
36         switch(type){
37         case VALINT: r.v = va_arg(va, uvlong); break;
38         case VALSTR: r.s = va_arg(va, char*); break;
39         }
40         va_end(va);
41         return r;
42 }
43
44 void
45 clausebegin(void)
46 {
47         clause = emalloc(sizeof(Clause));
48         clause->id = nclauses;
49 }
50
51 void
52 addprobe(char *s)
53 {
54         clause->probs = erealloc(clause->probs, sizeof(char *) * (clause->nprob + 1));
55         clause->probs[clause->nprob++] = strdup(s);
56 }
57
58 void
59 addstat(int type, ...)
60 {
61         Stat *s;
62         va_list va;
63
64         clause->stats = erealloc(clause->stats, sizeof(Stat) * (clause->nstats + 1));
65         s = &clause->stats[clause->nstats++];
66         memset(s, 0, sizeof(Stat));
67         s->type = type;
68         va_start(va, type);
69         switch(type){
70         case STATEXPR:
71                 s->n = va_arg(va, Node *);
72                 break;
73         case STATPRINT:
74         case STATPRINTF:
75                 break;
76         default:
77                 sysfatal("addstat: unknown type %d", type);
78         }
79         va_end(va);
80 }
81
82 void
83 addarg(Node *n)
84 {
85         Stat *s;
86         
87         assert(clause->nstats > 0);
88         s = &clause->stats[clause->nstats - 1];
89         s->arg = erealloc(s->arg, sizeof(Node *) * (s->narg + 1));
90         s->arg[s->narg++] = n;
91 }
92
93 void
94 clauseend(void)
95 {
96         clauses = erealloc(clauses, sizeof(Clause) * (nclauses + 1));
97         clauses[nclauses++] = clause;
98 }
99
100 void
101 actgradd(DTActGr *a, DTAct b)
102 {
103         a->acts = erealloc(a->acts, sizeof(DTAct) * (a->nact + 1));
104         a->acts[a->nact++] = b;
105 }
106
107 void
108 addpred(DTExpr *e)
109 {
110         clause->pred = e;
111 }
112
113 static void
114 prepprintf(Node **arg, int narg, DTActGr *g, int *recoff)
115 {
116         char *fmt;
117         int n;
118         Fmt f;
119
120         if(narg <= 0) sysfatal("printf() needs an argument");
121         if((*arg)->type != OSTR) sysfatal("printf() format string must be a literal");
122         fmt = (*arg)->str;
123         fmtstrinit(&f);
124         n = 1;
125         for(; *fmt != 0; fmt++){
126                 fmtrune(&f, *fmt);
127                 if(*fmt != '%')
128                         continue;
129                 fmt++;
130         again:
131                 switch(*fmt){
132                 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
133                 case 'u': case '+': case '-': case ',': case '#': case ' ': case '.':
134                         fmtrune(&f, *fmt);
135                         fmt++;
136                         goto again;
137                 case 'x': case 'X': case 'o': case 'b': case 'd':
138                         if(n >= narg) sysfatal("printf() too few arguments");
139                         if(arg[n]->typ->type != TYPINT) sysfatal("print() %%%c with non-integer", *fmt);
140                         arg[n] = tracegen(arg[n], g, recoff);
141                         n++;
142                         fmtrune(&f, 'l');
143                         fmtrune(&f, 'l');
144                         fmtrune(&f, *fmt);
145                         break;
146                 case 's':
147                         if(n >= narg) sysfatal("printf() too few arguments");
148                         if(arg[n]->typ->type != TYPSTRING) sysfatal("print() %%s with non-string");
149                         arg[n] = tracegen(arg[n], g, recoff);
150                         n++;
151                         fmtrune(&f, *fmt);
152                         break;
153                 case 0: sysfatal("printf() missing verb");
154                 default: sysfatal("printf() unknown verb %%%c", *fmt);
155                 }
156         }
157         if(n < narg) sysfatal("printf() too many arguments");
158         (*arg)->str = fmtstrflush(&f);
159 }
160
161 DTClause *
162 mkdtclause(Clause *c)
163 {
164         DTClause *d;
165         Stat *s;
166         int recoff, i;
167         
168         d = emalloc(sizeof(DTClause));
169         d->nprob = c->nprob;
170         d->probs = c->probs;
171         d->gr = emalloc(sizeof(DTActGr));
172         d->gr->pred = c->pred;
173         d->gr->id = c->id;
174         recoff = 12;
175         for(s = c->stats; s < c->stats + c->nstats; s++)
176                 switch(s->type){
177                 case STATEXPR:
178                         actgradd(d->gr, (DTAct){ACTTRACE, codegen(s->n), 0});
179                         break;
180                 case STATPRINT:
181                         for(i = 0; i < s->narg; i++)
182                                 s->arg[i] = tracegen(s->arg[i], d->gr, &recoff);
183                         break;
184                 case STATPRINTF:
185                         prepprintf(s->arg, s->narg, d->gr, &recoff);
186                         break;
187                 }
188         return d;
189 }
190
191 void
192 packclauses(Fmt *f)
193 {
194         int i;
195         DTClause *d;
196         
197         for(i = 0; i < nclauses; i++){
198                 d = mkdtclause(clauses[i]);
199                 dtclpack(f, d);
200         }
201 }
202
203 /* epid lookup table, filled with info from the kernel */
204 Enab *enabtab[1024];
205
206 void
207 addepid(u32int epid, u32int cid, int reclen, char *p)
208 {
209         Enab *e, **ep;
210         
211         assert(cid < nclauses);
212         assert((uint)reclen >= 12);
213         e = emalloc(sizeof(Enab));
214         e->epid = epid;
215         e->cl = clauses[cid];
216         e->reclen = reclen;
217         e->probe = strdup(p);
218         ep = &enabtab[epid % nelem(enabtab)];
219         e->next = *ep;
220         *ep = e;
221 }
222
223 Enab *
224 epidlookup(u32int epid)
225 {
226         Enab *e;
227         
228         for(e = enabtab[epid % nelem(enabtab)]; e != nil; e = e->next)
229                 if(e->epid == epid)
230                         return e;
231         return nil;
232 }
233
234 uchar *
235 unpack(uchar *p, uchar *e, char *fmt, ...)
236 {
237         va_list va;
238         u64int vl;
239         
240         va_start(va, fmt);
241         for(;;)
242                 switch(*fmt++){
243                 case 'c':
244                         if(p + 1 > e) return nil;
245                         *va_arg(va, u8int *) = p[0];
246                         p += 1;
247                         break;
248                 case 's':
249                         if(p + 2 > e) return nil;
250                         *va_arg(va, u16int *) = p[0] | p[1] << 8;
251                         p += 2;
252                         break;
253                 case 'i':
254                         if(p + 4 > e) return nil;
255                         *va_arg(va, u32int *) = p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
256                         p += 4;
257                         break;
258                 case 'v':
259                         if(p + 8 > e) return nil;
260                         vl = p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
261                         vl |= (uvlong)p[4] << 32 | (uvlong)p[5] << 40 | (uvlong)p[6] << 48 | (uvlong)p[7] << 56;
262                         *va_arg(va, u64int *) = vl;
263                         p += 8;
264                         break;
265                 case 0:
266                         return p;
267                 default:
268                         abort();
269                 }
270 }
271
272 static Val
273 receval(Node *n, uchar *p, uchar *e, Enab *en)
274 {
275         u8int c;
276         u16int s;
277         u32int i;
278         uvlong v;
279         char *sp;
280         uchar *q;
281         Val a, b;
282
283         switch(n->type){
284         case OSYM:
285                 switch(n->sym->type){
286                 case SYMVAR:
287                         switch(n->sym->idx){
288                         case DTV_TIME:
289                                 q = unpack(p + 4, e, "v", &v);
290                                 assert(q != nil);
291                                 return mkval(VALINT, v);
292                         case DTV_PROBE:
293                                 return mkval(VALSTR, en->probe);
294                         default: sysfatal("receval: unknown variable %d", n->type); return mkval(VALINT, 0LL);
295                         }
296                         break;
297                 default: sysfatal("receval: unknown symbol type %d", n->type); return mkval(VALINT, 0LL);
298                 }
299         case ONUM: return mkval(VALINT, n->num);
300         case OBIN:
301                 a = receval(n->n1, p, e, en);
302                 b = receval(n->n2, p, e, en);
303                 assert(a.type == VALINT);
304                 assert(b.type == VALINT);
305                 return mkval(VALINT, evalop(n->op, n->typ->sign, a.v, b.v));
306         case OLNOT:
307                 a = receval(n->n1, p, e, en);
308                 assert(a.type == VALINT);
309                 return mkval(VALINT, (uvlong) !a.v);
310         case OTERN:
311                 a = receval(n->n1, p, e, en);
312                 assert(a.type == VALINT);
313                 return a.v ? receval(n->n2, p, e, en) : receval(n->n3, p, e, en);
314         case ORECORD:
315                 switch(n->typ->type){
316                 case TYPINT:
317                         switch(n->typ->size){
318                         case 1: q = unpack(p + n->num, e, "c", &c); v = n->typ->sign ? (s8int)c : (u8int)c; break;
319                         case 2: q = unpack(p + n->num, e, "s", &s); v = n->typ->sign ? (s16int)s : (u16int)s; break;
320                         case 4: q = unpack(p + n->num, e, "i", &i); v = n->typ->sign ? (s32int)i : (u32int)i; break;
321                         case 8: q = unpack(p + n->num, e, "v", &v); break;
322                         default: q = nil;
323                         }
324                         assert(q != nil);
325                         return mkval(VALINT, v);
326                 case TYPSTRING:
327                         assert(p + n->num + n->typ->size <= e);
328                         sp = emalloc(n->typ->size + 1);
329                         memcpy(sp, p + n->num, n->typ->size);
330                         return mkval(VALSTR, sp); /* TODO: fix leak */
331                 default:
332                         sysfatal("receval: don't know how to parse record for %τ", n->typ);
333                 }
334         default:
335                 sysfatal("receval: unknown type %α", n->type);
336                 return mkval(VALINT, 0LL);
337         }
338 }
339
340 static void
341 execprintf(Node **arg, int narg, uchar *p, uchar *e, Enab *en)
342 {
343         char *x, *xp;
344         Val v;
345         int i;
346         
347         x = emalloc(sizeof(uvlong) * (narg - 1));
348         xp = x;
349         for(i = 0; i < narg - 1; i++){
350                 v = receval(arg[i + 1], p, e, en);
351                 switch(v.type){
352                 case VALINT:
353                         *(uvlong*)xp = v.v;
354                         xp += sizeof(uvlong);
355                         break;
356                 case VALSTR:
357                         *(char**)xp = v.s;
358                         xp += sizeof(char*);
359                         break;
360                 default: abort();
361                 }
362         }
363         vfprint(1, (*arg)->str, (va_list) x);
364         free(x);
365 }
366
367 int
368 parseclause(Clause *cl, uchar *p, uchar *e, Enab *en, Biobuf *bp)
369 {
370         Stat *s;
371         int i;
372         Val v;
373         
374         for(s = cl->stats; s < cl->stats + cl->nstats; s++)
375                 switch(s->type){
376                 case STATEXPR: break;
377                 case STATPRINT:
378                         for(i = 0; i < s->narg; i++){
379                                 v = receval(s->arg[i], p, e, en);
380                                 switch(v.type){
381                                 case VALINT:
382                                         Bprint(bp, "%lld", v.v);
383                                         break;
384                                 case VALSTR:
385                                         Bprint(bp, "%s", v.s);
386                                         break;
387                                 default: sysfatal("parseclause: unknown val type %d", s->type);
388                                 }
389                                 Bprint(bp, "%c", i == s->narg - 1 ? '\n' : ' ');
390                         }
391                         break;
392                 case STATPRINTF:
393                         execprintf(s->arg, s->narg, p, e, en);
394                         break;
395                 default:
396                         sysfatal("parseclause: unknown type %d", s->type);
397                 }
398         return 0;
399 }
400
401 int
402 parsebuf(uchar *p, int n, Biobuf *bp)
403 {
404         uchar *e;
405         u32int epid;
406         u64int ts;
407         Enab *en;
408         
409         e = p + n;
410         while(p < e){
411                 p = unpack(p, e, "iv", &epid, &ts);
412                 if(p == nil) goto err;
413                 en = epidlookup(epid);
414                 if(en == nil) goto err;
415                 if(parseclause(en->cl, p - 12, p + en->reclen - 12, en, bp) < 0) return -1;
416                 p += en->reclen - 12;
417         }
418         return 0;
419 err:
420         werrstr("buffer invalid");
421         return -1;
422 }
423
424 static void
425 dumpexpr(DTExpr *e, char *prefix)
426 {
427         int i;
428         
429         for(i = 0; i < e->n; i++)
430                 print("%s%.8ux %I\n", prefix, e->b[i], e->b[i]);
431 }
432
433 #pragma varargck type "ε" Node*
434
435 static void
436 fmtstring(Fmt *f, char *s)
437 {
438         fmtrune(f, '"');
439         for(; *s != 0; s++)
440                 switch(*s){
441                 case '\n': fmtprint(f, "\\n"); break;
442                 case '\r': fmtprint(f, "\\r"); break;
443                 case '\t': fmtprint(f, "\\t"); break;
444                 case '\v': fmtprint(f, "\\v"); break;
445                 case '\b': fmtprint(f, "\\b"); break;
446                 case '\a': fmtprint(f, "\\a"); break;
447                 case '"': fmtprint(f, "\""); break;
448                 case '\\': fmtprint(f, "\\"); break;
449                 default:
450                         if(*s < 0x20 || *s >= 0x7f)
451                                 fmtprint(f, "\\%.3o", (uchar)*s);
452                         else
453                                 fmtrune(f, *s);
454                 }
455         fmtrune(f, '"');
456 }
457
458 typedef struct Op Op;
459 struct Op {
460         char *name;
461         int pred;
462         enum { PRECRIGHT = 1 } flags;
463 };
464 static Op optab[] = {
465         [OPLOR] {"||", 3, 0},
466         [OPLAND] {"&&", 4, 0},
467         [OPOR] {"|", 5, 0},
468         [OPXNOR] {"~^", 6, 0},
469         [OPXOR] {"^", 6, 0},
470         [OPAND] {"&", 7, 0},
471         [OPEQ] {"==", 8, },
472         [OPNE] {"!=", 8, 0},
473         [OPLE] {"<=", 9, 0},
474         [OPLT] {"<", 9, 0},
475         [OPLSH] {"<<", 10, 0},
476         [OPRSH] {">>", 10, 0},
477         [OPADD] {"+", 11, 0},
478         [OPSUB] {"-", 11, 0},
479         [OPDIV] {"/", 12, 0},
480         [OPMOD] {"%", 12, 0},
481         [OPMUL] {"*", 12, 0},
482 };
483 enum { PREDUNARY = 14 };
484
485 int
486 nodefmt(Fmt *f)
487 {
488         Node *n;
489         Op *op;
490         int p;
491         
492         p = f->width;
493         n = va_arg(f->args, Node *);
494         switch(n->type){
495         case OSYM: fmtprint(f, "%s", n->sym->name); break;
496         case ONUM: fmtprint(f, "%lld", n->num); break;
497         case OSTR: fmtstring(f, n->str); break;
498         case OBIN:
499                 if(n->op >= nelem(optab) || optab[n->op].name == nil)
500                         fmtprint(f, "(%*ε ??op%d %*ε)", PREDUNARY, n->n1, n->op, PREDUNARY, n->n2);
501                 else{
502                         op = &optab[n->op];
503                         if(op->pred < p) fmtrune(f, '(');
504                         fmtprint(f, "%*ε %s %*ε", op->pred + (op->flags & PRECRIGHT), n->n1, op->name, op->pred + (~op->flags & PRECRIGHT), n->n2);
505                         if(op->pred < p) fmtrune(f, ')');
506                 }
507                 break;
508         case OLNOT: fmtprint(f, "!%*ε", PREDUNARY, n->n1); break;
509         case OTERN: fmtprint(f, "%2ε ? %1ε : %1ε", n->n1, n->n2, n->n3); break;
510         case ORECORD: fmtprint(f, "record(%ε, %τ, %d)", n->n1, n->typ, (int)n->num); break;
511         case OCAST: fmtprint(f, "(%τ) %*ε", n->typ, PREDUNARY, n->n1); break;
512         default: fmtprint(f, "??? %α", n->type);
513         }
514         return 0;
515 }
516
517 void
518 dump(void)
519 {
520         int i, j;
521         Stat *s;
522         Clause *c;
523         DTClause *d;
524         DTAct *a;
525         
526         for(i = 0; i < nclauses; i++){
527                 c = clauses[i];
528                 d = mkdtclause(c);
529                 print("clause %d:\n", c->id);
530                 for(j = 0; j < c->nprob; j++)
531                         print("\tprobe '%s'\n", c->probs[j]);
532                 print("\tkernel code:\n");
533                 if(c->pred == nil)
534                         print("\t\tno predicate\n");
535                 else{
536                         print("\t\tpredicate\n");
537                         dumpexpr(c->pred, "\t\t\t");
538                 }
539                 for(a = d->gr->acts; a < d->gr->acts + d->gr->nact; a++)
540                         switch(a->type){
541                         case ACTTRACE:
542                                 print("\t\ttrace (%d bytes)\n", a->size);
543                                 dumpexpr(a->p, "\t\t\t");
544                                 break;
545                         case ACTTRACESTR:
546                                 print("\t\ttrace string (%d bytes)\n", a->size);
547                                 dumpexpr(a->p, "\t\t\t");
548                                 break;
549                         default:
550                                 print("\t\t??? %d\n", a->type);
551                         }
552                 print("\trecord formatting:\n");
553                 for(s = c->stats; s < c->stats + c->nstats; s++)
554                         switch(s->type){
555                         case STATEXPR:
556                                 break;
557                         case STATPRINT:
558                                 print("\t\tprint\n");
559                                 for(j = 0; j < s->narg; j++)
560                                         print("\t\t\targ %ε\n", s->arg[j]);
561                                 break;
562                         case STATPRINTF:
563                                 print("\t\tprintf\n");
564                                 for(j = 0; j < s->narg; j++)
565                                         print("\t\t\targ %ε\n", s->arg[j]);
566                                 break;
567                         default:
568                                 print("\t\t??? %d\n", s->type);
569                         }
570         }
571 }