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