]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/dtracy/act.c
dtracy: get rid of DTName struct, support more than three parts in a probe name,...
[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 static char *
45 insertstars(char *n)
46 {
47         Fmt f;
48         int partlen;
49         
50         fmtstrinit(&f);
51         partlen = 0;
52         for(; *n != 0; n++){
53                 if(*n == ':'){
54                         if(partlen == 0)
55                                 fmtrune(&f, '*');
56                         partlen = 0;
57                 }else
58                         partlen++;
59                 fmtrune(&f, *n);
60         }
61         if(partlen == 0)
62                 fmtrune(&f, '*');
63         return fmtstrflush(&f);
64 }
65
66 void
67 clausebegin(void)
68 {
69         clause = emalloc(sizeof(Clause));
70         clause->id = nclauses;
71 }
72
73 void
74 addprobe(char *s)
75 {
76         clause->probs = erealloc(clause->probs, sizeof(char *) * (clause->nprob + 1));
77         clause->probs[clause->nprob++] = insertstars(s);
78 }
79
80 static char *aggtypes[] = {
81         [AGGCNT] "count",
82         [AGGMIN] "min",
83         [AGGMAX] "max",
84         [AGGSUM] "sum",
85         [AGGAVG] "avg",
86         [AGGSTD] "std",
87 };
88
89 int
90 aggtype(Symbol *s)
91 {
92         int i;
93
94         for(i = 0; i < nelem(aggtypes); i++)
95                 if(strcmp(s->name, aggtypes[i]) == 0)
96                         return i;
97         error("%s unknown aggregation type", s->name);
98         return 0;
99 }
100
101 void
102 addstat(int type, ...)
103 {
104         Stat *s;
105         va_list va;
106
107         clause->stats = erealloc(clause->stats, sizeof(Stat) * (clause->nstats + 1));
108         s = &clause->stats[clause->nstats++];
109         memset(s, 0, sizeof(Stat));
110         s->type = type;
111         va_start(va, type);
112         switch(type){
113         case STATEXPR:
114                 s->n = va_arg(va, Node *);
115                 break;
116         case STATPRINT:
117         case STATPRINTF:
118                 break;
119         case STATAGG:
120                 s->agg.name = va_arg(va, Symbol *);
121                 s->agg.key = va_arg(va, Node *);
122                 s->agg.type = aggtype(va_arg(va, Symbol *));
123                 s->agg.value = va_arg(va, Node *);
124                 if(s->agg.type == AGGCNT){
125                         if(s->agg.value != nil)
126                                 error("too many arguments for count()");
127                 }else{
128                         if(s->agg.value == nil)
129                                 error("need argument for %s()", aggtypes[s->agg.type]);
130                 }
131                 break;
132         default:
133                 sysfatal("addstat: unknown type %d", type);
134         }
135         va_end(va);
136 }
137
138 void
139 addarg(Node *n)
140 {
141         Stat *s;
142         
143         assert(clause->nstats > 0);
144         s = &clause->stats[clause->nstats - 1];
145         s->arg = erealloc(s->arg, sizeof(Node *) * (s->narg + 1));
146         s->arg[s->narg++] = n;
147 }
148
149 void
150 clauseend(void)
151 {
152         clauses = erealloc(clauses, sizeof(Clause) * (nclauses + 1));
153         clauses[nclauses++] = clause;
154 }
155
156 void
157 actgradd(DTActGr *a, DTAct b)
158 {
159         a->acts = erealloc(a->acts, sizeof(DTAct) * (a->nact + 1));
160         a->acts[a->nact++] = b;
161 }
162
163 void
164 addpred(DTExpr *e)
165 {
166         clause->pred = e;
167 }
168
169 static void
170 prepprintf(Node **arg, int narg, DTActGr *g, int *recoff)
171 {
172         char *fmt;
173         int n;
174         Fmt f;
175
176         if(narg <= 0) sysfatal("printf() needs an argument");
177         if((*arg)->type != OSTR) sysfatal("printf() format string must be a literal");
178         fmt = (*arg)->str;
179         fmtstrinit(&f);
180         n = 1;
181         for(; *fmt != 0; fmt++){
182                 fmtrune(&f, *fmt);
183                 if(*fmt != '%')
184                         continue;
185                 fmt++;
186         again:
187                 switch(*fmt){
188                 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
189                 case 'u': case '+': case '-': case ',': case '#': case ' ': case '.':
190                         fmtrune(&f, *fmt);
191                         fmt++;
192                         goto again;
193                 case 'x': case 'X': case 'o': case 'b': case 'd':
194                         if(n >= narg) sysfatal("printf() too few arguments");
195                         if(arg[n]->typ->type != TYPINT) sysfatal("print() %%%c with non-integer", *fmt);
196                         arg[n] = tracegen(arg[n], g, recoff);
197                         n++;
198                         fmtrune(&f, 'l');
199                         fmtrune(&f, 'l');
200                         fmtrune(&f, *fmt);
201                         break;
202                 case 's':
203                         if(n >= narg) sysfatal("printf() too few arguments");
204                         if(arg[n]->typ->type != TYPSTRING) sysfatal("print() %%s with non-string");
205                         arg[n] = tracegen(arg[n], g, recoff);
206                         n++;
207                         fmtrune(&f, *fmt);
208                         break;
209                 case 0: sysfatal("printf() missing verb");
210                 default: sysfatal("printf() unknown verb %%%c", *fmt);
211                 }
212         }
213         if(n < narg) sysfatal("printf() too many arguments");
214         (*arg)->str = fmtstrflush(&f);
215 }
216
217 int aggid;
218
219 int
220 allagg(Clause *c)
221 {
222         Stat *s;
223
224         for(s = c->stats; s < c->stats + c->nstats; s++)
225                 if(s->type != STATAGG)
226                         return 0;
227         return 1;
228 }
229
230 DTClause *
231 mkdtclause(Clause *c)
232 {
233         DTClause *d;
234         Stat *s;
235         int recoff, i;
236         Node *n;
237         
238         d = emalloc(sizeof(DTClause));
239         d->nprob = c->nprob;
240         d->probs = c->probs;
241         d->gr = emalloc(sizeof(DTActGr));
242         d->gr->pred = c->pred;
243         d->gr->id = c->id;
244         recoff = 12;
245         for(s = c->stats; s < c->stats + c->nstats; s++)
246                 switch(s->type){
247                 case STATEXPR:
248                         actgradd(d->gr, (DTAct){ACTTRACE, codegen(s->n), 0, noagg});
249                         break;
250                 case STATPRINT:
251                         for(i = 0; i < s->narg; i++)
252                                 s->arg[i] = tracegen(s->arg[i], d->gr, &recoff);
253                         break;
254                 case STATPRINTF:
255                         prepprintf(s->arg, s->narg, d->gr, &recoff);
256                         break;
257                 case STATAGG: {
258                         DTAgg agg = {.id = s->agg.type << 28 | 1 << 16 | aggid++};
259                         assert(dtaunpackid(&agg) >= 0);
260                         aggs = realloc(aggs, sizeof(Agg) * aggid);
261                         memset(&aggs[aggid-1], 0, sizeof(Agg));
262                         aggs[aggid-1].DTAgg = agg;
263                         aggs[aggid-1].name = strdup(s->agg.name == nil ? "" : s->agg.name->name);
264                         actgradd(d->gr, (DTAct){ACTAGGKEY, codegen(s->agg.key), 8, agg});
265                         n = s->agg.value;
266                         if(n == nil) n = node(ONUM, 0ULL);
267                         actgradd(d->gr, (DTAct){ACTAGGVAL, codegen(n), 8, agg});
268                         break;
269                 }
270                 }
271         if(allagg(c))
272                 actgradd(d->gr, (DTAct){ACTCANCEL, codegen(node(ONUM, 0)), 0, noagg});
273         return d;
274 }
275
276 void
277 packclauses(Fmt *f)
278 {
279         int i;
280         DTClause *d;
281         
282         for(i = 0; i < nclauses; i++){
283                 d = mkdtclause(clauses[i]);
284                 dtclpack(f, d);
285         }
286 }
287
288 /* epid lookup table, filled with info from the kernel */
289 Enab *enabtab[1024];
290
291 void
292 addepid(u32int epid, u32int cid, int reclen, char *p)
293 {
294         Enab *e, **ep;
295         
296         assert(cid < nclauses);
297         assert((uint)reclen >= 12);
298         e = emalloc(sizeof(Enab));
299         e->epid = epid;
300         e->cl = clauses[cid];
301         e->reclen = reclen;
302         e->probe = strdup(p);
303         ep = &enabtab[epid % nelem(enabtab)];
304         e->next = *ep;
305         *ep = e;
306 }
307
308 Enab *
309 epidlookup(u32int epid)
310 {
311         Enab *e;
312         
313         for(e = enabtab[epid % nelem(enabtab)]; e != nil; e = e->next)
314                 if(e->epid == epid)
315                         return e;
316         return nil;
317 }
318
319 uchar *
320 unpack(uchar *p, uchar *e, char *fmt, ...)
321 {
322         va_list va;
323         u64int vl;
324         
325         va_start(va, fmt);
326         for(;;)
327                 switch(*fmt++){
328                 case 'c':
329                         if(p + 1 > e) return nil;
330                         *va_arg(va, u8int *) = p[0];
331                         p += 1;
332                         break;
333                 case 's':
334                         if(p + 2 > e) return nil;
335                         *va_arg(va, u16int *) = p[0] | p[1] << 8;
336                         p += 2;
337                         break;
338                 case 'i':
339                         if(p + 4 > e) return nil;
340                         *va_arg(va, u32int *) = p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
341                         p += 4;
342                         break;
343                 case 'v':
344                         if(p + 8 > e) return nil;
345                         vl = p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
346                         vl |= (uvlong)p[4] << 32 | (uvlong)p[5] << 40 | (uvlong)p[6] << 48 | (uvlong)p[7] << 56;
347                         *va_arg(va, u64int *) = vl;
348                         p += 8;
349                         break;
350                 case 0:
351                         return p;
352                 default:
353                         abort();
354                 }
355 }
356
357 static Val
358 receval(Node *n, uchar *p, uchar *e, Enab *en)
359 {
360         u8int c;
361         u16int s;
362         u32int i;
363         uvlong v;
364         char *sp;
365         uchar *q;
366         Val a, b;
367
368         switch(n->type){
369         case OSYM:
370                 switch(n->sym->type){
371                 case SYMVAR:
372                         switch(n->sym->idx){
373                         case DTV_TIME:
374                                 q = unpack(p + 4, e, "v", &v);
375                                 assert(q != nil);
376                                 return mkval(VALINT, v);
377                         case DTV_PROBE:
378                                 return mkval(VALSTR, en->probe);
379                         default: sysfatal("receval: unknown variable %d", n->type); return mkval(VALINT, 0LL);
380                         }
381                         break;
382                 default: sysfatal("receval: unknown symbol type %d", n->type); return mkval(VALINT, 0LL);
383                 }
384         case ONUM: return mkval(VALINT, n->num);
385         case OBIN:
386                 a = receval(n->n1, p, e, en);
387                 b = receval(n->n2, p, e, en);
388                 assert(a.type == VALINT);
389                 assert(b.type == VALINT);
390                 return mkval(VALINT, evalop(n->op, n->typ->sign, a.v, b.v));
391         case OLNOT:
392                 a = receval(n->n1, p, e, en);
393                 assert(a.type == VALINT);
394                 return mkval(VALINT, (uvlong) !a.v);
395         case OTERN:
396                 a = receval(n->n1, p, e, en);
397                 assert(a.type == VALINT);
398                 return a.v ? receval(n->n2, p, e, en) : receval(n->n3, p, e, en);
399         case ORECORD:
400                 switch(n->typ->type){
401                 case TYPINT:
402                         switch(n->typ->size){
403                         case 1: q = unpack(p + n->num, e, "c", &c); v = n->typ->sign ? (s8int)c : (u8int)c; break;
404                         case 2: q = unpack(p + n->num, e, "s", &s); v = n->typ->sign ? (s16int)s : (u16int)s; break;
405                         case 4: q = unpack(p + n->num, e, "i", &i); v = n->typ->sign ? (s32int)i : (u32int)i; break;
406                         case 8: q = unpack(p + n->num, e, "v", &v); break;
407                         default: q = nil;
408                         }
409                         assert(q != nil);
410                         return mkval(VALINT, v);
411                 case TYPSTRING:
412                         assert(p + n->num + n->typ->size <= e);
413                         sp = emalloc(n->typ->size + 1);
414                         memcpy(sp, p + n->num, n->typ->size);
415                         return mkval(VALSTR, sp); /* TODO: fix leak */
416                 default:
417                         sysfatal("receval: don't know how to parse record for %τ", n->typ);
418                 }
419         default:
420                 sysfatal("receval: unknown type %α", n->type);
421                 return mkval(VALINT, 0LL);
422         }
423 }
424
425 static void
426 execprintf(Node **arg, int narg, uchar *p, uchar *e, Enab *en)
427 {
428         char *x, *xp;
429         Val v;
430         int i;
431         
432         x = emalloc(sizeof(uvlong) * (narg - 1));
433         xp = x;
434         for(i = 0; i < narg - 1; i++){
435                 v = receval(arg[i + 1], p, e, en);
436                 switch(v.type){
437                 case VALINT:
438                         *(uvlong*)xp = v.v;
439                         xp += sizeof(uvlong);
440                         break;
441                 case VALSTR:
442                         *(char**)xp = v.s;
443                         xp += sizeof(char*);
444                         break;
445                 default: abort();
446                 }
447         }
448         vfprint(1, (*arg)->str, (va_list) x);
449         free(x);
450 }
451
452 int
453 parseclause(Clause *cl, uchar *p, uchar *e, Enab *en, Biobuf *bp)
454 {
455         Stat *s;
456         int i;
457         Val v;
458         
459         for(s = cl->stats; s < cl->stats + cl->nstats; s++)
460                 switch(s->type){
461                 case STATEXPR: break;
462                 case STATPRINT:
463                         for(i = 0; i < s->narg; i++){
464                                 v = receval(s->arg[i], p, e, en);
465                                 switch(v.type){
466                                 case VALINT:
467                                         Bprint(bp, "%lld", v.v);
468                                         break;
469                                 case VALSTR:
470                                         Bprint(bp, "%s", v.s);
471                                         break;
472                                 default: sysfatal("parseclause: unknown val type %d", s->type);
473                                 }
474                                 Bprint(bp, "%c", i == s->narg - 1 ? '\n' : ' ');
475                         }
476                         break;
477                 case STATPRINTF:
478                         execprintf(s->arg, s->narg, p, e, en);
479                         break;
480                 case STATAGG: break;
481                 default:
482                         sysfatal("parseclause: unknown type %d", s->type);
483                 }
484         return 0;
485 }
486
487 uchar *
488 parsefault(uchar *p0, uchar *e)
489 {
490         uchar *p;
491         u32int epid;
492         u8int type, dummy;
493         u16int n;
494         Enab *en;
495
496         p = unpack(p0, e, "csci", &type, &n, &dummy, &epid);
497         if(p == nil) return nil;
498         en = epidlookup(epid);
499         switch(type){
500         case DTFILL: {
501                 u32int pid;
502                 u64int addr;
503                 
504                 p = unpack(p, e, "iv", &pid, &addr);
505                 if(p == nil) return nil;
506                 fprint(2, "dtracy: illegal access: probe=%s, pid=%d, addr=%#llx\n", en != nil ? en->probe : nil, pid, addr);
507                 break;
508         }
509         default:
510                 fprint(2, "dtracy: unknown fault type %#.2ux\n", type);
511         }
512         return p0 + n - 12;
513 }
514
515 int
516 parsebuf(uchar *p, int n, Biobuf *bp)
517 {
518         uchar *e;
519         u32int epid;
520         u64int ts;
521         Enab *en;
522         
523         e = p + n;
524         while(p < e){
525                 p = unpack(p, e, "iv", &epid, &ts);
526                 if(p == nil) goto err;
527                 if(epid == (u32int)-1){
528                         p = parsefault(p, e);
529                         if(p == nil) goto err;
530                         continue;
531                 }
532                 en = epidlookup(epid);
533                 if(en == nil) goto err;
534                 if(parseclause(en->cl, p - 12, p + en->reclen - 12, en, bp) < 0) return -1;
535                 p += en->reclen - 12;
536         }
537         return 0;
538 err:
539         werrstr("buffer invalid");
540         return -1;
541 }
542
543 static void
544 dumpexpr(DTExpr *e, char *prefix)
545 {
546         int i;
547         
548         for(i = 0; i < e->n; i++)
549                 print("%s%.8ux %I\n", prefix, e->b[i], e->b[i]);
550 }
551
552 #pragma varargck type "ε" Node*
553
554 static void
555 fmtstring(Fmt *f, char *s)
556 {
557         fmtrune(f, '"');
558         for(; *s != 0; s++)
559                 switch(*s){
560                 case '\n': fmtprint(f, "\\n"); break;
561                 case '\r': fmtprint(f, "\\r"); break;
562                 case '\t': fmtprint(f, "\\t"); break;
563                 case '\v': fmtprint(f, "\\v"); break;
564                 case '\b': fmtprint(f, "\\b"); break;
565                 case '\a': fmtprint(f, "\\a"); break;
566                 case '"': fmtprint(f, "\""); break;
567                 case '\\': fmtprint(f, "\\"); break;
568                 default:
569                         if(*s < 0x20 || *s >= 0x7f)
570                                 fmtprint(f, "\\%.3o", (uchar)*s);
571                         else
572                                 fmtrune(f, *s);
573                 }
574         fmtrune(f, '"');
575 }
576
577 typedef struct Op Op;
578 struct Op {
579         char *name;
580         int pred;
581         enum { PRECRIGHT = 1 } flags;
582 };
583 static Op optab[] = {
584         [OPLOR] {"||", 3, 0},
585         [OPLAND] {"&&", 4, 0},
586         [OPOR] {"|", 5, 0},
587         [OPXNOR] {"~^", 6, 0},
588         [OPXOR] {"^", 6, 0},
589         [OPAND] {"&", 7, 0},
590         [OPEQ] {"==", 8, },
591         [OPNE] {"!=", 8, 0},
592         [OPLE] {"<=", 9, 0},
593         [OPLT] {"<", 9, 0},
594         [OPLSH] {"<<", 10, 0},
595         [OPRSH] {">>", 10, 0},
596         [OPADD] {"+", 11, 0},
597         [OPSUB] {"-", 11, 0},
598         [OPDIV] {"/", 12, 0},
599         [OPMOD] {"%", 12, 0},
600         [OPMUL] {"*", 12, 0},
601 };
602 enum { PREDUNARY = 14 };
603
604 int
605 nodefmt(Fmt *f)
606 {
607         Node *n;
608         Op *op;
609         int p;
610         
611         p = f->width;
612         n = va_arg(f->args, Node *);
613         switch(n->type){
614         case OSYM: fmtprint(f, "%s", n->sym->name); break;
615         case ONUM: fmtprint(f, "%lld", n->num); break;
616         case OSTR: fmtstring(f, n->str); break;
617         case OBIN:
618                 if(n->op >= nelem(optab) || optab[n->op].name == nil)
619                         fmtprint(f, "(%*ε ??op%d %*ε)", PREDUNARY, n->n1, n->op, PREDUNARY, n->n2);
620                 else{
621                         op = &optab[n->op];
622                         if(op->pred < p) fmtrune(f, '(');
623                         fmtprint(f, "%*ε %s %*ε", op->pred + (op->flags & PRECRIGHT), n->n1, op->name, op->pred + (~op->flags & PRECRIGHT), n->n2);
624                         if(op->pred < p) fmtrune(f, ')');
625                 }
626                 break;
627         case OLNOT: fmtprint(f, "!%*ε", PREDUNARY, n->n1); break;
628         case OTERN: fmtprint(f, "%2ε ? %1ε : %1ε", n->n1, n->n2, n->n3); break;
629         case ORECORD: fmtprint(f, "record(%ε, %τ, %d)", n->n1, n->typ, (int)n->num); break;
630         case OCAST: fmtprint(f, "(%τ) %*ε", n->typ, PREDUNARY, n->n1); break;
631         default: fmtprint(f, "??? %α", n->type);
632         }
633         return 0;
634 }
635
636 void
637 dump(void)
638 {
639         int i, j;
640         Stat *s;
641         Clause *c;
642         DTClause *d;
643         DTAct *a;
644         
645         for(i = 0; i < nclauses; i++){
646                 c = clauses[i];
647                 d = mkdtclause(c);
648                 print("clause %d:\n", c->id);
649                 for(j = 0; j < c->nprob; j++)
650                         print("\tprobe '%s'\n", c->probs[j]);
651                 print("\tkernel code:\n");
652                 if(c->pred == nil)
653                         print("\t\tno predicate\n");
654                 else{
655                         print("\t\tpredicate\n");
656                         dumpexpr(c->pred, "\t\t\t");
657                 }
658                 for(a = d->gr->acts; a < d->gr->acts + d->gr->nact; a++)
659                         switch(a->type){
660                         case ACTTRACE:
661                                 print("\t\ttrace (%d bytes)\n", a->size);
662                                 dumpexpr(a->p, "\t\t\t");
663                                 break;
664                         case ACTTRACESTR:
665                                 print("\t\ttrace string (%d bytes)\n", a->size);
666                                 dumpexpr(a->p, "\t\t\t");
667                                 break;
668                         case ACTAGGKEY:
669                                 print("\t\taggregation key (%s,%d,%d)\n", a->agg.type >= nelem(aggtypes) ? "???" : aggtypes[a->agg.type], a->agg.keysize, (u16int)a->agg.id);
670                                 dumpexpr(a->p, "\t\t\t");
671                                 break;
672                         case ACTAGGVAL:
673                                 print("\t\taggregation value (%s,%d,%d)\n", a->agg.type >= nelem(aggtypes) ? "???" : aggtypes[a->agg.type], a->agg.keysize, (u16int)a->agg.id);
674                                 dumpexpr(a->p, "\t\t\t");
675                                 break;
676                         case ACTCANCEL:
677                                 print("\t\tcancel record\n");
678                                 break;
679                         default:
680                                 print("\t\t??? %d\n", a->type);
681                         }
682                 print("\trecord formatting:\n");
683                 for(s = c->stats; s < c->stats + c->nstats; s++)
684                         switch(s->type){
685                         case STATEXPR:
686                                 break;
687                         case STATPRINT:
688                                 print("\t\tprint\n");
689                                 for(j = 0; j < s->narg; j++)
690                                         print("\t\t\targ %ε\n", s->arg[j]);
691                                 break;
692                         case STATPRINTF:
693                                 print("\t\tprintf\n");
694                                 for(j = 0; j < s->narg; j++)
695                                         print("\t\t\targ %ε\n", s->arg[j]);
696                                 break;
697                         case STATAGG:
698                                 break;
699                         default:
700                                 print("\t\t??? %d\n", s->type);
701                         }
702         }
703 }