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