2 #include "../port/lib.h"
6 #include "../port/error.h"
10 static Lock *machlocks;
12 typedef struct DTKChan DTKChan;
13 typedef struct DTKAux DTKAux;
26 prog(DTKChan *p, char *s)
31 dtcrun(p->ch, DTCSTOP);
34 s = dtclunpack(s, &c);
36 error("invalid program");
37 rc = dtcaddcl(p->ch, c);
61 static Dirtab dtracydir[] = {
62 "ctl", { Qctl, 0, 0 }, 0, 0660,
63 "prog", { Qprog, 0, 0 }, 0, 0660,
64 "buf", { Qbuf, 0, 0, }, 0, 0440,
65 "epid", { Qepid, 0, 0 }, 0, 0440,
66 "aggbuf", { Qaggbuf, 0, 0 }, 0, 0440,
74 static Cmdtab dtracyctlmsg[] = {
79 static DTKChan **dtktab;
85 if((uvlong)n >= ndtktab) return nil;
88 #define QIDPATH(q,e) ((q) + 1 << 8 | (e))
89 #define SLOT(q) ((vlong)((q).path >> 8) - 1)
90 #define FILE(q) ((int)(q).path & 0xff)
99 p = malloc(sizeof(DTKChan));
100 if(p == nil) error(Enomem);
101 for(i = 0; i < ndtktab; i++)
102 if(dtktab[i] == nil){
108 newtab = realloc(dtktab, (ndtktab + 1) * sizeof(DTKChan *));
109 if(newtab == nil) error(Enomem);
134 dtracyen = getconf("*dtracy") != nil;
135 if(!dtracyen) return;
136 machlocks = smalloc(sizeof(Lock) * conf.nmach);
141 dtracyattach(char *spec)
144 error("*dtracy= not set");
145 return devattach(L'Δ', spec);
149 dtracygen(Chan *c, char *, Dirtab *, int, int s, Dir *dp)
155 devdir(c, (Qid){Qdir, 0, QTDIR}, "#Δ", 0, eve, 0555, dp);
158 if(c->qid.path == Qdir){
159 if(s-- == 0) goto clone;
160 if(s-- == 0) goto probes;
161 if(s >= ndtktab) return -1;
162 if(dtklook(s) == nil) return 0;
163 sprint(up->genbuf, "%d", s);
164 devdir(c, (Qid){QIDPATH(s, Qdir), 0, QTDIR}, up->genbuf, 0, eve, DMDIR|0555, dp);
167 if(c->qid.path == Qclone){
169 strcpy(up->genbuf, "clone");
170 devdir(c, (Qid){Qclone, 0, QTFILE}, up->genbuf, 0, eve, 0444, dp);
173 if(c->qid.path == Qprobes){
175 strcpy(up->genbuf, "probes");
176 devdir(c, (Qid){Qprobes, 0, QTFILE}, up->genbuf, 0, eve, 0444, dp);
179 if(s >= nelem(dtracydir))
182 path = QIDPATH(SLOT(c->qid), 0);
183 devdir(c, (Qid){tab->qid.path|path, tab->qid.vers, tab->qid.type}, tab->name, tab->length, eve, tab->perm, dp);
188 dtracywalk(Chan *c, Chan *nc, char **name, int nname)
194 qunlock(&dtracylock);
197 rc = devwalk(c, nc, name, nname, nil, 0, dtracygen);
198 qunlock(&dtracylock);
204 dtracystat(Chan *c, uchar *dp, int n)
210 qunlock(&dtracylock);
213 rc = devstat(c, dp, n, nil, 0, dtracygen);
214 qunlock(&dtracylock);
220 dtracyopen(Chan *c, int omode)
227 qunlock(&dtracylock);
230 if(c->qid.path == Qclone){
231 if(!iseve()) error(Eperm);
233 c->qid.path = QIDPATH(p->idx, Qctl);
235 if(c->qid.path == Qprobes){
238 p = dtklook(SLOT(c->qid));
239 if(SLOT(c->qid) >= 0 && p == nil) error(Enonexist);
240 if(FILE(c->qid) != Qdir && !iseve()) error(Eperm);
242 ch = devopen(c, omode, nil, 0, dtracygen);
243 if(p != nil) p->ref++;
244 qunlock(&dtracylock);
246 ch->aux = smalloc(sizeof(DTKAux));
251 dtracyclose(Chan *ch)
258 p = dtklook(SLOT(ch->qid));
259 if(p != nil && --p->ref == 0)
261 qunlock(&dtracylock);
270 epidread(DTKAux *aux, DTChan *c, char *a, long n, vlong off)
281 for(e = c->enab; e != nil; e = e->channext)
282 fmtprint(&f, "%d %d %d %s\n", e->epid, e->gr->id, e->gr->reclen, e->prob->name);
283 aux->str = fmtstrflush(&f);
285 return readstr(off, a, n, aux->str);
289 lockedread(DTChan *c, void *a, long n, int(*readf)(DTChan *, void *, int))
294 qunlock(&dtracylock);
299 qunlock(&dtracylock);
305 handleread(DTChan *c, void *a, long n, int(*readf)(DTChan *, void *, int))
311 rc = lockedread(c, a, n, readf);
312 if(rc < 0) return -1;
314 tsleep(&up->sleep, return0, 0, 250);
317 for(i = 0; i < 3 && m < n/2; i++){
318 tsleep(&up->sleep, return0, 0, 50);
319 rc = lockedread(c, (uchar *)a + m, n - m, readf);
327 probesread(DTKAux *aux, char *a, long n, vlong off)
336 for(i = 0; i < nl; i++)
337 fmtprint(&f, "%s\n", l[i]->name);
339 aux->str = fmtstrflush(&f);
341 return readstr(off, a, n, aux->str);
345 dtracyread(Chan *c, void *a, long n, vlong off)
353 qunlock(&dtracylock);
356 if(SLOT(c->qid) == -1)
357 switch((int)c->qid.path){
359 rc = devdirread(c, a, n, nil, 0, dtracygen);
362 rc = probesread(c->aux, a, n, off);
367 p = dtklook(SLOT(c->qid));
368 if(p == nil) error(Enonexist);
369 switch(FILE(c->qid)){
371 rc = devdirread(c, a, n, nil, 0, dtracygen);
374 sprint(up->genbuf, "%d", p->idx);
375 rc = readstr(off, a, n, up->genbuf);
379 qunlock(&dtracylock);
381 return handleread(ch, a, n, dtcread);
384 qunlock(&dtracylock);
386 return handleread(ch, a, n, dtcaggread);
388 rc = epidread(c->aux, p->ch, a, n, off);
395 qunlock(&dtracylock);
401 dtracywrite(Chan *c, void *a, long n, vlong)
410 qunlock(&dtracylock);
413 if(SLOT(c->qid) == -1)
414 switch((int)c->qid.path){
420 p = dtklook(SLOT(c->qid));
421 if(p == nil) error(Enonexist);
422 switch(FILE(c->qid)){
432 ct = lookupcmd(cb, dtracyctlmsg, nelem(dtracyctlmsg));
434 case CMstop: dtcrun(p->ch, DTCSTOP); break;
435 case CMgo: dtcrun(p->ch, DTCGO); break;
463 qunlock(&dtracylock);
496 setmalloctag(v, getcallerpc(&n));
507 dtrealloc(void *v, ulong n)
511 setrealloctag(v, getcallerpc(&v));
519 i = dtmachlock(m->machno);
525 ilock(&machlocks[i]);
532 iunlock(&machlocks[i]);
544 return fastticks(nil);
552 return up != nil ? up->pid : 0;
558 extern int peek(char *, char *, int);
561 dtpeek(uvlong addr, void *buf, int len)
566 if(len == 0) return 0;
567 if(a != addr || a > -(uintptr)len || len < 0) return -1;
568 if(up == nil || up->privatemem || a >= KZERO) return -1;
569 return peek((void *)a, buf, len) > 0 ? -1 : 0;