changelog shortlog tags branches files raw gz bz2 help

Mercurial > hg > plan9front / changeset: adding dtracy (crude early version)

changeset 6877: 81f788b3708f
parent 6876: 12f6b6fbac27
child 6878: bbfa4ca306a8
author: aiju
date: Sat, 10 Nov 2018 13:46:16 +0000
files: sys/src/9/port/devdtracy.c sys/src/9/port/dtracysys.c sys/src/cmd/dtracy/act.c sys/src/cmd/dtracy/cgen.c sys/src/cmd/dtracy/dat.h sys/src/cmd/dtracy/dtracy.c sys/src/cmd/dtracy/fns.h sys/src/cmd/dtracy/lex.c sys/src/cmd/dtracy/lint.rc sys/src/cmd/dtracy/mkfile sys/src/cmd/dtracy/parse.y sys/src/cmd/dtracy/type.c sys/src/libdtracy/chan.c sys/src/libdtracy/dtefmt.c sys/src/libdtracy/mkfile sys/src/libdtracy/pack.c sys/src/libdtracy/prog.c sys/src/libdtracy/prov.c
description: adding dtracy (crude early version)
     1.1new file mode 100644
     1.2--- /dev/null
     1.3+++ b/sys/src/9/port/devdtracy.c
     1.4@@ -0,0 +1,530 @@
     1.5+#include	"u.h"
     1.6+#include	"../port/lib.h"
     1.7+#include	"mem.h"
     1.8+#include	"dat.h"
     1.9+#include	"fns.h"
    1.10+#include	"../port/error.h"
    1.11+
    1.12+#include	<dtracy.h>
    1.13+
    1.14+Lock *machlocks;
    1.15+
    1.16+typedef struct DTKChan DTKChan;
    1.17+typedef struct DTKAux DTKAux;
    1.18+QLock dtracylock;
    1.19+
    1.20+struct DTKChan {
    1.21+	DTChan *ch;
    1.22+	int ref;
    1.23+	int idx;
    1.24+};
    1.25+struct DTKAux {
    1.26+	char *str;
    1.27+};
    1.28+
    1.29+static void
    1.30+prog(DTKChan *p, char *s)
    1.31+{
    1.32+	DTClause *c;
    1.33+	int rc;
    1.34+
    1.35+	dtcrun(p->ch, DTCSTOP);
    1.36+	dtcreset(p->ch);
    1.37+	while(*s != 0){
    1.38+		s = dtclunpack(s, &c);
    1.39+		if(s == nil)
    1.40+			error("invalid program");
    1.41+		rc = dtcaddcl(p->ch, c);
    1.42+		dtclfree(c);
    1.43+		if(rc < 0){
    1.44+			dtcreset(p->ch);
    1.45+			error("failed to add clause");
    1.46+		}
    1.47+	}
    1.48+}
    1.49+
    1.50+enum {
    1.51+	/* Qdir */
    1.52+	Qclone = 1,
    1.53+};
    1.54+
    1.55+enum {
    1.56+	Qdir,
    1.57+	Qctl,
    1.58+	Qprog,
    1.59+	Qbuf,
    1.60+	Qepid,
    1.61+};
    1.62+
    1.63+static Dirtab dtracydir[] = {
    1.64+	"ctl",	{ Qctl, 0, 0 }, 0,	0660,
    1.65+	"prog", { Qprog, 0, 0 }, 0,	0660,
    1.66+	"buf",	{ Qbuf, 0, 0, }, 0,	0440,
    1.67+	"epid",	{ Qepid, 0, 0 }, 0,	0440,
    1.68+};
    1.69+
    1.70+enum {
    1.71+	CMstop,
    1.72+	CMgo,
    1.73+};
    1.74+
    1.75+static Cmdtab dtracyctlmsg[] = {
    1.76+	CMstop,		"stop",		1,
    1.77+	CMgo,		"go",		1,
    1.78+};
    1.79+
    1.80+DTKChan **dtktab;
    1.81+int ndtktab;
    1.82+
    1.83+static DTKChan *
    1.84+dtklook(vlong n)
    1.85+{
    1.86+	if((uvlong)n >= ndtktab) return nil;
    1.87+	return dtktab[n];
    1.88+}
    1.89+#define QIDPATH(q,e) ((q) + 1 << 8 | (e))
    1.90+#define SLOT(q) ((vlong)((q).path >> 8) - 1)
    1.91+#define FILE(q) ((int)(q).path & 0xff)
    1.92+
    1.93+static DTKChan *
    1.94+dtknew(void)
    1.95+{
    1.96+	DTKChan *p;
    1.97+	DTKChan **newtab;
    1.98+	int i;
    1.99+	
   1.100+	p = malloc(sizeof(DTKChan));
   1.101+	if(p == nil) error(Enomem);
   1.102+	for(i = 0; i < ndtktab; i++)
   1.103+		if(dtktab[i] == nil){
   1.104+			dtktab[i] = p;
   1.105+			p->idx = i;
   1.106+			break;
   1.107+		}
   1.108+	if(i == ndtktab){
   1.109+		newtab = realloc(dtktab, (ndtktab + 1) * sizeof(DTKChan *));
   1.110+		if(newtab == nil) error(Enomem);
   1.111+		dtktab = newtab;
   1.112+		dtktab[ndtktab] = p;
   1.113+		p->idx = ndtktab++;
   1.114+	}
   1.115+	p->ch = dtcnew();
   1.116+	return p;
   1.117+}
   1.118+
   1.119+static void
   1.120+dtkfree(DTKChan *p)
   1.121+{
   1.122+	int idx;
   1.123+	
   1.124+	idx = p->idx;
   1.125+	dtcfree(p->ch);
   1.126+	free(p);
   1.127+	dtktab[idx] = nil;
   1.128+}
   1.129+
   1.130+static void
   1.131+dtracyinit(void)
   1.132+{
   1.133+	machlocks = smalloc(sizeof(Lock) * conf.nmach);
   1.134+	dtinit(conf.nmach);
   1.135+}
   1.136+
   1.137+static Chan*
   1.138+dtracyattach(char *spec)
   1.139+{
   1.140+	return devattach(L'Δ', spec);
   1.141+}
   1.142+
   1.143+static int
   1.144+dtracygen(Chan *c, char *, Dirtab *, int, int s, Dir *dp)
   1.145+{
   1.146+	Dirtab *tab;
   1.147+	uvlong path;
   1.148+
   1.149+	if(s == DEVDOTDOT){
   1.150+		devdir(c, (Qid){Qdir, 0, QTDIR}, "#Δ", 0, eve, 0555, dp);
   1.151+		return 1;
   1.152+	}
   1.153+	if(c->qid.path == Qdir){
   1.154+		if(s-- == 0) goto clone;
   1.155+		if(s >= ndtktab) return -1;
   1.156+		if(dtklook(s) == nil) return 0;
   1.157+		sprint(up->genbuf, "%d", s);
   1.158+		devdir(c, (Qid){QIDPATH(s, Qdir), 0, QTDIR}, up->genbuf, 0, eve, DMDIR|0555, dp);
   1.159+		return 1;
   1.160+	}
   1.161+	if(c->qid.path == Qclone){
   1.162+	clone:
   1.163+		strcpy(up->genbuf, "clone");
   1.164+		devdir(c, (Qid){Qclone, 0, QTFILE}, up->genbuf, 0, eve, 0444, dp);
   1.165+		return 1;
   1.166+	}
   1.167+	if(s >= nelem(dtracydir))
   1.168+		return -1;
   1.169+	tab = &dtracydir[s];
   1.170+	path = QIDPATH(SLOT(c->qid), 0);
   1.171+	devdir(c, (Qid){tab->qid.path|path, tab->qid.vers, tab->qid.type}, tab->name, tab->length, eve, tab->perm, dp);
   1.172+	return 1;
   1.173+}
   1.174+
   1.175+static Walkqid*
   1.176+dtracywalk(Chan *c, Chan *nc, char **name, int nname)
   1.177+{
   1.178+	Walkqid *rc;
   1.179+
   1.180+	eqlock(&dtracylock);
   1.181+	if(waserror()){
   1.182+		qunlock(&dtracylock);
   1.183+		nexterror();
   1.184+	}
   1.185+	rc = devwalk(c, nc, name, nname, nil, 0, dtracygen);
   1.186+	qunlock(&dtracylock);
   1.187+	poperror();
   1.188+	return rc;
   1.189+}
   1.190+
   1.191+static int
   1.192+dtracystat(Chan *c, uchar *dp, int n)
   1.193+{
   1.194+	int rc;
   1.195+
   1.196+	eqlock(&dtracylock);
   1.197+	if(waserror()){
   1.198+		qunlock(&dtracylock);
   1.199+		nexterror();
   1.200+	}
   1.201+	rc = devstat(c, dp, n, nil, 0, dtracygen);
   1.202+	qunlock(&dtracylock);
   1.203+	poperror();
   1.204+	return rc;	
   1.205+}
   1.206+
   1.207+static Chan*
   1.208+dtracyopen(Chan *c, int omode)
   1.209+{
   1.210+	DTKChan *p;
   1.211+	Chan *ch;
   1.212+
   1.213+	eqlock(&dtracylock);
   1.214+	if(waserror()){
   1.215+		qunlock(&dtracylock);
   1.216+		nexterror();
   1.217+	}
   1.218+	if(c->qid.path == Qclone){
   1.219+		if(!iseve()) error(Eperm);
   1.220+		p = dtknew();
   1.221+		c->qid.path = QIDPATH(p->idx, Qctl);
   1.222+	}
   1.223+	p = dtklook(SLOT(c->qid));
   1.224+	if(SLOT(c->qid) >= 0 && p == nil) error(Enonexist);
   1.225+	if(FILE(c->qid) != Qdir && !iseve()) error(Eperm);
   1.226+	ch = devopen(c, omode, nil, 0, dtracygen);
   1.227+	if(p != nil) p->ref++;
   1.228+	qunlock(&dtracylock);
   1.229+	poperror();
   1.230+	ch->aux = smalloc(sizeof(DTKAux));
   1.231+	return ch;
   1.232+}
   1.233+
   1.234+static void
   1.235+dtracyclose(Chan *ch)
   1.236+{
   1.237+	DTKAux *aux;
   1.238+	DTKChan *p;
   1.239+
   1.240+	if(ch->aux != nil){
   1.241+		eqlock(&dtracylock);
   1.242+		p = dtklook(SLOT(ch->qid));
   1.243+		if(p != nil && --p->ref == 0)
   1.244+			dtkfree(p);
   1.245+		qunlock(&dtracylock);
   1.246+		aux = ch->aux;
   1.247+		free(aux->str);
   1.248+		free(ch->aux);
   1.249+		ch->aux = nil;
   1.250+	}
   1.251+}
   1.252+
   1.253+static int
   1.254+epidread(DTKAux *aux, DTChan *c, char *a, long n, vlong off)
   1.255+{
   1.256+	Fmt f;
   1.257+	DTEnab *e;
   1.258+
   1.259+	if(off == 0){
   1.260+		free(aux->str);
   1.261+		aux->str = nil;
   1.262+	}
   1.263+	if(aux->str == nil){
   1.264+		fmtstrinit(&f);
   1.265+		for(e = c->enab; e != nil; e = e->channext){
   1.266+			fmtprint(&f, "%d %d %d %s:%s:%s\n", e->epid, e->gr->id, e->gr->reclen,
   1.267+				e->prob->provider == nil ? "" : e->prob->provider,
   1.268+				e->prob->function == nil ? "" : e->prob->function,
   1.269+				e->prob->name == nil ? "" : e->prob->name);
   1.270+		}
   1.271+		aux->str = fmtstrflush(&f);
   1.272+	}
   1.273+	return readstr(off, a, n, aux->str);
   1.274+}
   1.275+
   1.276+static long
   1.277+dtracyread(Chan *c, void *a, long n, vlong off)
   1.278+{
   1.279+	int rc;
   1.280+	DTKChan *p;
   1.281+
   1.282+	eqlock(&dtracylock);
   1.283+	if(waserror()){
   1.284+		qunlock(&dtracylock);
   1.285+		nexterror();
   1.286+	}
   1.287+	if(SLOT(c->qid) == -1)
   1.288+		switch((int)c->qid.path){
   1.289+		case Qdir:
   1.290+			rc = devdirread(c, a, n, nil, 0, dtracygen);
   1.291+			goto out;
   1.292+		default:
   1.293+			error(Egreg);
   1.294+		}
   1.295+	p = dtklook(SLOT(c->qid));
   1.296+	if(p == nil) error(Enonexist);
   1.297+	switch(FILE(c->qid)){
   1.298+	case Qdir:
   1.299+		rc = devdirread(c, a, n, nil, 0, dtracygen);
   1.300+		break;
   1.301+	case Qctl:
   1.302+		sprint(up->genbuf, "%d", p->idx);
   1.303+		rc = readstr(off, a, n, up->genbuf);
   1.304+		break;
   1.305+	case Qbuf:
   1.306+		while(rc = dtcread(p->ch, a, n), rc == 0)
   1.307+			tsleep(&up->sleep, return0, 0, 250);
   1.308+		break;
   1.309+	case Qepid:
   1.310+		rc = epidread(c->aux, p->ch, a, n, off);
   1.311+		break;
   1.312+	default:
   1.313+		error(Egreg);
   1.314+		return 0;
   1.315+	}
   1.316+out:
   1.317+	qunlock(&dtracylock);
   1.318+	poperror();
   1.319+	return rc;
   1.320+}
   1.321+
   1.322+static long
   1.323+dtracywrite(Chan *c, void *a, long n, vlong)
   1.324+{
   1.325+	int rc;
   1.326+	DTKChan *p;
   1.327+	Cmdbuf *cb;
   1.328+	Cmdtab *ct;
   1.329+
   1.330+	eqlock(&dtracylock);
   1.331+	if(waserror()){
   1.332+		qunlock(&dtracylock);
   1.333+		nexterror();
   1.334+	}
   1.335+	if(SLOT(c->qid) == -1)
   1.336+		switch((int)c->qid.path){
   1.337+		case Qdir:
   1.338+			error(Eperm);
   1.339+		default:
   1.340+			error(Egreg);
   1.341+		}
   1.342+	p = dtklook(SLOT(c->qid));
   1.343+	if(p == nil) error(Enonexist);
   1.344+	switch(FILE(c->qid)){
   1.345+	case Qdir:
   1.346+		error(Eperm);
   1.347+		return 0;
   1.348+	case Qctl:
   1.349+		cb = parsecmd(a, n);
   1.350+		if(waserror()){
   1.351+			free(cb);
   1.352+			nexterror();
   1.353+		}
   1.354+		ct = lookupcmd(cb, dtracyctlmsg, nelem(dtracyctlmsg));
   1.355+		switch(ct->index){
   1.356+		case CMstop: dtcrun(p->ch, DTCSTOP); break;
   1.357+		case CMgo: dtcrun(p->ch, DTCGO); break;
   1.358+		default:
   1.359+			error(Egreg);
   1.360+		}
   1.361+		poperror();
   1.362+		free(cb);
   1.363+		rc = n;
   1.364+		break;
   1.365+	case Qprog:
   1.366+		{
   1.367+			char *buf;
   1.368+			
   1.369+			buf = smalloc(n+1);
   1.370+			if(waserror()){
   1.371+				free(buf);
   1.372+				nexterror();
   1.373+			}
   1.374+			memmove(buf, a, n);
   1.375+			prog(p, buf);
   1.376+			free(buf);
   1.377+			poperror();
   1.378+			rc = n;
   1.379+			break;
   1.380+		}
   1.381+	default:
   1.382+		error(Egreg);
   1.383+		return 0;
   1.384+	}
   1.385+	qunlock(&dtracylock);
   1.386+	poperror();
   1.387+	return rc;
   1.388+}
   1.389+
   1.390+
   1.391+Dev dtracydevtab = {
   1.392+	L'Δ',
   1.393+	"dtracy",
   1.394+	
   1.395+	devreset,
   1.396+	dtracyinit,
   1.397+	devshutdown,
   1.398+	dtracyattach,
   1.399+	dtracywalk,
   1.400+	dtracystat,
   1.401+	dtracyopen,
   1.402+	devcreate,
   1.403+	dtracyclose,
   1.404+	dtracyread,
   1.405+	devbread,
   1.406+	dtracywrite,
   1.407+	devbwrite,
   1.408+	devremove,
   1.409+	devwstat,
   1.410+};
   1.411+
   1.412+void *
   1.413+dtmalloc(ulong n)
   1.414+{
   1.415+	void *v;
   1.416+
   1.417+	v = smalloc(n);
   1.418+	setmalloctag(v, getcallerpc(&n));
   1.419+	return v;
   1.420+}
   1.421+
   1.422+void
   1.423+dtfree(void *v)
   1.424+{
   1.425+	free(v);
   1.426+}
   1.427+
   1.428+void *
   1.429+dtrealloc(void *v, ulong n)
   1.430+{
   1.431+	v = realloc(v, n);
   1.432+	if(v != nil)
   1.433+		setrealloctag(v, getcallerpc(&v));
   1.434+	return v;
   1.435+}
   1.436+
   1.437+void
   1.438+dtmachlock(int i)
   1.439+{
   1.440+	ilock(&machlocks[i]);
   1.441+}
   1.442+
   1.443+void
   1.444+dtmachunlock(int i)
   1.445+{
   1.446+	iunlock(&machlocks[i]);
   1.447+}
   1.448+
   1.449+void
   1.450+dtcoherence(void)
   1.451+{
   1.452+	coherence();
   1.453+}
   1.454+
   1.455+uvlong
   1.456+dttime(void)
   1.457+{
   1.458+	return fastticks(nil);
   1.459+}
   1.460+
   1.461+uvlong
   1.462+dtgetvar(int v)
   1.463+{
   1.464+	switch(v){
   1.465+	case DTV_PID:
   1.466+		return up != nil ? up->pid : 0;
   1.467+	case DTV_MACHNO:
   1.468+		return m->machno;
   1.469+	default:
   1.470+		return 0;
   1.471+	}
   1.472+}
   1.473+
   1.474+int
   1.475+dtpeek(uvlong addr, void *buf, int len)
   1.476+{
   1.477+	if((uintptr)addr != addr || up == nil || !okaddr((uintptr) addr, len, 0)) return -1;
   1.478+	memmove(buf, (void *) addr, len);
   1.479+	return 0;
   1.480+}
   1.481+
   1.482+static DTProbe *timerprobe;
   1.483+
   1.484+static void
   1.485+dtracytimer(void *)
   1.486+{
   1.487+	for(;;){
   1.488+		tsleep(&up->sleep, return0, nil, 1000);
   1.489+		dtptrigger(timerprobe, m->machno, 0, 0, 0, 0);
   1.490+	}
   1.491+}
   1.492+
   1.493+static void
   1.494+timerprovide(DTProvider *prov, DTName)
   1.495+{
   1.496+	static int provided;
   1.497+	
   1.498+	if(provided) return;
   1.499+	provided = 1;
   1.500+	timerprobe = dtpnew((DTName){"timer", "", "1s"}, prov, nil);
   1.501+}
   1.502+
   1.503+static int
   1.504+timerenable(DTProbe *)
   1.505+{
   1.506+	static int gotkproc;
   1.507+	
   1.508+	if(!gotkproc){
   1.509+		kproc("dtracytimer", dtracytimer, nil);
   1.510+		gotkproc=1;
   1.511+	}
   1.512+	return 0;
   1.513+}
   1.514+
   1.515+static void
   1.516+timerdisable(DTProbe *)
   1.517+{
   1.518+}
   1.519+
   1.520+DTProvider dtracyprov_timer = {
   1.521+	.name = "timer",
   1.522+	.provide = timerprovide,
   1.523+	.enable = timerenable,
   1.524+	.disable = timerdisable,
   1.525+};
   1.526+
   1.527+extern DTProvider dtracyprov_sys;
   1.528+
   1.529+DTProvider *dtproviders[] = {
   1.530+	&dtracyprov_timer,
   1.531+	&dtracyprov_sys,
   1.532+	nil,
   1.533+};
   1.534+
     2.1new file mode 100644
     2.2--- /dev/null
     2.3+++ b/sys/src/9/port/dtracysys.c
     2.4@@ -0,0 +1,249 @@
     2.5+#include	"u.h"
     2.6+#include	"../port/lib.h"
     2.7+#include	"mem.h"
     2.8+#include	"dat.h"
     2.9+#include	"fns.h"
    2.10+#include	"../port/error.h"
    2.11+
    2.12+#include "/sys/src/libc/9syscall/sys.h"
    2.13+
    2.14+#include	<dtracy.h>
    2.15+#include	<ctype.h>
    2.16+
    2.17+static DTProbe **dtpsysentry, **dtpsysreturn;
    2.18+
    2.19+typedef uintptr Syscall(va_list);
    2.20+extern Syscall *systab[];
    2.21+
    2.22+#define WRAP0(x,y,z)\
    2.23+	Syscall z; uintptr x(va_list va){\
    2.24+	uintptr rc;\
    2.25+	dtptrigger(dtpsysentry[y], m->machno, 0, 0, 0, 0);\
    2.26+	rc = z(va);\
    2.27+	dtptrigger(dtpsysreturn[y], m->machno, 0, 0, 0, 0);\
    2.28+	return rc;\
    2.29+}
    2.30+#define WRAP1(x,y,z,type0)\
    2.31+	Syscall z; uintptr x(va_list va){\
    2.32+	uintptr rc;\
    2.33+	va_list vb = va;\
    2.34+	type0 arg0 = va_arg(vb, type0);\
    2.35+	dtptrigger(dtpsysentry[y], m->machno, (uvlong)arg0, 0, 0, 0);\
    2.36+	rc = z(va);\
    2.37+	dtptrigger(dtpsysreturn[y], m->machno, (uvlong)arg0, 0, 0, 0);\
    2.38+	return rc;\
    2.39+}
    2.40+#define WRAP2(x,y,z,type0,type1)\
    2.41+	Syscall z; uintptr x(va_list va){\
    2.42+	uintptr rc;\
    2.43+	va_list vb = va;\
    2.44+	type0 arg0 = va_arg(vb, type0);\
    2.45+	type1 arg1 = va_arg(vb, type1);\
    2.46+	dtptrigger(dtpsysentry[y], m->machno, (uvlong)arg0, (uvlong)arg1, 0, 0);\
    2.47+	rc = z(va);\
    2.48+	dtptrigger(dtpsysreturn[y], m->machno, (uvlong)arg0, (uvlong)arg1, 0, 0);\
    2.49+	return rc;\
    2.50+}
    2.51+#define WRAP3(x,y,z,type0,type1,type2)\
    2.52+	Syscall z; uintptr x(va_list va){\
    2.53+	uintptr rc;\
    2.54+	va_list vb = va;\
    2.55+	type0 arg0 = va_arg(vb, type0);\
    2.56+	type1 arg1 = va_arg(vb, type1);\
    2.57+	type2 arg2 = va_arg(vb, type2);\
    2.58+	dtptrigger(dtpsysentry[y], m->machno, (uvlong)arg0, (uvlong)arg1, (uvlong)arg2, 0);\
    2.59+	rc = z(va);\
    2.60+	dtptrigger(dtpsysreturn[y], m->machno, (uvlong)arg0, (uvlong)arg1, (uvlong)arg2, 0);\
    2.61+	return rc;\
    2.62+}
    2.63+#define WRAP4(x,y,z,type0,type1,type2,type3)\
    2.64+	Syscall z; uintptr x(va_list va){\
    2.65+	uintptr rc;\
    2.66+	va_list vb = va;\
    2.67+	type0 arg0 = va_arg(vb, type0);\
    2.68+	type1 arg1 = va_arg(vb, type1);\
    2.69+	type2 arg2 = va_arg(vb, type2);\
    2.70+	type3 arg3 = va_arg(vb, type3);\
    2.71+	dtptrigger(dtpsysentry[y], m->machno, (uvlong)arg0, (uvlong)arg1, (uvlong)arg2, (uvlong)arg3);\
    2.72+	rc = z(va);\
    2.73+	dtptrigger(dtpsysreturn[y], m->machno, (uvlong)arg0, (uvlong)arg1, (uvlong)arg2, (uvlong)arg3);\
    2.74+	return rc;\
    2.75+}
    2.76+/*TODO*/
    2.77+#define WRAP5(x,y,z,type0,type1,type2,type3,type4)\
    2.78+	Syscall z; uintptr x(va_list va){\
    2.79+	uintptr rc;\
    2.80+	va_list vb = va;\
    2.81+	type0 arg0 = va_arg(vb, type0);\
    2.82+	type1 arg1 = va_arg(vb, type1);\
    2.83+	type2 arg2 = va_arg(vb, type2);\
    2.84+	type3 arg3 = va_arg(vb, type3);\
    2.85+	dtptrigger(dtpsysentry[y], m->machno, (uvlong)arg0, (uvlong)arg1, (uvlong)arg2, (uvlong)arg3);\
    2.86+	rc = z(va);\
    2.87+	dtptrigger(dtpsysreturn[y], m->machno, (uvlong)arg0, (uvlong)arg1, (uvlong)arg2, (uvlong)arg3);\
    2.88+	return rc;\
    2.89+}
    2.90+
    2.91+WRAP0(dtwrap_sysr1, SYSR1, sysr1)
    2.92+WRAP1(dtwrap_sys_errstr, _ERRSTR, sys_errstr, char*)
    2.93+WRAP3(dtwrap_sysbind, BIND, sysbind, char*, char*, int)
    2.94+WRAP1(dtwrap_syschdir, CHDIR, syschdir, char*)
    2.95+WRAP1(dtwrap_sysclose, CLOSE, sysclose, int)
    2.96+WRAP2(dtwrap_sysdup, DUP, sysdup, int, int)
    2.97+WRAP1(dtwrap_sysalarm, ALARM, sysalarm, ulong)
    2.98+WRAP2(dtwrap_sysexec, EXEC, sysexec, char *, char **)
    2.99+WRAP1(dtwrap_sysexits, EXITS, sysexits, char *)
   2.100+WRAP3(dtwrap_sys_fsession, _FSESSION, sys_fsession, int, char *, uint)
   2.101+WRAP2(dtwrap_sysfauth, FAUTH, sysfauth, int, char *)
   2.102+WRAP2(dtwrap_sys_fstat, _FSTAT, sys_fstat, int, uchar *)
   2.103+WRAP1(dtwrap_syssegbrk, SEGBRK, syssegbrk, void *)
   2.104+WRAP4(dtwrap_sys_mount, _MOUNT, sys_mount, int, char *, int, char *)
   2.105+WRAP2(dtwrap_sysopen, OPEN, sysopen, char *, int)
   2.106+WRAP3(dtwrap_sys_read, _READ, sys_read, int, void*, long)
   2.107+WRAP3(dtwrap_sysoseek, OSEEK, sysoseek, int, long, int)
   2.108+WRAP1(dtwrap_syssleep, SLEEP, syssleep, long)
   2.109+WRAP2(dtwrap_sys_stat, _STAT, sys_stat, char *, uchar *)
   2.110+WRAP1(dtwrap_sysrfork, RFORK, sysrfork, int)
   2.111+WRAP3(dtwrap_sys_write, _WRITE, sys_write, int, void *, long)
   2.112+WRAP1(dtwrap_syspipe, PIPE, syspipe, int*)
   2.113+WRAP3(dtwrap_syscreate, CREATE, syscreate, char*, int, int)
   2.114+WRAP3(dtwrap_sysfd2path, FD2PATH, sysfd2path, int, char*, uint)
   2.115+WRAP1(dtwrap_sysbrk_, BRK_, sysbrk_, uintptr)
   2.116+WRAP1(dtwrap_sysremove, REMOVE, sysremove, char *)
   2.117+WRAP0(dtwrap_sys_wstat, _WSTAT, sys_wstat)
   2.118+WRAP0(dtwrap_sys_fwstat, _FWSTAT, sys_fwstat)
   2.119+WRAP2(dtwrap_sysnotify, NOTIFY, sysnotify, char *, void *)
   2.120+WRAP1(dtwrap_sysnoted, NOTED, sysnoted, int)
   2.121+WRAP4(dtwrap_syssegattach, SEGATTACH, syssegattach, int, char *, uintptr, ulong)
   2.122+WRAP1(dtwrap_syssegdetach, SEGDETACH, syssegdetach, uintptr)
   2.123+WRAP2(dtwrap_syssegfree, SEGFREE, syssegfree, uintptr, ulong)
   2.124+WRAP2(dtwrap_syssegflush, SEGFLUSH, syssegflush, void*, ulong)
   2.125+WRAP2(dtwrap_sysrendezvous, RENDEZVOUS, sysrendezvous, uintptr, uintptr)
   2.126+WRAP2(dtwrap_sysunmount, UNMOUNT, sysunmount, char *, char *)
   2.127+WRAP1(dtwrap_sys_wait, _WAIT, sys_wait, void*)
   2.128+WRAP2(dtwrap_syssemacquire, SEMACQUIRE, syssemacquire, long*, int)
   2.129+WRAP2(dtwrap_syssemrelease, SEMRELEASE, syssemrelease, long*, long)
   2.130+WRAP4(dtwrap_sysfversion, FVERSION, sysfversion, int, int, char *, int)
   2.131+WRAP2(dtwrap_syserrstr, ERRSTR, syserrstr, char *, uint)
   2.132+WRAP3(dtwrap_sysstat, STAT, sysstat, char *, uchar *, uint)
   2.133+WRAP3(dtwrap_sysfstat, FSTAT, sysfstat, int, uchar *, uint)
   2.134+WRAP3(dtwrap_syswstat, WSTAT, syswstat, char *, uchar *, uint)
   2.135+WRAP3(dtwrap_sysfwstat, FWSTAT, sysfwstat, int, uchar *, uint)
   2.136+WRAP5(dtwrap_sysmount, MOUNT, sysmount, int, int, char *, int, char *)
   2.137+WRAP2(dtwrap_sysawait, AWAIT, sysawait, char *, uint)
   2.138+WRAP4(dtwrap_syspread, PREAD, syspread, int, void *, long, vlong)
   2.139+WRAP4(dtwrap_syspwrite, PWRITE, syspwrite, int, void *, long, vlong)
   2.140+WRAP2(dtwrap_systsemacquire, TSEMACQUIRE, systsemacquire, long *, ulong)
   2.141+
   2.142+
   2.143+/* TODO: amd64 */
   2.144+WRAP4(dtwrap_sysseek, SEEK, sysseek, vlong*, int, vlong, int)
   2.145+WRAP1(dtwrap_sys_nsec, _NSEC, sys_nsec, vlong*)
   2.146+
   2.147+static Syscall *wraptab[]={
   2.148+	[SYSR1]		dtwrap_sysr1,
   2.149+	[_ERRSTR]	dtwrap_sys_errstr,
   2.150+	[BIND]		dtwrap_sysbind,
   2.151+	[CHDIR]		dtwrap_syschdir,
   2.152+	[CLOSE]		dtwrap_sysclose,
   2.153+	[DUP]		dtwrap_sysdup,
   2.154+	[ALARM]		dtwrap_sysalarm,
   2.155+	[EXEC]		dtwrap_sysexec,
   2.156+	[EXITS]		dtwrap_sysexits,
   2.157+	[_FSESSION]	dtwrap_sys_fsession,
   2.158+	[FAUTH]		dtwrap_sysfauth,
   2.159+	[_FSTAT]	dtwrap_sys_fstat,
   2.160+	[SEGBRK]	dtwrap_syssegbrk,
   2.161+	[_MOUNT]	dtwrap_sys_mount,
   2.162+	[OPEN]		dtwrap_sysopen,
   2.163+	[_READ]		dtwrap_sys_read,
   2.164+	[OSEEK]		dtwrap_sysoseek,
   2.165+	[SLEEP]		dtwrap_syssleep,
   2.166+	[_STAT]		dtwrap_sys_stat,
   2.167+	[RFORK]		dtwrap_sysrfork,
   2.168+	[_WRITE]	dtwrap_sys_write,
   2.169+	[PIPE]		dtwrap_syspipe,
   2.170+	[CREATE]	dtwrap_syscreate,
   2.171+	[FD2PATH]	dtwrap_sysfd2path,
   2.172+	[BRK_]		dtwrap_sysbrk_,
   2.173+	[REMOVE]	dtwrap_sysremove,
   2.174+	[_WSTAT]	dtwrap_sys_wstat,
   2.175+	[_FWSTAT]	dtwrap_sys_fwstat,
   2.176+	[NOTIFY]	dtwrap_sysnotify,
   2.177+	[NOTED]		dtwrap_sysnoted,
   2.178+	[SEGATTACH]	dtwrap_syssegattach,
   2.179+	[SEGDETACH]	dtwrap_syssegdetach,
   2.180+	[SEGFREE]	dtwrap_syssegfree,
   2.181+	[SEGFLUSH]	dtwrap_syssegflush,
   2.182+	[RENDEZVOUS]	dtwrap_sysrendezvous,
   2.183+	[UNMOUNT]	dtwrap_sysunmount,
   2.184+	[_WAIT]		dtwrap_sys_wait,
   2.185+	[SEMACQUIRE]	dtwrap_syssemacquire,
   2.186+	[SEMRELEASE]	dtwrap_syssemrelease,
   2.187+	[SEEK]		dtwrap_sysseek,
   2.188+	[FVERSION]	dtwrap_sysfversion,
   2.189+	[ERRSTR]	dtwrap_syserrstr,
   2.190+	[STAT]		dtwrap_sysstat,
   2.191+	[FSTAT]		dtwrap_sysfstat,
   2.192+	[WSTAT]		dtwrap_syswstat,
   2.193+	[FWSTAT]	dtwrap_sysfwstat,
   2.194+	[MOUNT]		dtwrap_sysmount,
   2.195+	[AWAIT]		dtwrap_sysawait,
   2.196+	[PREAD]		dtwrap_syspread,
   2.197+	[PWRITE]	dtwrap_syspwrite,
   2.198+	[TSEMACQUIRE]	dtwrap_systsemacquire,
   2.199+	[_NSEC]		dtwrap_sys_nsec,
   2.200+};
   2.201+
   2.202+static void
   2.203+sysprovide(DTProvider *prov, DTName)
   2.204+{
   2.205+	static int provided;
   2.206+	char buf[32];
   2.207+	int i;
   2.208+	
   2.209+	if(provided) return;
   2.210+	provided = 1;
   2.211+	dtpsysentry = smalloc(sizeof(Syscall *) * nsyscall);
   2.212+	dtpsysreturn = smalloc(sizeof(Syscall *) * nsyscall);
   2.213+	for(i = 0; i < nsyscall; i++){
   2.214+		if(systab[i] == nil || sysctab[i] == nil) continue;
   2.215+		strecpy(buf, buf + sizeof(buf), sysctab[i]);
   2.216+		if(isupper(buf[0])) buf[0] += 'a' - 'A';
   2.217+		if(i == SYSR1) strcpy(buf, "r1");
   2.218+		dtpsysentry[i] = dtpnew((DTName){"sys", buf, "entry"}, prov, (void *) i);
   2.219+		dtpsysreturn[i] = dtpnew((DTName){"sys", buf, "return"}, prov, (void *) i);
   2.220+	}
   2.221+}
   2.222+
   2.223+static int
   2.224+sysenable(DTProbe *p)
   2.225+{
   2.226+	int i;
   2.227+	Syscall *z;
   2.228+	
   2.229+	i = (int) p->aux;
   2.230+	assert(i >= 0 && i < nsyscall);
   2.231+	if(dtpsysentry[i]->nenable + dtpsysreturn[i]->nenable == 0)
   2.232+		z = systab[i], systab[i] = wraptab[i], wraptab[i] = z;
   2.233+	return 0;
   2.234+}
   2.235+
   2.236+static void
   2.237+sysdisable(DTProbe *p)
   2.238+{
   2.239+	int i;
   2.240+	Syscall *z;
   2.241+	
   2.242+	i = (int) p->aux;
   2.243+	assert(i >= 0 && i < nsyscall);
   2.244+	if(dtpsysentry[i]->nenable + dtpsysreturn[i]->nenable == 0)
   2.245+		z = systab[i], systab[i] = wraptab[i], wraptab[i] = z;
   2.246+}
   2.247+
   2.248+DTProvider dtracyprov_sys = {
   2.249+	.name = "sys",
   2.250+	.provide = sysprovide,
   2.251+	.enable = sysenable,
   2.252+	.disable = sysdisable,
   2.253+};
     3.1new file mode 100644
     3.2--- /dev/null
     3.3+++ b/sys/src/cmd/dtracy/act.c
     3.4@@ -0,0 +1,571 @@
     3.5+#include <u.h>
     3.6+#include <libc.h>
     3.7+#include <ctype.h>
     3.8+#include <dtracy.h>
     3.9+#include <bio.h>
    3.10+#include "dat.h"
    3.11+#include "fns.h"
    3.12+
    3.13+/* this contains the code to prepare the kernel data structures and to parse records */
    3.14+
    3.15+Clause *clause;
    3.16+Clause **clauses;
    3.17+int nclauses;
    3.18+
    3.19+/* we could just rely on the types in the expression tree but i'm paranoid */
    3.20+typedef struct Val Val;
    3.21+struct Val {
    3.22+	enum {
    3.23+		VALINT,
    3.24+		VALSTR,
    3.25+	} type;
    3.26+	union {
    3.27+		vlong v;
    3.28+		char *s;
    3.29+	};
    3.30+};
    3.31+
    3.32+Val
    3.33+mkval(int type, ...)
    3.34+{
    3.35+	Val r;
    3.36+	va_list va;
    3.37+	
    3.38+	r.type = type;
    3.39+	va_start(va, type);
    3.40+	switch(type){
    3.41+	case VALINT: r.v = va_arg(va, uvlong); break;
    3.42+	case VALSTR: r.s = va_arg(va, char*); break;
    3.43+	}
    3.44+	va_end(va);
    3.45+	return r;
    3.46+}
    3.47+
    3.48+void
    3.49+clausebegin(void)
    3.50+{
    3.51+	clause = emalloc(sizeof(Clause));
    3.52+	clause->id = nclauses;
    3.53+}
    3.54+
    3.55+void
    3.56+addprobe(char *s)
    3.57+{
    3.58+	clause->probs = erealloc(clause->probs, sizeof(char *) * (clause->nprob + 1));
    3.59+	clause->probs[clause->nprob++] = strdup(s);
    3.60+}
    3.61+
    3.62+void
    3.63+addstat(int type, ...)
    3.64+{
    3.65+	Stat *s;
    3.66+	va_list va;
    3.67+
    3.68+	clause->stats = erealloc(clause->stats, sizeof(Stat) * (clause->nstats + 1));
    3.69+	s = &clause->stats[clause->nstats++];
    3.70+	memset(s, 0, sizeof(Stat));
    3.71+	s->type = type;
    3.72+	va_start(va, type);
    3.73+	switch(type){
    3.74+	case STATEXPR:
    3.75+		s->n = va_arg(va, Node *);
    3.76+		break;
    3.77+	case STATPRINT:
    3.78+	case STATPRINTF:
    3.79+		break;
    3.80+	default:
    3.81+		sysfatal("addstat: unknown type %d", type);
    3.82+	}
    3.83+	va_end(va);
    3.84+}
    3.85+
    3.86+void
    3.87+addarg(Node *n)
    3.88+{
    3.89+	Stat *s;
    3.90+	
    3.91+	assert(clause->nstats > 0);
    3.92+	s = &clause->stats[clause->nstats - 1];
    3.93+	s->arg = erealloc(s->arg, sizeof(Node *) * (s->narg + 1));
    3.94+	s->arg[s->narg++] = n;
    3.95+}
    3.96+
    3.97+void
    3.98+clauseend(void)
    3.99+{
   3.100+	clauses = erealloc(clauses, sizeof(Clause) * (nclauses + 1));
   3.101+	clauses[nclauses++] = clause;
   3.102+}
   3.103+
   3.104+void
   3.105+actgradd(DTActGr *a, DTAct b)
   3.106+{
   3.107+	a->acts = erealloc(a->acts, sizeof(DTAct) * (a->nact + 1));
   3.108+	a->acts[a->nact++] = b;
   3.109+}
   3.110+
   3.111+void
   3.112+addpred(DTExpr *e)
   3.113+{
   3.114+	clause->pred = e;
   3.115+}
   3.116+
   3.117+static void
   3.118+prepprintf(Node **arg, int narg, DTActGr *g, int *recoff)
   3.119+{
   3.120+	char *fmt;
   3.121+	int n;
   3.122+	Fmt f;
   3.123+
   3.124+	if(narg <= 0) sysfatal("printf() needs an argument");
   3.125+	if((*arg)->type != OSTR) sysfatal("printf() format string must be a literal");
   3.126+	fmt = (*arg)->str;
   3.127+	fmtstrinit(&f);
   3.128+	n = 1;
   3.129+	for(; *fmt != 0; fmt++){
   3.130+		fmtrune(&f, *fmt);
   3.131+		if(*fmt != '%')
   3.132+			continue;
   3.133+		fmt++;
   3.134+	again:
   3.135+		switch(*fmt){
   3.136+		case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
   3.137+		case 'u': case '+': case '-': case ',': case '#': case ' ': case '.':
   3.138+			fmtrune(&f, *fmt);
   3.139+			fmt++;
   3.140+			goto again;
   3.141+		case 'x': case 'X': case 'o': case 'b': case 'd':
   3.142+			if(n >= narg) sysfatal("printf() too few arguments");
   3.143+			if(arg[n]->typ->type != TYPINT) sysfatal("print() %%%c with non-integer", *fmt);
   3.144+			arg[n] = tracegen(arg[n], g, recoff);
   3.145+			n++;
   3.146+			fmtrune(&f, 'l');
   3.147+			fmtrune(&f, 'l');
   3.148+			fmtrune(&f, *fmt);
   3.149+			break;
   3.150+		case 's':
   3.151+			if(n >= narg) sysfatal("printf() too few arguments");
   3.152+			if(arg[n]->typ->type != TYPSTRING) sysfatal("print() %%s with non-string");
   3.153+			arg[n] = tracegen(arg[n], g, recoff);
   3.154+			n++;
   3.155+			fmtrune(&f, *fmt);
   3.156+			break;
   3.157+		case 0: sysfatal("printf() missing verb");
   3.158+		default: sysfatal("printf() unknown verb %%%c", *fmt);
   3.159+		}
   3.160+	}
   3.161+	if(n < narg) sysfatal("printf() too many arguments");
   3.162+	(*arg)->str = fmtstrflush(&f);
   3.163+}
   3.164+
   3.165+DTClause *
   3.166+mkdtclause(Clause *c)
   3.167+{
   3.168+	DTClause *d;
   3.169+	Stat *s;
   3.170+	int recoff, i;
   3.171+	
   3.172+	d = emalloc(sizeof(DTClause));
   3.173+	d->nprob = c->nprob;
   3.174+	d->probs = c->probs;
   3.175+	d->gr = emalloc(sizeof(DTActGr));
   3.176+	d->gr->pred = c->pred;
   3.177+	d->gr->id = c->id;
   3.178+	recoff = 12;
   3.179+	for(s = c->stats; s < c->stats + c->nstats; s++)
   3.180+		switch(s->type){
   3.181+		case STATEXPR:
   3.182+			actgradd(d->gr, (DTAct){ACTTRACE, codegen(s->n), 0});
   3.183+			break;
   3.184+		case STATPRINT:
   3.185+			for(i = 0; i < s->narg; i++)
   3.186+				s->arg[i] = tracegen(s->arg[i], d->gr, &recoff);
   3.187+			break;
   3.188+		case STATPRINTF:
   3.189+			prepprintf(s->arg, s->narg, d->gr, &recoff);
   3.190+			break;
   3.191+		}
   3.192+	return d;
   3.193+}
   3.194+
   3.195+void
   3.196+packclauses(Fmt *f)
   3.197+{
   3.198+	int i;
   3.199+	DTClause *d;
   3.200+	
   3.201+	for(i = 0; i < nclauses; i++){
   3.202+		d = mkdtclause(clauses[i]);
   3.203+		dtclpack(f, d);
   3.204+	}
   3.205+}
   3.206+
   3.207+/* epid lookup table, filled with info from the kernel */
   3.208+Enab *enabtab[1024];
   3.209+
   3.210+void
   3.211+addepid(u32int epid, u32int cid, int reclen, char *p)
   3.212+{
   3.213+	Enab *e, **ep;
   3.214+	
   3.215+	assert(cid < nclauses);
   3.216+	assert((uint)reclen >= 12);
   3.217+	e = emalloc(sizeof(Enab));
   3.218+	e->epid = epid;
   3.219+	e->cl = clauses[cid];
   3.220+	e->reclen = reclen;
   3.221+	e->probe = strdup(p);
   3.222+	ep = &enabtab[epid % nelem(enabtab)];
   3.223+	e->next = *ep;
   3.224+	*ep = e;
   3.225+}
   3.226+
   3.227+Enab *
   3.228+epidlookup(u32int epid)
   3.229+{
   3.230+	Enab *e;
   3.231+	
   3.232+	for(e = enabtab[epid % nelem(enabtab)]; e != nil; e = e->next)
   3.233+		if(e->epid == epid)
   3.234+			return e;
   3.235+	return nil;
   3.236+}
   3.237+
   3.238+uchar *
   3.239+unpack(uchar *p, uchar *e, char *fmt, ...)
   3.240+{
   3.241+	va_list va;
   3.242+	u64int vl;
   3.243+	
   3.244+	va_start(va, fmt);
   3.245+	for(;;)
   3.246+		switch(*fmt++){
   3.247+		case 'c':
   3.248+			if(p + 1 > e) return nil;
   3.249+			*va_arg(va, u8int *) = p[0];
   3.250+			p += 1;
   3.251+			break;
   3.252+		case 's':
   3.253+			if(p + 2 > e) return nil;
   3.254+			*va_arg(va, u16int *) = p[0] | p[1] << 8;
   3.255+			p += 2;
   3.256+			break;
   3.257+		case 'i':
   3.258+			if(p + 4 > e) return nil;
   3.259+			*va_arg(va, u32int *) = p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
   3.260+			p += 4;
   3.261+			break;
   3.262+		case 'v':
   3.263+			if(p + 8 > e) return nil;
   3.264+			vl = p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
   3.265+			vl |= (uvlong)p[4] << 32 | (uvlong)p[5] << 40 | (uvlong)p[6] << 48 | (uvlong)p[7] << 56;
   3.266+			*va_arg(va, u64int *) = vl;
   3.267+			p += 8;
   3.268+			break;
   3.269+		case 0:
   3.270+			return p;
   3.271+		default:
   3.272+			abort();
   3.273+		}
   3.274+}
   3.275+
   3.276+static Val
   3.277+receval(Node *n, uchar *p, uchar *e, Enab *en)
   3.278+{
   3.279+	u8int c;
   3.280+	u16int s;
   3.281+	u32int i;
   3.282+	uvlong v;
   3.283+	char *sp;
   3.284+	uchar *q;
   3.285+	Val a, b;
   3.286+
   3.287+	switch(n->type){
   3.288+	case OSYM:
   3.289+		switch(n->sym->type){
   3.290+		case SYMVAR:
   3.291+			switch(n->sym->idx){
   3.292+			case DTV_TIME:
   3.293+				q = unpack(p + 4, e, "v", &v);
   3.294+				assert(q != nil);
   3.295+				return mkval(VALINT, v);
   3.296+			case DTV_PROBE:
   3.297+				return mkval(VALSTR, en->probe);
   3.298+			default: sysfatal("receval: unknown variable %d", n->type); return mkval(VALINT, 0LL);
   3.299+			}
   3.300+			break;
   3.301+		default: sysfatal("receval: unknown symbol type %d", n->type); return mkval(VALINT, 0LL);
   3.302+		}
   3.303+	case ONUM: return mkval(VALINT, n->num);
   3.304+	case OBIN:
   3.305+		a = receval(n->n1, p, e, en);
   3.306+		b = receval(n->n2, p, e, en);
   3.307+		assert(a.type == VALINT);
   3.308+		assert(b.type == VALINT);
   3.309+		return mkval(VALINT, evalop(n->op, n->typ->sign, a.v, b.v));
   3.310+	case OLNOT:
   3.311+		a = receval(n->n1, p, e, en);
   3.312+		assert(a.type == VALINT);
   3.313+		return mkval(VALINT, (uvlong) !a.v);
   3.314+	case OTERN:
   3.315+		a = receval(n->n1, p, e, en);
   3.316+		assert(a.type == VALINT);
   3.317+		return a.v ? receval(n->n2, p, e, en) : receval(n->n3, p, e, en);
   3.318+	case ORECORD:
   3.319+		switch(n->typ->type){
   3.320+		case TYPINT:
   3.321+			switch(n->typ->size){
   3.322+			case 1: q = unpack(p + n->num, e, "c", &c); v = n->typ->sign ? (s8int)c : (u8int)c; break;
   3.323+			case 2: q = unpack(p + n->num, e, "s", &s); v = n->typ->sign ? (s16int)s : (u16int)s; break;
   3.324+			case 4: q = unpack(p + n->num, e, "i", &i); v = n->typ->sign ? (s32int)i : (u32int)i; break;
   3.325+			case 8: q = unpack(p + n->num, e, "v", &v); break;
   3.326+			default: q = nil;
   3.327+			}
   3.328+			assert(q != nil);
   3.329+			return mkval(VALINT, v);
   3.330+		case TYPSTRING:
   3.331+			assert(p + n->num + n->typ->size <= e);
   3.332+			sp = emalloc(n->typ->size + 1);
   3.333+			memcpy(sp, p + n->num, n->typ->size);
   3.334+			return mkval(VALSTR, sp); /* TODO: fix leak */
   3.335+		default:
   3.336+			sysfatal("receval: don't know how to parse record for %τ", n->typ);
   3.337+		}
   3.338+	default:
   3.339+		sysfatal("receval: unknown type %α", n->type);
   3.340+		return mkval(VALINT, 0LL);
   3.341+	}
   3.342+}
   3.343+
   3.344+static void
   3.345+execprintf(Node **arg, int narg, uchar *p, uchar *e, Enab *en)
   3.346+{
   3.347+	char *x, *xp;
   3.348+	Val v;
   3.349+	int i;
   3.350+	
   3.351+	x = emalloc(sizeof(uvlong) * (narg - 1));
   3.352+	xp = x;
   3.353+	for(i = 0; i < narg - 1; i++){
   3.354+		v = receval(arg[i + 1], p, e, en);
   3.355+		switch(v.type){
   3.356+		case VALINT:
   3.357+			*(uvlong*)xp = v.v;
   3.358+			xp += sizeof(uvlong);
   3.359+			break;
   3.360+		case VALSTR:
   3.361+			*(char**)xp = v.s;
   3.362+			xp += sizeof(char*);
   3.363+			break;
   3.364+		default: abort();
   3.365+		}
   3.366+	}
   3.367+	vfprint(1, (*arg)->str, (va_list) x);
   3.368+	free(x);
   3.369+}
   3.370+
   3.371+int
   3.372+parseclause(Clause *cl, uchar *p, uchar *e, Enab *en, Biobuf *bp)
   3.373+{
   3.374+	Stat *s;
   3.375+	int i;
   3.376+	Val v;
   3.377+	
   3.378+	for(s = cl->stats; s < cl->stats + cl->nstats; s++)
   3.379+		switch(s->type){
   3.380+		case STATEXPR: break;
   3.381+		case STATPRINT:
   3.382+			for(i = 0; i < s->narg; i++){
   3.383+				v = receval(s->arg[i], p, e, en);
   3.384+				switch(v.type){
   3.385+				case VALINT:
   3.386+					Bprint(bp, "%lld", v.v);
   3.387+					break;
   3.388+				case VALSTR:
   3.389+					Bprint(bp, "%s", v.s);
   3.390+					break;
   3.391+				default: sysfatal("parseclause: unknown val type %d", s->type);
   3.392+				}
   3.393+				Bprint(bp, "%c", i == s->narg - 1 ? '\n' : ' ');
   3.394+			}
   3.395+			break;
   3.396+		case STATPRINTF:
   3.397+			execprintf(s->arg, s->narg, p, e, en);
   3.398+			break;
   3.399+		default:
   3.400+			sysfatal("parseclause: unknown type %d", s->type);
   3.401+		}
   3.402+	return 0;
   3.403+}
   3.404+
   3.405+int
   3.406+parsebuf(uchar *p, int n, Biobuf *bp)
   3.407+{
   3.408+	uchar *e;
   3.409+	u32int epid;
   3.410+	u64int ts;
   3.411+	Enab *en;
   3.412+	
   3.413+	e = p + n;
   3.414+	while(p < e){
   3.415+		p = unpack(p, e, "iv", &epid, &ts);
   3.416+		if(p == nil) goto err;
   3.417+		en = epidlookup(epid);
   3.418+		if(en == nil) goto err;
   3.419+		if(parseclause(en->cl, p - 12, p + en->reclen - 12, en, bp) < 0) return -1;
   3.420+		p += en->reclen - 12;
   3.421+	}
   3.422+	return 0;
   3.423+err:
   3.424+	werrstr("buffer invalid");
   3.425+	return -1;
   3.426+}
   3.427+
   3.428+static void
   3.429+dumpexpr(DTExpr *e, char *prefix)
   3.430+{
   3.431+	int i;
   3.432+	
   3.433+	for(i = 0; i < e->n; i++)
   3.434+		print("%s%.8ux %I\n", prefix, e->b[i], e->b[i]);
   3.435+}
   3.436+
   3.437+#pragma varargck type "ε" Node*
   3.438+
   3.439+static void
   3.440+fmtstring(Fmt *f, char *s)
   3.441+{
   3.442+	fmtrune(f, '"');
   3.443+	for(; *s != 0; s++)
   3.444+		switch(*s){
   3.445+		case '\n': fmtprint(f, "\\n"); break;
   3.446+		case '\r': fmtprint(f, "\\r"); break;
   3.447+		case '\t': fmtprint(f, "\\t"); break;
   3.448+		case '\v': fmtprint(f, "\\v"); break;
   3.449+		case '\b': fmtprint(f, "\\b"); break;
   3.450+		case '\a': fmtprint(f, "\\a"); break;
   3.451+		case '"': fmtprint(f, "\""); break;
   3.452+		case '\\': fmtprint(f, "\\"); break;
   3.453+		default:
   3.454+			if(*s < 0x20 || *s >= 0x7f)
   3.455+				fmtprint(f, "\\%.3o", (uchar)*s);
   3.456+			else
   3.457+				fmtrune(f, *s);
   3.458+		}
   3.459+	fmtrune(f, '"');
   3.460+}
   3.461+
   3.462+typedef struct Op Op;
   3.463+struct Op {
   3.464+	char *name;
   3.465+	int pred;
   3.466+	enum { PRECRIGHT = 1 } flags;
   3.467+};
   3.468+static Op optab[] = {
   3.469+	[OPLOR] {"||", 3, 0},
   3.470+	[OPLAND] {"&&", 4, 0},
   3.471+	[OPOR] {"|", 5, 0},
   3.472+	[OPXNOR] {"~^", 6, 0},
   3.473+	[OPXOR] {"^", 6, 0},
   3.474+	[OPAND] {"&", 7, 0},
   3.475+	[OPEQ] {"==", 8, },
   3.476+	[OPNE] {"!=", 8, 0},
   3.477+	[OPLE] {"<=", 9, 0},
   3.478+	[OPLT] {"<", 9, 0},
   3.479+	[OPLSH] {"<<", 10, 0},
   3.480+	[OPRSH] {">>", 10, 0},
   3.481+	[OPADD] {"+", 11, 0},
   3.482+	[OPSUB] {"-", 11, 0},
   3.483+	[OPDIV] {"/", 12, 0},
   3.484+	[OPMOD] {"%", 12, 0},
   3.485+	[OPMUL] {"*", 12, 0},
   3.486+};
   3.487+enum { PREDUNARY = 14 };
   3.488+
   3.489+int
   3.490+nodefmt(Fmt *f)
   3.491+{
   3.492+	Node *n;
   3.493+	Op *op;
   3.494+	int p;
   3.495+	
   3.496+	p = f->width;
   3.497+	n = va_arg(f->args, Node *);
   3.498+	switch(n->type){
   3.499+	case OSYM: fmtprint(f, "%s", n->sym->name); break;
   3.500+	case ONUM: fmtprint(f, "%lld", n->num); break;
   3.501+	case OSTR: fmtstring(f, n->str); break;
   3.502+	case OBIN:
   3.503+		if(n->op >= nelem(optab) || optab[n->op].name == nil)
   3.504+			fmtprint(f, "(%*ε ??op%d %*ε)", PREDUNARY, n->n1, n->op, PREDUNARY, n->n2);
   3.505+		else{
   3.506+			op = &optab[n->op];
   3.507+			if(op->pred < p) fmtrune(f, '(');
   3.508+			fmtprint(f, "%*ε %s %*ε", op->pred + (op->flags & PRECRIGHT), n->n1, op->name, op->pred + (~op->flags & PRECRIGHT), n->n2);
   3.509+			if(op->pred < p) fmtrune(f, ')');
   3.510+		}
   3.511+		break;
   3.512+	case OLNOT: fmtprint(f, "!%*ε", PREDUNARY, n->n1); break;
   3.513+	case OTERN: fmtprint(f, "%2ε ? %1ε : %1ε", n->n1, n->n2, n->n3); break;
   3.514+	case ORECORD: fmtprint(f, "record(%ε, %τ, %d)", n->n1, n->typ, (int)n->num); break;
   3.515+	case OCAST: fmtprint(f, "(%τ) %*ε", n->typ, PREDUNARY, n->n1); break;
   3.516+	default: fmtprint(f, "??? %α", n->type);
   3.517+	}
   3.518+	return 0;
   3.519+}
   3.520+
   3.521+void
   3.522+dump(void)
   3.523+{
   3.524+	int i, j;
   3.525+	Stat *s;
   3.526+	Clause *c;
   3.527+	DTClause *d;
   3.528+	DTAct *a;
   3.529+	
   3.530+	for(i = 0; i < nclauses; i++){
   3.531+		c = clauses[i];
   3.532+		d = mkdtclause(c);
   3.533+		print("clause %d:\n", c->id);
   3.534+		for(j = 0; j < c->nprob; j++)
   3.535+			print("\tprobe '%s'\n", c->probs[j]);
   3.536+		print("\tkernel code:\n");
   3.537+		if(c->pred == nil)
   3.538+			print("\t\tno predicate\n");
   3.539+		else{
   3.540+			print("\t\tpredicate\n");
   3.541+			dumpexpr(c->pred, "\t\t\t");
   3.542+		}
   3.543+		for(a = d->gr->acts; a < d->gr->acts + d->gr->nact; a++)
   3.544+			switch(a->type){
   3.545+			case ACTTRACE:
   3.546+				print("\t\ttrace (%d bytes)\n", a->size);
   3.547+				dumpexpr(a->p, "\t\t\t");
   3.548+				break;
   3.549+			case ACTTRACESTR:
   3.550+				print("\t\ttrace string (%d bytes)\n", a->size);
   3.551+				dumpexpr(a->p, "\t\t\t");
   3.552+				break;
   3.553+			default:
   3.554+				print("\t\t??? %d\n", a->type);
   3.555+			}
   3.556+		print("\trecord formatting:\n");
   3.557+		for(s = c->stats; s < c->stats + c->nstats; s++)
   3.558+			switch(s->type){
   3.559+			case STATEXPR:
   3.560+				break;
   3.561+			case STATPRINT:
   3.562+				print("\t\tprint\n");
   3.563+				for(j = 0; j < s->narg; j++)
   3.564+					print("\t\t\targ %ε\n", s->arg[j]);
   3.565+				break;
   3.566+			case STATPRINTF:
   3.567+				print("\t\tprintf\n");
   3.568+				for(j = 0; j < s->narg; j++)
   3.569+					print("\t\t\targ %ε\n", s->arg[j]);
   3.570+				break;
   3.571+			default:
   3.572+				print("\t\t??? %d\n", s->type);
   3.573+			}
   3.574+	}
   3.575+}
     4.1new file mode 100644
     4.2--- /dev/null
     4.3+++ b/sys/src/cmd/dtracy/cgen.c
     4.4@@ -0,0 +1,313 @@
     4.5+#include <u.h>
     4.6+#include <libc.h>
     4.7+#include <dtracy.h>
     4.8+#include <bio.h>
     4.9+#include "dat.h"
    4.10+#include "fns.h"
    4.11+
    4.12+u16int regsused = 1;
    4.13+u32int cbuf[256];
    4.14+int ncbuf;
    4.15+int labtab[256];
    4.16+int nlab;
    4.17+
    4.18+static void
    4.19+emit(u32int x)
    4.20+{
    4.21+	assert(ncbuf < nelem(cbuf));
    4.22+	cbuf[ncbuf++] = x;
    4.23+}
    4.24+
    4.25+static int
    4.26+regalloc(void)
    4.27+{
    4.28+	u16int v;
    4.29+	int n;
    4.30+
    4.31+	if(regsused == 0xffff){
    4.32+		error("out of registers");
    4.33+		return 0;
    4.34+	}
    4.35+	v = regsused + 1 & ~regsused;
    4.36+	regsused ^= v;
    4.37+	n = 0;
    4.38+	if((u8int)v == 0) {v >>= 8; n += 8;}
    4.39+	if((v & 0xf) == 0) {v >>= 4; n += 4;}
    4.40+	if((v & 3) == 0) {v >>= 2; n += 2;}
    4.41+	return n + (v >> 1);
    4.42+}
    4.43+
    4.44+static void
    4.45+regfree(int n)
    4.46+{
    4.47+	assert((regsused & 1<<n) != 0);
    4.48+	assert(n != 0);
    4.49+	regsused &= ~(1<<n);
    4.50+}
    4.51+
    4.52+static int
    4.53+popcount(u64int s)
    4.54+{
    4.55+	s = (s & 0x5555555555555555ULL) + (s >> 1 & 0x5555555555555555ULL);
    4.56+	s = (s & 0x3333333333333333ULL) + (s >> 2 & 0x3333333333333333ULL);
    4.57+	s = (s & 0x0F0F0F0F0F0F0F0FULL) + (s >> 4 & 0x0F0F0F0F0F0F0F0FULL);
    4.58+	s = (s & 0x00FF00FF00FF00FFULL) + (s >> 8 & 0x00FF00FF00FF00FFULL);
    4.59+	s = (s & 0x0000FFFF0000FFFFULL) + (s >> 16 & 0x0000FFFF0000FFFFULL);
    4.60+	return (u32int)s + (u32int)(s >> 32);
    4.61+}
    4.62+
    4.63+static int
    4.64+constenc(s64int val)
    4.65+{
    4.66+	int i, r;
    4.67+	s64int x;
    4.68+
    4.69+	r = 0;
    4.70+	do{
    4.71+		i = popcount(val ^ val - 1) - 1;
    4.72+		x = val << 54 - i >> 54;
    4.73+		if(r == 0){
    4.74+			r = regalloc();
    4.75+			emit(DTE_LDI << 24 | (x & 0x3ff) << 14 | i << 8 | r);
    4.76+		}else
    4.77+			emit(DTE_XORI << 24 | (x & 0x3ff) << 14 | i << 8 | r);
    4.78+		val ^= x << i;
    4.79+	}while(val != 0);
    4.80+	return r;
    4.81+}
    4.82+
    4.83+static int egen(Node *);
    4.84+
    4.85+static void
    4.86+condgen(Node *n, int invert, int truelab)
    4.87+{
    4.88+	int r1, r2, l1, op;
    4.89+
    4.90+	if(n->type != OBIN) goto other;
    4.91+	switch(n->op){
    4.92+	case OPEQ: op = DTE_SEQ; goto cmp;
    4.93+	case OPNE: op = DTE_SNE; goto cmp;
    4.94+	case OPLT: op = DTE_SLT; goto cmp;
    4.95+	case OPLE: op = DTE_SLE;
    4.96+	cmp:
    4.97+		r1 = egen(n->n1);
    4.98+		r2 = egen(n->n2);
    4.99+		if(invert)
   4.100+			emit(DTE(op ^ 1, r2, r1, truelab));
   4.101+		else
   4.102+			emit(DTE(op, r1, r2, truelab));
   4.103+		regfree(r1);
   4.104+		regfree(r2);
   4.105+		break;
   4.106+	case OPLOR:
   4.107+	case OPLAND:
   4.108+		if(invert ^ n->op == OPLOR){
   4.109+			condgen(n->n1, invert, truelab);
   4.110+			condgen(n->n2, invert, truelab);
   4.111+		}else{
   4.112+			l1 = nlab++;
   4.113+			condgen(n->n1, !invert, l1);
   4.114+			condgen(n->n2, invert, truelab);
   4.115+			labtab[l1] = ncbuf;
   4.116+		}
   4.117+		break;
   4.118+	default:
   4.119+	other:
   4.120+		r1 = egen(n);
   4.121+		emit(DTE(DTE_BNE ^ invert, r1, 0, truelab));
   4.122+		regfree(r1);
   4.123+		break;
   4.124+	}
   4.125+}
   4.126+
   4.127+static int
   4.128+condvgen(Node *n, int invert)
   4.129+{
   4.130+	int r, l1, l2, op;
   4.131+
   4.132+	if(n->type == OLNOT)
   4.133+		return condvgen(n->n1, !invert);
   4.134+	if(n->type != OBIN) goto other;
   4.135+	switch(n->op){
   4.136+	case OPEQ: op = DTE_SEQ; goto cmp;
   4.137+	case OPNE: op = DTE_SNE; goto cmp;
   4.138+	case OPLT: op = DTE_SLT; goto cmp;
   4.139+	case OPLE: op = DTE_SLE;
   4.140+	cmp:
   4.141+		if(invert)
   4.142+			return egen(node(OBIN, op ^ 1, n->n2, n->n1));
   4.143+		return egen(n);
   4.144+	case OPLOR:
   4.145+	case OPLAND:
   4.146+		if(invert ^ n->op == OPLOR){
   4.147+			l1 = nlab++;
   4.148+			l2 = nlab++;
   4.149+			condgen(n->n1, invert, l1);
   4.150+			r = condvgen(n->n2, invert);
   4.151+			emit(DTE(DTE_BEQ, 0, 0, l2));
   4.152+			labtab[l1] = ncbuf;
   4.153+			emit(DTE(DTE_LDI, 0, 1<<6, r));
   4.154+			labtab[l2] = ncbuf;
   4.155+			return r;
   4.156+		}else{
   4.157+			l1 = nlab++;
   4.158+			l2 = nlab++;
   4.159+			condgen(n->n1, invert, l1);
   4.160+			r = condvgen(n->n2, invert);
   4.161+			emit(DTE(DTE_BEQ, 0, 0, l2));
   4.162+			labtab[l1] = ncbuf;
   4.163+			emit(DTE(DTE_LDI, 0, 0<<6, r));
   4.164+			labtab[l2] = ncbuf;
   4.165+			return r;
   4.166+		}
   4.167+	default:
   4.168+	other:
   4.169+		r = egen(n);
   4.170+		emit(DTE(DTE_SNE ^ invert, r, 0, r));
   4.171+		return r;
   4.172+	}
   4.173+}
   4.174+
   4.175+static int
   4.176+egen(Node *n)
   4.177+{
   4.178+	int r1, r2, rt, l1, l2, op;
   4.179+
   4.180+	switch(/*nodetype*/n->type){
   4.181+	case ONUM:
   4.182+		return constenc(n->num);
   4.183+	case OSYM:
   4.184+		switch(n->sym->type){
   4.185+		case SYMVAR:
   4.186+			rt = regalloc();
   4.187+			emit(DTE(DTE_LDV, n->sym->idx, rt, 0));
   4.188+			return rt;
   4.189+		default: sysfatal("egen: unknown symbol type %d", n->sym->type); return 0;
   4.190+		}
   4.191+	case OBIN:
   4.192+		switch(/*oper*/n->op){
   4.193+		case OPLAND:
   4.194+		case OPLOR:
   4.195+			return condvgen(n, 0);
   4.196+		case OPADD: op = DTE_ADD; break;
   4.197+		case OPSUB: op = DTE_SUB; break;
   4.198+		case OPMUL: op = DTE_MUL; break;
   4.199+		case OPDIV: op = n->typ->sign ? DTE_SDIV : DTE_UDIV; break;
   4.200+		case OPMOD: op = n->typ->sign ? DTE_SMOD : DTE_UMOD; break;
   4.201+		case OPAND: op = DTE_AND; break;
   4.202+		case OPOR: op = DTE_OR; break;
   4.203+		case OPXOR: op = DTE_XOR; break;
   4.204+		case OPLSH: op = DTE_LSL; break;
   4.205+		case OPRSH: op = n->typ->sign ? DTE_ASR : DTE_LSR; break;
   4.206+		case OPEQ: op = DTE_SEQ; break;
   4.207+		case OPNE: op = DTE_SNE; break;
   4.208+		case OPLT: op = DTE_SLT; break;
   4.209+		case OPLE: op = DTE_SLE; break;
   4.210+		case OPXNOR: op = DTE_XNOR; break;
   4.211+		default: sysfatal("egen: unknown op %d", n->op); return 0;
   4.212+		}
   4.213+		r1 = egen(n->n1);
   4.214+		r2 = egen(n->n2);
   4.215+		regfree(r1);
   4.216+		regfree(r2);
   4.217+		rt = regalloc();
   4.218+		emit(DTE(op, r1, r2, rt));
   4.219+		return rt;
   4.220+	case OTERN:
   4.221+		l1 = nlab++;
   4.222+		l2 = nlab++;
   4.223+		condgen(n->n1, 1, l1);
   4.224+		r1 = egen(n->n2);
   4.225+		emit(DTE(DTE_BEQ, 0, 0, l2));
   4.226+		labtab[l1] = ncbuf;
   4.227+		r2 = egen(n->n3);
   4.228+		if(r1 != r2)
   4.229+			emit(DTE(DTE_OR, 0, r2, r1));
   4.230+		labtab[l2] = ncbuf;
   4.231+		return r1;
   4.232+	case OLNOT:
   4.233+		return condvgen(n, 0);
   4.234+	case OCAST:
   4.235+		switch(n->typ->type){
   4.236+		case TYPINT:
   4.237+			r1 = egen(n->n1);
   4.238+			emit(DTE(n->typ->sign ? DTE_SXT : DTE_ZXT, r1, n->typ->size * 8, r1));
   4.239+			return r1;
   4.240+		case TYPSTRING:
   4.241+			return egen(n->n1);
   4.242+		default:
   4.243+			sysfatal("egen: don't know how to cast %τ to %τ", n->n1->typ, n->typ);
   4.244+		}
   4.245+	case ORECORD:
   4.246+	case OSTR:
   4.247+	default: sysfatal("egen: unknown type %α", n->type); return 0;
   4.248+	}
   4.249+}
   4.250+
   4.251+DTExpr *
   4.252+codegen(Node *n)
   4.253+{
   4.254+	int r, i, t;
   4.255+	DTExpr *ep;
   4.256+	
   4.257+	regsused = 1;
   4.258+	ncbuf = 0;
   4.259+	nlab = 0;
   4.260+	r = egen(n);
   4.261+	emit(DTE(DTE_RET, r, 0, 0));
   4.262+	
   4.263+	for(i = 0; i < ncbuf; i++)
   4.264+		if((cbuf[i] >> 24 & 0xf0) == 0x30){
   4.265+			t = labtab[cbuf[i] & 0xff];
   4.266+			assert((uint)(t - i - 1) < 0x100);
   4.267+			cbuf[i] = cbuf[i] & 0xffffff00 | t - i - 1;
   4.268+		}
   4.269+	
   4.270+	ep = emalloc(sizeof(DTExpr) + ncbuf * sizeof(u32int));
   4.271+	ep->n = ncbuf;
   4.272+	ep->b = (void *)(ep + 1);
   4.273+	memcpy(ep->b, cbuf, ncbuf * sizeof(u32int));
   4.274+	return ep;
   4.275+}
   4.276+
   4.277+Node *
   4.278+tracegen(Node *n, DTActGr *g, int *recoff)
   4.279+{
   4.280+	switch(/*nodetype*/n->type){
   4.281+	case OSYM:
   4.282+	case ONUM:
   4.283+	case OSTR:
   4.284+		break;
   4.285+	case OBIN:
   4.286+		n->n1 = tracegen(n->n1, g, recoff);
   4.287+		n->n2 = tracegen(n->n2, g, recoff);
   4.288+		break;
   4.289+	case OLNOT:
   4.290+		n->n1 = tracegen(n->n1, g, recoff);
   4.291+		break;
   4.292+	case OTERN:
   4.293+		n->n1 = tracegen(n->n1, g, recoff);
   4.294+		n->n2 = tracegen(n->n2, g, recoff);
   4.295+		n->n3 = tracegen(n->n3, g, recoff);
   4.296+		break;
   4.297+	case OCAST:
   4.298+		n->n1 = tracegen(n->n1, g, recoff);
   4.299+		break;
   4.300+	case ORECORD:
   4.301+		switch(n->typ->type){
   4.302+		case TYPINT:
   4.303+			actgradd(g, (DTAct){ACTTRACE, codegen(n->n1), n->typ->size});
   4.304+			break;
   4.305+		case TYPSTRING:
   4.306+			actgradd(g, (DTAct){ACTTRACESTR, codegen(n->n1), n->typ->size});
   4.307+			break;
   4.308+		default:
   4.309+			sysfatal("tracegen: don't know how to record %τ", n->typ);
   4.310+		}
   4.311+		n->num = *recoff;
   4.312+		*recoff += n->typ->size;
   4.313+		return n;
   4.314+	default: sysfatal("tracegen: unknown type %α", n->type); return nil;
   4.315+	}
   4.316+	return n;
   4.317+}
     5.1new file mode 100644
     5.2--- /dev/null
     5.3+++ b/sys/src/cmd/dtracy/dat.h
     5.4@@ -0,0 +1,123 @@
     5.5+typedef struct Node Node;
     5.6+typedef struct Symbol Symbol;
     5.7+typedef struct SymTab SymTab;
     5.8+typedef struct Clause Clause;
     5.9+typedef struct Enab Enab;
    5.10+typedef struct Stat Stat;
    5.11+typedef struct Type Type;
    5.12+
    5.13+enum {
    5.14+	SYMHASH = 256,
    5.15+};
    5.16+
    5.17+struct Type {
    5.18+	enum {
    5.19+		TYPINVAL,
    5.20+		TYPINT,
    5.21+		TYPPTR,
    5.22+		TYPSTRING,
    5.23+	} type;
    5.24+	int size;
    5.25+	uchar sign;
    5.26+	Type *ref;
    5.27+	Type *typenext;
    5.28+};
    5.29+
    5.30+struct Symbol {
    5.31+	enum {
    5.32+		SYMNONE,
    5.33+		SYMVAR,
    5.34+	} type;
    5.35+	char *name;
    5.36+	int idx;
    5.37+	Symbol *next;
    5.38+	Type *typ;
    5.39+};
    5.40+
    5.41+struct SymTab {
    5.42+	Symbol *sym[SYMHASH];
    5.43+};
    5.44+
    5.45+struct Node {
    5.46+	enum {
    5.47+		OINVAL,
    5.48+		OSYM,
    5.49+		ONUM,
    5.50+		OSTR,
    5.51+		OBIN,
    5.52+		OLNOT,
    5.53+		OTERN,
    5.54+		ORECORD,
    5.55+		OCAST,
    5.56+	} type;
    5.57+	enum {
    5.58+		OPINVAL,
    5.59+		OPADD,
    5.60+		OPSUB,
    5.61+		OPMUL,
    5.62+		OPDIV,
    5.63+		OPMOD,
    5.64+		OPAND,
    5.65+		OPOR,
    5.66+		OPXOR,
    5.67+		OPLSH,
    5.68+		OPRSH,
    5.69+		OPEQ,
    5.70+		OPNE,
    5.71+		OPLT,
    5.72+		OPLE,
    5.73+		OPLAND,
    5.74+		OPLOR,
    5.75+		OPXNOR,
    5.76+	} op;
    5.77+	Node *n1, *n2, *n3;
    5.78+	Symbol *sym;
    5.79+	char *str;
    5.80+	s64int num;
    5.81+	
    5.82+	/* used by elidecasts() */
    5.83+	char databits;
    5.84+	enum {UPZX, UPSX} upper;
    5.85+	
    5.86+	int recsize;
    5.87+	
    5.88+	Type *typ;
    5.89+};
    5.90+
    5.91+struct Stat {
    5.92+	enum {
    5.93+		STATEXPR,
    5.94+		STATPRINT,
    5.95+		STATPRINTF,
    5.96+	} type;
    5.97+	Node *n;
    5.98+	int narg;
    5.99+	Node **arg;
   5.100+};
   5.101+
   5.102+struct Clause {
   5.103+	int id;
   5.104+	Stat *stats;
   5.105+	int nstats;
   5.106+	char **probs;
   5.107+	int nprob;
   5.108+	DTExpr *pred;
   5.109+};
   5.110+
   5.111+struct Enab {
   5.112+	int epid;
   5.113+	int reclen;
   5.114+	char *probe;
   5.115+	Clause *cl;
   5.116+	Enab *next;
   5.117+};
   5.118+
   5.119+extern int errors;
   5.120+
   5.121+#pragma	varargck	type	"α"	int
   5.122+#pragma varargck	type	"t"	int
   5.123+#pragma varargck	type	"τ"	Type *
   5.124+#pragma varargck	type	"ε"	Node *
   5.125+#pragma varargck	argpos error 1
   5.126+
   5.127+extern int dflag;
     6.1new file mode 100644
     6.2--- /dev/null
     6.3+++ b/sys/src/cmd/dtracy/dtracy.c
     6.4@@ -0,0 +1,224 @@
     6.5+#include <u.h>
     6.6+#include <libc.h>
     6.7+#include <dtracy.h>
     6.8+#include <bio.h>
     6.9+#include "dat.h"
    6.10+#include "fns.h"
    6.11+
    6.12+char *dtracyroot = "#Δ";
    6.13+int dtracyno;
    6.14+int ctlfd, buffd;
    6.15+
    6.16+int
    6.17+min(int a, int b)
    6.18+{
    6.19+	return a < b ? a : b;
    6.20+}
    6.21+
    6.22+int
    6.23+max(int a, int b)
    6.24+{
    6.25+	return a < b ? b : a;
    6.26+}
    6.27+
    6.28+void *
    6.29+emalloc(ulong n)
    6.30+{
    6.31+	void *v;
    6.32+	
    6.33+	v = malloc(n);
    6.34+	if(v == nil) sysfatal("malloc: %r");
    6.35+	memset(v, 0, n);
    6.36+	setmalloctag(v, getcallerpc(&n));
    6.37+	return v;
    6.38+}
    6.39+
    6.40+void *
    6.41+erealloc(void *v, ulong n)
    6.42+{
    6.43+	v = realloc(v, n);
    6.44+	if(n != 0){
    6.45+		if(v == nil) sysfatal("realloc: %r");
    6.46+		setrealloctag(v, getcallerpc(&v));
    6.47+	}
    6.48+	return v;
    6.49+}
    6.50+
    6.51+void *
    6.52+dtmalloc(ulong n)
    6.53+{
    6.54+	return emalloc(n);
    6.55+}
    6.56+
    6.57+void
    6.58+dtfree(void *v)
    6.59+{
    6.60+	free(v);
    6.61+}
    6.62+
    6.63+void
    6.64+defvar(char *name, int idx, Type *ty)
    6.65+{
    6.66+	Symbol *s;
    6.67+	
    6.68+	s = getsym(name);
    6.69+	s->type = SYMVAR;
    6.70+	s->idx = idx;
    6.71+	s->typ = ty;
    6.72+}
    6.73+
    6.74+void
    6.75+globvars(void)
    6.76+{
    6.77+	defvar("arg0", DTV_ARG0, type(TYPINT, 8, 1));
    6.78+	defvar("arg1", DTV_ARG1, type(TYPINT, 8, 1));
    6.79+	defvar("arg2", DTV_ARG2, type(TYPINT, 8, 1));
    6.80+	defvar("arg3", DTV_ARG3, type(TYPINT, 8, 1));
    6.81+	defvar("arg4", DTV_ARG4, type(TYPINT, 8, 1));
    6.82+	defvar("arg5", DTV_ARG5, type(TYPINT, 8, 1));
    6.83+	defvar("arg6", DTV_ARG6, type(TYPINT, 8, 1));
    6.84+	defvar("arg7", DTV_ARG7, type(TYPINT, 8, 1));
    6.85+	defvar("arg8", DTV_ARG8, type(TYPINT, 8, 1));
    6.86+	defvar("arg9", DTV_ARG9, type(TYPINT, 8, 1));
    6.87+	defvar("pid", DTV_PID, type(TYPINT, 4, 1));
    6.88+	defvar("machno", DTV_MACHNO, type(TYPINT, 4, 1));
    6.89+	defvar("time", DTV_TIME, type(TYPINT, 8, 0));
    6.90+	defvar("probe", DTV_PROBE, type(TYPSTRING));
    6.91+}
    6.92+
    6.93+int
    6.94+setup(void)
    6.95+{
    6.96+	char buf[512];
    6.97+	char *p;
    6.98+	int n;
    6.99+	
   6.100+	snprint(buf, sizeof(buf), "%s/clone", dtracyroot);
   6.101+	ctlfd = open(buf, ORDWR);
   6.102+	if(ctlfd < 0) return -1;
   6.103+	n = read(ctlfd, buf, sizeof(buf) - 1);
   6.104+	if(n < 0) return -1;
   6.105+	buf[n] = 0;
   6.106+	dtracyno = strtol(buf, &p, 10);
   6.107+	if(p == buf || *p != 0){
   6.108+		werrstr("expected number reading from ctl");
   6.109+		return -1;
   6.110+	}
   6.111+	snprint(buf, sizeof(buf), "%s/%d/buf", dtracyroot, dtracyno);
   6.112+	buffd = open(buf, OREAD);
   6.113+	if(buffd < 0) return -1;
   6.114+	return 0;
   6.115+}
   6.116+
   6.117+int
   6.118+progcopy(void)
   6.119+{
   6.120+	char buf[512];
   6.121+	int fd;
   6.122+	char *prog;
   6.123+	Fmt f;
   6.124+
   6.125+	fmtstrinit(&f);
   6.126+	packclauses(&f);
   6.127+	prog = fmtstrflush(&f);
   6.128+	snprint(buf, sizeof(buf), "%s/%d/prog", dtracyroot, dtracyno);
   6.129+	fd = open(buf, OWRITE);
   6.130+	if(fd < 0) return -1;
   6.131+	if(write(fd, prog, strlen(prog)) < 0){
   6.132+		close(fd);
   6.133+		return -1;
   6.134+	}
   6.135+	close(fd);
   6.136+	return 0;
   6.137+}
   6.138+
   6.139+int
   6.140+epidread(void)
   6.141+{
   6.142+	char buf[512];
   6.143+	Biobuf *bp;
   6.144+	char *s;
   6.145+	char *f[5];
   6.146+	int a, b, c;
   6.147+
   6.148+	snprint(buf, sizeof(buf), "%s/%d/epid", dtracyroot, dtracyno);
   6.149+	bp = Bopen(buf, OREAD);
   6.150+	if(bp == nil) return -1;
   6.151+	for(; s = Brdstr(bp, '\n', 1), s != nil; free(s)){
   6.152+		if(tokenize(s, f, nelem(f)) != 4)
   6.153+			goto err;
   6.154+		a = atoi(f[0]);
   6.155+		b = atoi(f[1]);
   6.156+		c = atoi(f[2]);
   6.157+		addepid(a, b, c, f[3]);
   6.158+	}
   6.159+	return 0;
   6.160+err:
   6.161+	werrstr("epidread: invalid format");
   6.162+	free(s);
   6.163+	return -1;
   6.164+	
   6.165+}
   6.166+
   6.167+void
   6.168+bufread(Biobuf *bp)
   6.169+{
   6.170+	static uchar buf[65536];
   6.171+	int n;
   6.172+	
   6.173+	n = read(buffd, buf, sizeof(buf));
   6.174+	if(n < 0) sysfatal("bufread: %r");
   6.175+	if(parsebuf(buf, n, bp) < 0)
   6.176+		sysfatal("parsebuf: %r");
   6.177+	Bflush(bp);
   6.178+}
   6.179+
   6.180+static void
   6.181+usage(void)
   6.182+{
   6.183+	fprint(2, "usage: %s [ -cd ] script\n", argv0);
   6.184+	exits("usage");
   6.185+}
   6.186+
   6.187+int dflag;
   6.188+
   6.189+void
   6.190+main(int argc, char **argv)
   6.191+{
   6.192+	Biobuf *out;
   6.193+
   6.194+	dflag = 0;
   6.195+	ARGBEGIN {
   6.196+	case 'd': dflag = 1; break;
   6.197+	default: usage();
   6.198+	} ARGEND;
   6.199+	if(argc != 1) usage();
   6.200+
   6.201+	fmtinstall(L'α', nodetfmt);
   6.202+	fmtinstall('t', typetfmt);
   6.203+	fmtinstall(L'I', dtefmt);
   6.204+	fmtinstall(L'τ', typefmt);
   6.205+	fmtinstall(L'ε', nodefmt);
   6.206+	lexinit();
   6.207+	lexstring(argv[0]);
   6.208+	globvars();
   6.209+	yyparse();
   6.210+	if(errors != 0)
   6.211+		exits("errors");
   6.212+	if(dflag)
   6.213+		dump();
   6.214+	else{
   6.215+		if(setup() < 0)
   6.216+			sysfatal("setup: %r");
   6.217+		if(progcopy() < 0)
   6.218+			sysfatal("progcopy: %r");
   6.219+		if(epidread() < 0)
   6.220+			sysfatal("epidread: %r");
   6.221+		fprint(ctlfd, "go");
   6.222+		out = Bfdopen(1, OWRITE);
   6.223+		if(out == nil) sysfatal("Bfdopen: %r");
   6.224+		for(;;)
   6.225+			bufread(out);
   6.226+	}
   6.227+	exits(nil);
   6.228+}
     7.1new file mode 100644
     7.2--- /dev/null
     7.3+++ b/sys/src/cmd/dtracy/fns.h
     7.4@@ -0,0 +1,35 @@
     7.5+void yyerror(char *);
     7.6+int yylex(void);
     7.7+int yyparse(void);
     7.8+Node *node(int, ...);
     7.9+int nodetfmt(Fmt *);
    7.10+int typetfmt(Fmt *);
    7.11+int typefmt(Fmt *);
    7.12+int nodefmt(Fmt *);
    7.13+void *emalloc(ulong);
    7.14+void *erealloc(void *, ulong);
    7.15+DTAct action(int, DTExpr *);
    7.16+DTExpr *codegen(Node *);
    7.17+void error(char *, ...);
    7.18+Symbol *getsym(char *);
    7.19+void lexinit(void);
    7.20+void lexstring(char *);
    7.21+void clausebegin(void);
    7.22+void addstat(int, ...);
    7.23+void addarg(Node *);
    7.24+void addprobe(char *);
    7.25+void addpred(DTExpr *);
    7.26+void clauseend(void);
    7.27+void packclauses(Fmt *);
    7.28+void addepid(u32int, u32int, int, char*);
    7.29+int parsebuf(uchar *, int, Biobuf*);
    7.30+Node *tracegen(Node *, DTActGr *, int *);
    7.31+void actgradd(DTActGr *, DTAct);
    7.32+void needruntime(Node *);
    7.33+void dump(void);
    7.34+vlong evalop(int, int, vlong, vlong);
    7.35+Node *exprcheck(Node *, int);
    7.36+Type *type(int, ...);
    7.37+int min(int, int);
    7.38+int max(int, int);
    7.39+Node *addtype(Type *, Node *);
     8.1new file mode 100644
     8.2--- /dev/null
     8.3+++ b/sys/src/cmd/dtracy/lex.c
     8.4@@ -0,0 +1,390 @@
     8.5+#include <u.h>
     8.6+#include <libc.h>
     8.7+#include <ctype.h>
     8.8+#include <dtracy.h>
     8.9+#include <bio.h>
    8.10+#include "dat.h"
    8.11+#include "fns.h"
    8.12+#include "y.tab.h"
    8.13+
    8.14+char *str, *strp;
    8.15+int lineno = 1;
    8.16+int errors;
    8.17+
    8.18+typedef struct Keyword Keyword;
    8.19+struct Keyword {
    8.20+	char *name;
    8.21+	int tok;
    8.22+};
    8.23+/* both tables must be sorted */
    8.24+Keyword kwtab[] = {
    8.25+	"if", TIF,
    8.26+	"print", TPRINT,
    8.27+	"printf", TPRINTF,
    8.28+	"s16", TS16,
    8.29+	"s32", TS32,
    8.30+	"s64", TS64,
    8.31+	"s8", TS8,
    8.32+	"string", TSTRING,
    8.33+	"u16", TU16,
    8.34+	"u32", TU32,
    8.35+	"u64", TU64,
    8.36+	"u8", TU8,
    8.37+};
    8.38+Keyword optab[] = {
    8.39+	"!=", TNE,
    8.40+	"&&", TAND,
    8.41+	"<<", TLSL,
    8.42+	"<=", TLE,
    8.43+	"==", TEQ,
    8.44+	">=", TGE,
    8.45+	">>", TLSR,
    8.46+	"||", TOR,
    8.47+};
    8.48+Keyword *kwchar[128], *opchar[128];
    8.49+
    8.50+void
    8.51+lexinit(void)
    8.52+{
    8.53+	Keyword *kw;
    8.54+	
    8.55+	for(kw = kwtab; kw < kwtab + nelem(kwtab); kw++)
    8.56+		if(kwchar[*kw->name] == nil)
    8.57+			kwchar[*kw->name] = kw;
    8.58+	for(kw = optab; kw < optab + nelem(optab); kw++)
    8.59+		if(opchar[*kw->name] == nil)
    8.60+			opchar[*kw->name] = kw;
    8.61+}
    8.62+
    8.63+void
    8.64+lexstring(char *s)
    8.65+{
    8.66+	str = strp = s;
    8.67+}
    8.68+
    8.69+void
    8.70+error(char *fmt, ...)
    8.71+{
    8.72+	Fmt f;
    8.73+	char buf[128];
    8.74+	va_list va;
    8.75+	
    8.76+	fmtfdinit(&f, 2, buf, sizeof(buf));
    8.77+	fmtprint(&f, "%d ", lineno);
    8.78+	va_start(va, fmt);
    8.79+	fmtvprint(&f, fmt, va);
    8.80+	fmtrune(&f, '\n');
    8.81+	va_end(va);
    8.82+	fmtfdflush(&f);
    8.83+	errors++;
    8.84+}
    8.85+
    8.86+void
    8.87+yyerror(char *msg)
    8.88+{
    8.89+	error("%s", msg);
    8.90+}
    8.91+
    8.92+static int
    8.93+getch(void)
    8.94+{
    8.95+	if(*strp == 0) return -1;
    8.96+	return *strp++;
    8.97+}
    8.98+
    8.99+static void
   8.100+ungetch(void)
   8.101+{
   8.102+	assert(strp > str);
   8.103+	if(*strp != 0)
   8.104+		strp--;
   8.105+}
   8.106+
   8.107+int
   8.108+yylex(void)
   8.109+{
   8.110+	int ch;
   8.111+	static char buf[512];
   8.112+	char *p;
   8.113+	Keyword *kw;
   8.114+	u64int v;
   8.115+
   8.116+again:
   8.117+	while(ch = getch(), ch >= 0 && isspace(ch)){
   8.118+		if(ch == '\n')
   8.119+			lineno++;
   8.120+	}
   8.121+	if(ch < 0)
   8.122+		return -1;
   8.123+	if(ch == '/'){
   8.124+		ch = getch();
   8.125+		if(ch == '/'){
   8.126+			while(ch = getch(), ch >= 0 && ch != '\n')
   8.127+				;
   8.128+			if(ch == '\n')
   8.129+				lineno++;
   8.130+			goto again;
   8.131+		}
   8.132+		if(ch == '*'){
   8.133+		s1:
   8.134+			ch = getch();
   8.135+			if(ch < 0) return -1;
   8.136+			if(ch == '\n') lineno++;
   8.137+			if(ch != '*') goto s1;
   8.138+		s2:
   8.139+			ch = getch();
   8.140+			if(ch < 0) return -1;
   8.141+			if(ch == '\n') lineno++;
   8.142+			if(ch == '*') goto s2;
   8.143+			if(ch != '/') goto s1;
   8.144+			goto again;
   8.145+		}
   8.146+		ungetch();
   8.147+		return '/';
   8.148+	}
   8.149+	if(isalnum(ch) || ch == '_' || ch >= 0x80 || ch == ':'){
   8.150+		p = buf;
   8.151+		*p++ = ch;
   8.152+		while(ch = getch(), isalnum(ch) || ch == '_' || ch >= 0x80 || ch == ':')
   8.153+			if(p < buf + sizeof(buf) - 1)
   8.154+				*p++ = ch;
   8.155+		*p = 0;
   8.156+		ungetch();
   8.157+		v = strtoull(buf, &p, 0);
   8.158+		if(p != buf && *p == 0){
   8.159+			yylval.num = v;
   8.160+			return TNUM;
   8.161+		}
   8.162+		if(strcmp(buf, ":") == 0)
   8.163+			return ':';
   8.164+		if((uchar)buf[0] < 0x80 && kwchar[buf[0]] != nil)
   8.165+			for(kw = kwchar[buf[0]]; kw < kwtab + nelem(kwtab) && kw->name[0] == buf[0]; kw++)
   8.166+				if(strcmp(kw->name, buf) == 0)
   8.167+					return kw->tok;
   8.168+		yylval.sym = getsym(buf);
   8.169+		return TSYM;
   8.170+	}
   8.171+	if(ch == '"'){
   8.172+		p = buf;
   8.173+		while(ch = getch(), ch >= 0 && ch != '"'){
   8.174+			if(ch == '\n')
   8.175+				error("unterminated string");
   8.176+			if(ch == '\\')
   8.177+				switch(ch = getch()){
   8.178+				case 'n': ch = '\n'; break;
   8.179+				case 'r': ch = '\r'; break;
   8.180+				case 't': ch = '\t'; break;
   8.181+				case 'v': ch = '\v'; break;
   8.182+				case 'b': ch = '\b'; break;
   8.183+				case 'a': ch = '\a'; break;
   8.184+				case '"': case '\\': break;
   8.185+				default: error("unknown escape code \\%c", ch);
   8.186+				}
   8.187+			if(p < buf + sizeof(buf) - 1)
   8.188+				*p++ = ch;
   8.189+		}
   8.190+		if(ch < 0) error("unterminated string");
   8.191+		*p = 0;
   8.192+		yylval.str = strdup(buf);
   8.193+		return TSTR;
   8.194+	}
   8.195+	if(opchar[ch] != nil){
   8.196+		buf[0] = ch;
   8.197+		buf[1] = getch();
   8.198+		for(kw = opchar[buf[0]]; kw < optab + nelem(optab) && kw->name[0] == buf[0]; kw++)
   8.199+			if(buf[1] == kw->name[1]){
   8.200+				buf[2] = getch();
   8.201+				buf[3] = 0;
   8.202+				if(kw + 1 < optab + nelem(optab) && strcmp(kw[1].name, buf) == 0)
   8.203+					return kw[1].tok;
   8.204+				ungetch();
   8.205+				return kw->tok;
   8.206+			}
   8.207+		ungetch();
   8.208+	}
   8.209+	return ch;
   8.210+}
   8.211+
   8.212+int
   8.213+nodetfmt(Fmt *f)
   8.214+{
   8.215+	int t;
   8.216+	static char *nodestr[] = {
   8.217+		[OINVAL] "OINVAL",
   8.218+		[OBIN] "OBIN",
   8.219+		[OLNOT] "OLNOT",
   8.220+		[OSYM] "OSYM",
   8.221+		[ONUM] "ONUM",
   8.222+		[OSTR] "OSTR",
   8.223+		[OTERN] "OTERN",
   8.224+		[ORECORD] "ORECORD",
   8.225+		[OCAST] "OCAST",
   8.226+	};
   8.227+	
   8.228+	t = va_arg(f->args, int);
   8.229+	if(t >= nelem(nodestr) || nodestr[t] == nil)
   8.230+		return fmtprint(f, "??? (%d)", t);
   8.231+	else
   8.232+		return fmtprint(f, "%s", nodestr[t]);
   8.233+}
   8.234+
   8.235+Node *
   8.236+node(int type, ...)
   8.237+{
   8.238+	va_list va;
   8.239+	Node *n;
   8.240+	
   8.241+	n = emalloc(sizeof(Node));
   8.242+	n->type = type;
   8.243+	va_start(va, type);
   8.244+	switch(type){
   8.245+	case OBIN:
   8.246+		n->op = va_arg(va, int);
   8.247+		n->n1 = va_arg(va, Node *);
   8.248+		n->n2 = va_arg(va, Node *);
   8.249+		break;
   8.250+	case OLNOT:
   8.251+		n->n1 = va_arg(va, Node *);
   8.252+		break;
   8.253+	case OSYM:
   8.254+		n->sym = va_arg(va, Symbol *);
   8.255+		break;
   8.256+	case ONUM:
   8.257+		n->num = va_arg(va, s64int);
   8.258+		break;
   8.259+	case OTERN:
   8.260+		n->n1 = va_arg(va, Node *);
   8.261+		n->n2 = va_arg(va, Node *);
   8.262+		n->n3 = va_arg(va, Node *);
   8.263+		break;
   8.264+	case ORECORD:
   8.265+		n->n1 = va_arg(va, Node *);
   8.266+		break;
   8.267+	case OCAST:
   8.268+		n->typ = va_arg(va, Type *);
   8.269+		n->n1 = va_arg(va, Node *);
   8.270+		break;
   8.271+	case OSTR:
   8.272+		n->str = va_arg(va, char *);
   8.273+		break;
   8.274+	default:
   8.275+		sysfatal("node: unknown type %α", type);
   8.276+	}
   8.277+	va_end(va);
   8.278+	return n;
   8.279+}
   8.280+
   8.281+SymTab globals;
   8.282+
   8.283+static u64int
   8.284+hash(char *s)
   8.285+{
   8.286+	u64int h;
   8.287+	
   8.288+	h = 0xcbf29ce484222325ULL;
   8.289+	for(; *s != 0; s++){
   8.290+		h ^= *s;
   8.291+		h *= 0x100000001b3ULL;
   8.292+	}
   8.293+	return h;
   8.294+}
   8.295+
   8.296+Symbol *
   8.297+getsym(char *name)
   8.298+{
   8.299+	u64int h;
   8.300+	Symbol **sp, *s;
   8.301+	
   8.302+	h = hash(name);
   8.303+	for(sp = &globals.sym[h % SYMHASH]; s = *sp, s != nil; sp = &s->next)
   8.304+		if(strcmp(s->name, name) == 0)
   8.305+			return s;
   8.306+	*sp = s = emalloc(sizeof(Symbol));
   8.307+	s->name = strdup(name);
   8.308+	return s;
   8.309+}
   8.310+
   8.311+int
   8.312+typetfmt(Fmt *f)
   8.313+{
   8.314+	int t;
   8.315+	static char *tstr[] = {
   8.316+		[TYPINVAL] "TYPINVAL",
   8.317+		[TYPINT] "TYPINT",
   8.318+		[TYPPTR] "TYPPTR",
   8.319+		[TYPSTRING] "TYPSTRING",
   8.320+	};
   8.321+	
   8.322+	t = va_arg(f->args, int);
   8.323+	if(t >= nelem(tstr) || tstr[t] == nil)
   8.324+		return fmtprint(f, "??? (%d)", t);
   8.325+	else
   8.326+		return fmtprint(f, "%s", tstr[t]);
   8.327+}
   8.328+
   8.329+int
   8.330+typefmt(Fmt *f)
   8.331+{
   8.332+	Type *t;
   8.333+	
   8.334+	t = va_arg(f->args, Type *);
   8.335+	switch(t->type){
   8.336+	case TYPINT: return fmtprint(f, "%c%d", t->sign ? 's' : 'u', t->size * 8);
   8.337+	case TYPSTRING: return fmtprint(f, "string");
   8.338+	case TYPPTR: return fmtprint(f, "%τ*", t->ref);
   8.339+	default: return fmtprint(f, "%t", t->type);
   8.340+	}
   8.341+}
   8.342+
   8.343+static Type typu8 = {.type TYPINT, .size 1, .sign 0};
   8.344+static Type typs8 = {.type TYPINT, .size 1, .sign 1};
   8.345+static Type typu16 = {.type TYPINT, .size 2, .sign 0};
   8.346+static Type typs16 = {.type TYPINT, .size 2, .sign 1};
   8.347+static Type typu32 = {.type TYPINT, .size 4, .sign 0};
   8.348+static Type typs32 = {.type TYPINT, .size 4, .sign 1};
   8.349+static Type typu64 = {.type TYPINT, .size 8, .sign 0};
   8.350+static Type typs64 = {.type TYPINT, .size 8, .sign 1};
   8.351+static Type typstr = {.type TYPSTRING, .size DTSTRMAX };
   8.352+static Type *typereg;
   8.353+
   8.354+static Type *
   8.355+mkptr(Type *t)
   8.356+{
   8.357+	Type *s;
   8.358+	
   8.359+	for(s = typereg; s != nil; s = s->typenext)
   8.360+		if(s->type == TYPPTR && s->ref == t)
   8.361+			return s;
   8.362+	s = emalloc(sizeof(Type));
   8.363+	s->type = TYPPTR;
   8.364+	s->ref = t;
   8.365+	return s;
   8.366+}
   8.367+
   8.368+Type *
   8.369+type(int typ, ...)
   8.370+{
   8.371+	int size, sign;
   8.372+	va_list va;
   8.373+	
   8.374+	va_start(va, typ);
   8.375+	switch(typ){
   8.376+	case TYPINT:
   8.377+		size = va_arg(va, int);
   8.378+		sign = va_arg(va, int);
   8.379+		switch(size << 4 | sign){
   8.380+		case 0x10: return &typu8;
   8.381+		case 0x11: return &typs8;
   8.382+		case 0x20: return &typu16;
   8.383+		case 0x21: return &typs16;
   8.384+		case 0x40: return &typu32;
   8.385+		case 0x41: return &typs32;
   8.386+		case 0x80: return &typu64;
   8.387+		case 0x81: return &typs64;
   8.388+		default: sysfatal("type: invalid (size,sign) = (%d,%d)\n", size, sign); return nil;
   8.389+		}
   8.390+	case TYPSTRING: return &typstr;
   8.391+	case TYPPTR: return mkptr(va_arg(va, Type *));
   8.392+	default: sysfatal("type: unknown %t", typ); return nil;
   8.393+	}
   8.394+}
     9.1new file mode 100755
     9.2--- /dev/null
     9.3+++ b/sys/src/cmd/dtracy/lint.rc
     9.4@@ -0,0 +1,20 @@
     9.5+#!/bin/rc
     9.6+# check for full switch statements
     9.7+
     9.8+nl='
     9.9+'
    9.10+nodetypes=`''{sed -n '/OINVAL/,/}/ s/,//p' dat.h | sed 's/[ 	]*//g; /^$/d' | sort | grep -v '^OINVAL$'}
    9.11+switches=`$nl{grep -n '/\*nodetype\*/' *.[ch]}
    9.12+for(l in $switches){
    9.13+	f=`:{echo $l}
    9.14+	a=`$nl{sed -n $f(2)^'s/[^ 	].*//p' $f(1)}
    9.15+	comm -23 <{echo $nodetypes} <{sed -n $f(2)^',/^'^$a^'}/ s/^'^$a^'case ([^:]*):.*/\1/p' $f(1) | sort} | sed -n 's/.+/'^$f(1)^':'^$f(2)^' missing &/p'
    9.16+}
    9.17+
    9.18+oper=`''{sed -n '/OPINVAL/,/}/ s/,//p' dat.h | sed 's/[ 	]*//g; /^$/d' | sort | grep -v '^OPINVAL$'}
    9.19+switches=`$nl{grep -n '/\*oper\*/' *.[ch]}
    9.20+for(l in $switches){
    9.21+	f=`:{echo $l}
    9.22+	a=`$nl{sed -n $f(2)^'s/[^ 	].*//p' $f(1)}
    9.23+	comm -23 <{echo $oper} <{sed -n $f(2)^',/^'^$a^'}/ s/^'^$a^'case ([^:]*):.*/\1/p' $f(1) | sort} | sed -n 's/.+/'^$f(1)^':'^$f(2)^' missing &/p'
    9.24+}
    10.1new file mode 100644
    10.2--- /dev/null
    10.3+++ b/sys/src/cmd/dtracy/mkfile
    10.4@@ -0,0 +1,22 @@
    10.5+</$objtype/mkfile
    10.6+
    10.7+BIN=/$objtype/bin
    10.8+TARG=dtracy
    10.9+OFILES=\
   10.10+	dtracy.$O\
   10.11+	lex.$O\
   10.12+	y.tab.$O\
   10.13+	cgen.$O\
   10.14+	act.$O\
   10.15+	type.$O\
   10.16+
   10.17+YFILES=parse.y
   10.18+
   10.19+HFILES=\
   10.20+	dat.h\
   10.21+	fns.h\
   10.22+
   10.23+</sys/src/cmd/mkone
   10.24+
   10.25+YFLAGS=-v -d -D1
   10.26+lex.$O: y.tab.h
    11.1new file mode 100644
    11.2--- /dev/null
    11.3+++ b/sys/src/cmd/dtracy/parse.y
    11.4@@ -0,0 +1,123 @@
    11.5+%{
    11.6+#include <u.h>
    11.7+#include <libc.h>
    11.8+#include <dtracy.h>
    11.9+#include <bio.h>
   11.10+#include "dat.h"
   11.11+#include "fns.h"
   11.12+%}
   11.13+
   11.14+%union{
   11.15+	Node *n;
   11.16+	Symbol *sym;
   11.17+	DTExpr *e;
   11.18+	s64int num;
   11.19+	char *str;
   11.20+	Type *t;
   11.21+}
   11.22+
   11.23+%type <n> expr
   11.24+%type <t> type
   11.25+
   11.26+%token <sym> TSYM
   11.27+%token <num> TNUM
   11.28+%token <str> TSTR
   11.29+%token TPRINT TPRINTF
   11.30+%token TIF
   11.31+%token TU8 TU16 TU32 TU64
   11.32+%token TS8 TS16 TS32 TS64
   11.33+%token TSTRING
   11.34+
   11.35+%right '?'
   11.36+%left TOR
   11.37+%left TAND
   11.38+%left '|'
   11.39+%left '^'
   11.40+%left '&'
   11.41+%left TEQ TNE
   11.42+%left '<' '>' TLE TGE
   11.43+%left TLSL TLSR
   11.44+%left '+' '-'
   11.45+%left '*' '/' '%'
   11.46+%left unary
   11.47+%right castprec
   11.48+
   11.49+%%
   11.50+
   11.51+program: | program clause
   11.52+
   11.53+clause: { clausebegin(); } probes optpredicate optaction { clauseend(); }
   11.54+
   11.55+optpredicate: | TIF expr { addpred(codegen(exprcheck($2, 1))); }
   11.56+
   11.57+optaction:
   11.58+	{
   11.59+		addstat(STATPRINT);
   11.60+		addarg(node(OSYM, getsym("probe")));
   11.61+	}
   11.62+	| action
   11.63+action: '{' stats '}'
   11.64+stats: | stats0 | stats0 ';'
   11.65+stats0: stat | stats0 ';' stat
   11.66+
   11.67+stat: expr { addstat(STATEXPR, exprcheck($1, 0)); }
   11.68+| TPRINT { addstat(STATPRINT); } pelist
   11.69+| TPRINTF { addstat(STATPRINTF); } pelist
   11.70+
   11.71+
   11.72+pelist:
   11.73+	'(' ')'
   11.74+	| '(' arg ',' ')'
   11.75+	| '(' elist2 optcomma ')'
   11.76+	| arg optcomma
   11.77+	| elist2 optcomma
   11.78+elist2: arg ',' arg | elist2 ',' arg
   11.79+arg: expr { addarg(exprcheck($1, 0)); }
   11.80+optcomma: | ','
   11.81+
   11.82+expr:
   11.83+	TSYM { $$ = node(OSYM, $1); }
   11.84+	| TNUM { $$ = node(ONUM, $1); }
   11.85+	| TSTR { $$ = node(OSTR, $1); }
   11.86+	| expr '+' expr { $$ = node(OBIN, OPADD, $1, $3); }
   11.87+	| expr '-' expr { $$ = node(OBIN, OPSUB, $1, $3); }
   11.88+	| expr '*' expr { $$ = node(OBIN, OPMUL, $1, $3); }
   11.89+	| expr '/' expr { $$ = node(OBIN, OPDIV, $1, $3); }
   11.90+	| expr '%' expr { $$ = node(OBIN, OPMOD, $1, $3); }
   11.91+	| expr '&' expr { $$ = node(OBIN, OPAND, $1, $3); }
   11.92+	| expr '|' expr { $$ = node(OBIN, OPOR, $1, $3); }
   11.93+	| expr '^' expr { $$ = node(OBIN, OPXOR, $1, $3); }
   11.94+	| expr TLSL expr { $$ = node(OBIN, OPLSH, $1, $3); }
   11.95+	| expr TLSR expr { $$ = node(OBIN, OPRSH, $1, $3); }
   11.96+	| expr TEQ expr { $$ = node(OBIN, OPEQ, $1, $3); }
   11.97+	| expr TNE expr { $$ = node(OBIN, OPNE, $1, $3); }
   11.98+	| expr '<' expr { $$ = node(OBIN, OPLT, $1, $3); }
   11.99+	| expr TLE expr { $$ = node(OBIN, OPLE, $1, $3); }
  11.100+	| expr '>' expr { $$ = node(OBIN, OPLT, $3, $1); }
  11.101+	| expr TGE expr { $$ = node(OBIN, OPLE, $3, $1); }
  11.102+	| expr TAND expr { $$ = node(OBIN, OPLAND, $1, $3); }
  11.103+	| expr TOR expr { $$ = node(OBIN, OPLOR, $1, $3); }
  11.104+	| '-' expr %prec unary { $$ = node(OBIN, OPSUB, node(ONUM, 0LL), $2); }
  11.105+	| '~' expr %prec unary { $$ = node(OBIN, OPXNOR, node(ONUM, 0LL), $2); }
  11.106+	| '!' expr %prec unary { $$ = node(OLNOT, $2); }
  11.107+	| '(' expr ')' { $$ = $2; }
  11.108+	| expr '?' expr ':' expr %prec '?' { $$ = node(OTERN, $1, $3, $5); }
  11.109+	| '(' type ')' expr %prec castprec { $$ = node(OCAST, $2, $4); }
  11.110+
  11.111+type:
  11.112+	TU8 { $$ = type(TYPINT, 1, 0); }
  11.113+	| TS8 { $$ = type(TYPINT, 1, 1); }
  11.114+	| TU16 { $$ = type(TYPINT, 2, 0); }
  11.115+	| TS16 { $$ = type(TYPINT, 2, 1); }
  11.116+	| TU32 { $$ = type(TYPINT, 4, 0); }
  11.117+	| TS32 { $$ = type(TYPINT, 4, 1); }
  11.118+	| TU64 { $$ = type(TYPINT, 8, 0); }
  11.119+	| TS64 { $$ = type(TYPINT, 8, 1); }
  11.120+	| TSTRING { $$ = type(TYPSTRING); }
  11.121+
  11.122+probes:
  11.123+	TSYM { addprobe($1->name); }
  11.124+	| probes ',' TSYM { addprobe($3->name); }
  11.125+
  11.126+
  11.127+%%
    12.1new file mode 100644
    12.2--- /dev/null
    12.3+++ b/sys/src/cmd/dtracy/type.c
    12.4@@ -0,0 +1,529 @@
    12.5+#include <u.h>
    12.6+#include <libc.h>
    12.7+#include <ctype.h>
    12.8+#include <dtracy.h>
    12.9+#include <bio.h>
   12.10+#include "dat.h"
   12.11+#include "fns.h"
   12.12+
   12.13+Node *
   12.14+icast(int sign, int size, Node *n)
   12.15+{
   12.16+	Type *t;
   12.17+	
   12.18+	t = type(TYPINT, sign, size);
   12.19+	return node(OCAST, t, n);
   12.20+}
   12.21+
   12.22+/*
   12.23+	the type checker checks types.
   12.24+	the result is an expression that is correct if evaluated with 64-bit operands all the way.
   12.25+	to maintain c-like semantics, this means adding casts all over the place, which will get optimised later.
   12.26+	
   12.27+	note we use kencc, NOT ansi c, semantics for unsigned.
   12.28+*/
   12.29+
   12.30+Node *
   12.31+typecheck(Node *n)
   12.32+{
   12.33+	int s1, s2, sign;
   12.34+
   12.35+	switch(/*nodetype*/n->type){
   12.36+	case OSYM:
   12.37+		switch(n->sym->type){
   12.38+		case SYMNONE: error("undeclared '%s'", n->sym->name); break;
   12.39+		case SYMVAR: n->typ = n->sym->typ; break;
   12.40+		default: sysfatal("typecheck: unknown symbol type %d", n->sym->type);
   12.41+		}
   12.42+		break;
   12.43+	case ONUM:
   12.44+		if((vlong)n->num >= -0x80000000LL && (vlong)n->num <= 0x7fffffffLL)
   12.45+			n->typ = type(TYPINT, 4, 1);
   12.46+		else
   12.47+			n->typ = type(TYPINT, 8, 1);
   12.48+		break;
   12.49+	case OSTR:
   12.50+		n->typ = type(TYPSTRING);
   12.51+		break;
   12.52+	case OBIN:
   12.53+		n->n1 = typecheck(n->n1);
   12.54+		n->n2 = typecheck(n->n2);
   12.55+		if(n->n1->typ == nil || n->n2->typ == nil)
   12.56+			break;
   12.57+		if(n->n1->typ->type != TYPINT){
   12.58+			error("%τ not allowed in operation", n->n1->typ);
   12.59+			break;
   12.60+		}
   12.61+		if(n->n2->typ->type != TYPINT){
   12.62+			error("%τ not allowed in operation", n->n2->typ);
   12.63+			break;
   12.64+		}
   12.65+		s1 = n->n1->typ->size;
   12.66+		s2 = n->n2->typ->size;
   12.67+		sign = n->n1->typ->sign && n->n2->typ->sign;
   12.68+		switch(n->op){
   12.69+		case OPADD:
   12.70+		case OPSUB:
   12.71+		case OPMUL:
   12.72+		case OPDIV:
   12.73+		case OPMOD:
   12.74+		case OPAND:
   12.75+		case OPOR:
   12.76+		case OPXOR:
   12.77+		case OPXNOR:
   12.78+			n->typ = type(TYPINT, 8, sign);
   12.79+			if(s1 > 4 || s2 > 4){
   12.80+				n->n1 = icast(8, sign, n->n1);
   12.81+				n->n2 = icast(8, sign, n->n2);
   12.82+				return n;
   12.83+			}else{
   12.84+				n->n1 = icast(4, sign, n->n1);
   12.85+				n->n2 = icast(4, sign, n->n2);
   12.86+				return icast(4, sign, n);
   12.87+			}
   12.88+		case OPEQ:
   12.89+		case OPNE:
   12.90+		case OPLT:
   12.91+		case OPLE:
   12.92+			n->typ = type(TYPINT, 4, sign);
   12.93+			if(s1 > 4 || s2 > 4){
   12.94+				n->n1 = icast(8, sign, n->n1);
   12.95+				n->n2 = icast(8, sign, n->n2);
   12.96+				return n;
   12.97+			}else{
   12.98+				n->n1 = icast(4, sign, n->n1);
   12.99+				n->n2 = icast(4, sign, n->n2);
  12.100+				return n;
  12.101+			}
  12.102+		case OPLAND:
  12.103+		case OPLOR:
  12.104+			n->typ = type(TYPINT, 4, sign);
  12.105+			return n;
  12.106+		case OPLSH:
  12.107+		case OPRSH:
  12.108+			if(n->n1->typ->size <= 4)
  12.109+				n->n1 = icast(4, n->n1->typ->sign, n->n1);
  12.110+			n->typ = n->n1->typ;
  12.111+			return icast(n->typ->size, n->typ->sign, n);
  12.112+		default:
  12.113+			sysfatal("typecheck: unknown op %d", n->op);
  12.114+		}
  12.115+		break;
  12.116+	case OCAST:
  12.117+		n->n1 = typecheck(n->n1);
  12.118+		if(n->n1->typ == nil)
  12.119+			break;
  12.120+		if(n->typ->type == TYPINT && n->n1->typ->type == TYPINT){
  12.121+		}else if(n->typ == n->n1->typ){
  12.122+		}else if(n->typ->type == TYPSTRING && n->n1->typ->type == TYPINT){
  12.123+		}else
  12.124+			error("can't cast from %τ to %τ", n->n1->typ, n->typ);
  12.125+		break;
  12.126+	case OLNOT:
  12.127+		n->n1 = typecheck(n->n1);
  12.128+		if(n->n1->typ == nil)
  12.129+			break;
  12.130+		if(n->n1->typ->type != TYPINT){
  12.131+			error("%τ not allowed in operation", n->n1->typ);
  12.132+			break;
  12.133+		}
  12.134+		n->typ = type(TYPINT, 4, 1);
  12.135+		break;
  12.136+	case OTERN:
  12.137+		n->n1 = typecheck(n->n1);
  12.138+		n->n2 = typecheck(n->n2);
  12.139+		n->n3 = typecheck(n->n3);
  12.140+		if(n->n1->typ == nil || n->n2->typ == nil || n->n3->typ == nil)
  12.141+			break;
  12.142+		if(n->n1->typ->type != TYPINT){
  12.143+			error("%τ not allowed in operation", n->n1->typ);
  12.144+			break;
  12.145+		}
  12.146+		if(n->n2->typ->type == TYPINT || n->n3->typ->type == TYPINT){
  12.147+			sign = n->n2->typ->sign && n->n3->typ->sign;
  12.148+			s1 = n->n2->typ->size;
  12.149+			s2 = n->n3->typ->size;
  12.150+			if(s1 > 4 || s2 > 4){
  12.151+				n->n2 = icast(8, sign, n->n2);
  12.152+				n->n3 = icast(8, sign, n->n3);
  12.153+				n->typ = type(TYPINT, 8, sign);
  12.154+				return n;
  12.155+			}else{
  12.156+				n->n2 = icast(4, sign, n->n2);
  12.157+				n->n3 = icast(4, sign, n->n3);
  12.158+				n->typ = type(TYPINT, 4, sign);
  12.159+				return n;
  12.160+			}
  12.161+		}else if(n->n2->typ == n->n3->typ){
  12.162+			n->typ = n->n2->typ;
  12.163+		}else
  12.164+			error("don't know how to do ternary with %τ and %τ", n->n2->typ, n->n3->typ);
  12.165+		break;
  12.166+	case ORECORD:
  12.167+	default: sysfatal("typecheck: unknown node type %α", n->type);
  12.168+	}
  12.169+	return n;
  12.170+}
  12.171+
  12.172+vlong
  12.173+evalop(int op, int sign, vlong v1, vlong v2)
  12.174+{
  12.175+	switch(/*oper*/op){
  12.176+	case OPADD: return v1 + v2; break;
  12.177+	case OPSUB: return v1 - v2; break;
  12.178+	case OPMUL: return v1 * v2; break;
  12.179+	case OPDIV: if(v2 == 0) sysfatal("division by zero"); return sign ? v1 / v2 : (uvlong)v1 / (uvlong)v2; break;
  12.180+	case OPMOD: if(v2 == 0) sysfatal("division by zero"); return sign ? v1 % v2 : (uvlong)v1 % (uvlong)v2; break;
  12.181+	case OPAND: return v1 & v2; break;
  12.182+	case OPOR: return v1 | v2; break;
  12.183+	case OPXOR: return v1 ^ v2; break;
  12.184+	case OPXNOR: return ~(v1 ^ v2); break;
  12.185+	case OPLSH:
  12.186+		if((u64int)v2 >= 64)
  12.187+			return 0;
  12.188+		else
  12.189+			return v1 << v2;
  12.190+		break;
  12.191+	case OPRSH:
  12.192+		if(sign){
  12.193+			if((u64int)v2 >= 64)
  12.194+				return v1 >> 63;
  12.195+			else
  12.196+				return v1 >> v2;
  12.197+		}else{
  12.198+			if((u64int)v2 >= 64)
  12.199+				return 0;
  12.200+			else
  12.201+				return (u64int)v1 >> v2;
  12.202+		}
  12.203+		break;
  12.204+	case OPEQ: return v1 == v2; break;
  12.205+	case OPNE: return v1 != v2; break;
  12.206+	case OPLT: return v1 < v2; break;
  12.207+	case OPLE: return v1 <= v2; break;
  12.208+	case OPLAND: return v1 && v2; break;
  12.209+	case OPLOR: return v1 || v2; break;
  12.210+	default:
  12.211+		sysfatal("cfold: unknown op %.2x", op);
  12.212+		return 0;
  12.213+	}
  12.214+
  12.215+}
  12.216+
  12.217+Node *
  12.218+addtype(Type *t, Node *n)
  12.219+{
  12.220+	n->typ = t;
  12.221+	return n;
  12.222+}
  12.223+
  12.224+/* fold constants */
  12.225+
  12.226+static Node *
  12.227+cfold(Node *n)
  12.228+{
  12.229+	switch(/*nodetype*/n->type){
  12.230+	case ONUM:
  12.231+	case OSYM:
  12.232+	case OSTR:
  12.233+		return n;
  12.234+	case OBIN:
  12.235+		n->n1 = cfold(n->n1);
  12.236+		n->n2 = cfold(n->n2);
  12.237+		if(n->n1->type != ONUM || n->n2->type != ONUM)
  12.238+			return n;
  12.239+		return addtype(n->typ, node(ONUM, evalop(n->op, n->typ->sign, n->n1->num, n->n2->num)));
  12.240+	case OLNOT:
  12.241+		n->n1 = cfold(n->n1);
  12.242+		if(n->n1->type == ONUM)
  12.243+			return addtype(n->typ, node(ONUM, !n->n1->num));
  12.244+		return n;
  12.245+	case OTERN:
  12.246+		n->n1 = cfold(n->n1);
  12.247+		n->n2 = cfold(n->n2);
  12.248+		n->n3 = cfold(n->n3);
  12.249+		if(n->n1->type == ONUM)
  12.250+			return n->n1->num ? n->n2 : n->n3;
  12.251+		return n;
  12.252+	case OCAST:
  12.253+		n->n1 = cfold(n->n1);
  12.254+		if(n->n1->type != ONUM || n->typ->type != TYPINT)
  12.255+			return n;
  12.256+		switch(n->typ->size << 4 | n->typ->sign){
  12.257+		case 0x10: return addtype(n->typ, node(ONUM, (vlong)(u8int)n->n1->num));
  12.258+		case 0x11: return addtype(n->typ, node(ONUM, (vlong)(s8int)n->n1->num));
  12.259+		case 0x20: return addtype(n->typ, node(ONUM, (vlong)(u16int)n->n1->num));
  12.260+		case 0x21: return addtype(n->typ, node(ONUM, (vlong)(s16int)n->n1->num));
  12.261+		case 0x40: return addtype(n->typ, node(ONUM, (vlong)(u32int)n->n1->num));
  12.262+		case 0x41: return addtype(n->typ, node(ONUM, (vlong)(s32int)n->n1->num));
  12.263+		case 0x80: return addtype(n->typ, node(ONUM, n->n1->num));
  12.264+		case 0x81: return addtype(n->typ, node(ONUM, n->n1->num));
  12.265+		}
  12.266+		return n;
  12.267+	case ORECORD:
  12.268+	default:
  12.269+		fprint(2, "cfold: unknown type %α\n", n->type);
  12.270+		return n;
  12.271+	}
  12.272+}
  12.273+
  12.274+/* calculate the minimum record size for each node of the expression */
  12.275+static Node *
  12.276+calcrecsize(Node *n)
  12.277+{
  12.278+	switch(/*nodetype*/n->type){
  12.279+	case ONUM:
  12.280+	case OSTR:
  12.281+		n->recsize = 0;
  12.282+		break;
  12.283+	case OSYM:
  12.284+		switch(n->sym->type){
  12.285+		case SYMVAR:
  12.286+			switch(n->sym->idx){
  12.287+			case DTV_TIME:
  12.288+			case DTV_PROBE:
  12.289+				n->recsize = 0;
  12.290+				break;
  12.291+			default:
  12.292+				n->recsize = n->typ->size;
  12.293+				break;
  12.294+			}
  12.295+			break;
  12.296+		default: sysfatal("calcrecsize: unknown symbol type %d", n->sym->type); return nil;
  12.297+		}
  12.298+		break;
  12.299+	case OBIN:
  12.300+		n->n1 = calcrecsize(n->n1);
  12.301+		n->n2 = calcrecsize(n->n2);
  12.302+		n->recsize = min(n->typ->size, n->n1->recsize + n->n2->recsize);
  12.303+		break;
  12.304+	case OLNOT:
  12.305+		n->n1 = calcrecsize(n->n1);
  12.306+		n->recsize = min(n->typ->size, n->n1->recsize);
  12.307+		break;
  12.308+	case OCAST:
  12.309+		n->n1 = calcrecsize(n->n1);
  12.310+		if(n->typ->type == TYPSTRING)
  12.311+			n->recsize = n->typ->size;
  12.312+		else
  12.313+			n->recsize = min(n->typ->size, n->n1->recsize);
  12.314+		break;
  12.315+	case OTERN:
  12.316+		n->n1 = calcrecsize(n->n1);
  12.317+		n->n2 = calcrecsize(n->n2);
  12.318+		n->n3 = calcrecsize(n->n3);
  12.319+		n->recsize = min(n->typ->size, n->n1->recsize + n->n2->recsize + n->n3->recsize);
  12.320+		break;
  12.321+	case ORECORD:
  12.322+	default: sysfatal("calcrecsize: unknown type %α", n->type); return nil;
  12.323+	}
  12.324+	return n;
  12.325+}
  12.326+
  12.327+/* insert ORECORD nodes to mark the subexpression that we will pass to the kernel */
  12.328+static Node *
  12.329+insrecord(Node *n)
  12.330+{
  12.331+	if(n->recsize == 0)
  12.332+		return n;
  12.333+	if(n->typ->size == n->recsize)
  12.334+		return addtype(n->typ, node(ORECORD, n));
  12.335+	switch(/*nodetype*/n->type){
  12.336+	case ONUM:
  12.337+	case OSTR:
  12.338+	case OSYM:
  12.339+		break;
  12.340+	case OBIN:
  12.341+		n->n1 = insrecord(n->n1);
  12.342+		n->n2 = insrecord(n->n2);
  12.343+		break;
  12.344+	case OLNOT:
  12.345+	case OCAST:
  12.346+		n->n1 = insrecord(n->n1);
  12.347+		break;
  12.348+	case OTERN:
  12.349+		n->n1 = insrecord(n->n1);
  12.350+		n->n2 = insrecord(n->n2);
  12.351+		n->n3 = insrecord(n->n3);
  12.352+		break;
  12.353+	case ORECORD:
  12.354+	default: sysfatal("insrecord: unknown type %α", n->type); return nil;
  12.355+	}
  12.356+	return n;
  12.357+}
  12.358+
  12.359+/*
  12.360+	delete useless casts.
  12.361+	going down we determine the number of bits (m) needed to be correct at each stage.
  12.362+	going back up we determine the number of bits (n->databits) which can be either 0 or 1.
  12.363+	all other bits are either zero (n->upper == UPZX) or sign-extended (n->upper == UPSX).
  12.364+	note that by number of bits we always mean a consecutive block starting from the LSB.
  12.365+	
  12.366+	we can delete a cast if it either affects only bits not needed (according to m) or
  12.367+	if it's a no-op (according to databits, upper).
  12.368+*/
  12.369+static Node *
  12.370+elidecasts(Node *n, int m)
  12.371+{
  12.372+	switch(/*nodetype*/n->type){
  12.373+	case OSTR:
  12.374+		return n;
  12.375+	case ONUM:
  12.376+		n->databits = n->typ->size * 8;
  12.377+		n->upper = n->typ->sign ? UPSX : UPZX;
  12.378+		break;
  12.379+	case OSYM:
  12.380+		/* TODO: make less pessimistic */
  12.381+		n->databits = 64;
  12.382+		break;
  12.383+	case OBIN:
  12.384+		switch(/*oper*/n->op){
  12.385+		case OPADD:
  12.386+		case OPSUB:
  12.387+			n->n1 = elidecasts(n->n1, m);
  12.388+			n->n2 = elidecasts(n->n2, m);
  12.389+			n->databits = min(64, max(n->n1->databits, n->n2->databits) + 1);
  12.390+			n->upper = n->n1->upper | n->n2->upper;
  12.391+			break;
  12.392+		case OPMUL:
  12.393+			n->n1 = elidecasts(n->n1, m);
  12.394+			n->n2 = elidecasts(n->n2, m);
  12.395+			n->databits = min(64, n->n1->databits + n->n2->databits);
  12.396+			n->upper = n->n1->upper | n->n2->upper;
  12.397+			break;
  12.398+		case OPAND:
  12.399+		case OPOR:
  12.400+		case OPXOR:
  12.401+		case OPXNOR:
  12.402+			n->n1 = elidecasts(n->n1, m);
  12.403+			n->n2 = elidecasts(n->n2, m);
  12.404+			if(n->op == OPAND && (n->n1->upper == UPZX || n->n2->upper == UPZX)){
  12.405+				n->upper = UPZX;
  12.406+				if(n->n1->upper == UPZX && n->n2->upper == UPZX)
  12.407+					n->databits = min(n->n1->databits, n->n2->databits);
  12.408+				else if(n->n1->upper == UPZX)
  12.409+					n->databits = n->n1->databits;
  12.410+				else
  12.411+					n->databits = n->n2->databits;
  12.412+			}else{
  12.413+				n->databits = max(n->n1->databits, n->n2->databits);
  12.414+				n->upper = n->n1->upper | n->n2->upper;
  12.415+			}
  12.416+			break;
  12.417+		case OPLSH:
  12.418+			n->n1 = elidecasts(n->n1, m);
  12.419+			n->n2 = elidecasts(n->n2, 64);
  12.420+			if(n->n2->type == ONUM && n->n2->num >= 0 && n->n1->databits + (uvlong)n->n2->num <= 64)
  12.421+				n->databits = n->n1->databits + n->n2->num;
  12.422+			else
  12.423+				n->databits = 64;
  12.424+			n->upper = n->n1->upper;
  12.425+			break;
  12.426+		case OPRSH:
  12.427+			n->n1 = elidecasts(n->n1, 64);
  12.428+			n->n2 = elidecasts(n->n2, 64);
  12.429+			if(n->n1->upper == n->typ->sign){
  12.430+				n->databits = n->n1->databits;
  12.431+				n->upper = n->n1->upper;
  12.432+			}else{
  12.433+				n->databits = 64;
  12.434+				n->upper = UPZX;
  12.435+			}
  12.436+			break;
  12.437+		case OPEQ:
  12.438+		case OPNE:
  12.439+		case OPLT:
  12.440+		case OPLE:
  12.441+		case OPLAND:
  12.442+		case OPLOR:
  12.443+			n->n1 = elidecasts(n->n1, 64);
  12.444+			n->n2 = elidecasts(n->n2, 64);
  12.445+			n->databits = 1;
  12.446+			n->upper = UPZX;
  12.447+			break;
  12.448+		case OPDIV:
  12.449+		case OPMOD:
  12.450+		default:
  12.451+			n->n1 = elidecasts(n->n1, 64);
  12.452+			n->n2 = elidecasts(n->n2, 64);
  12.453+			n->databits = 64;
  12.454+			n->upper = UPZX;
  12.455+			break;
  12.456+		}
  12.457+		break;
  12.458+	case OLNOT:
  12.459+		n->n1 = elidecasts(n->n1, 64);
  12.460+		n->databits = 1;
  12.461+		n->upper = UPZX;
  12.462+		break;
  12.463+	case OCAST:
  12.464+		switch(n->typ->type){
  12.465+		case TYPINT:
  12.466+			n->n1 = elidecasts(n->n1, min(n->typ->size * 8, m));
  12.467+			if(n->n1->databits < n->typ->size * 8 && n->n1->upper == n->typ->sign){
  12.468+				n->databits = n->n1->databits;
  12.469+				n->upper = n->n1->upper;
  12.470+			}else{
  12.471+				n->databits = n->typ->size * 8;
  12.472+				n->upper = n->typ->sign ? UPSX : UPZX;
  12.473+			}
  12.474+			if(n->typ->size * 8 >= m) return n->n1;
  12.475+			if(n->typ->size * 8 >= n->n1->databits && n->typ->sign == n->n1->upper) return n->n1;
  12.476+			if(n->typ->size * 8 > n->n1->databits && n->typ->sign && !n->n1->upper) return n->n1;
  12.477+			break;
  12.478+		case TYPSTRING:
  12.479+			n->n1 = elidecasts(n->n1, 64);
  12.480+			break;
  12.481+		default:
  12.482+			sysfatal("elidecasts: don't know how to cast %τ to %τ", n->n1->typ, n->typ);
  12.483+		}
  12.484+		break;
  12.485+	case ORECORD:
  12.486+		n->n1 = elidecasts(n->n1, min(n->typ->size * 8, m));
  12.487+		if(n->n1->databits < n->typ->size * 8 && n->n1->upper == n->typ->sign){
  12.488+			n->databits = n->n1->databits;
  12.489+			n->upper = n->n1->upper;
  12.490+		}else{
  12.491+			n->databits = n->typ->size * 8;
  12.492+			n->upper = n->typ->sign ? UPSX : UPZX;
  12.493+		}
  12.494+		break;
  12.495+	case OTERN:
  12.496+		n->n1 = elidecasts(n->n1, 64);
  12.497+		n->n2 = elidecasts(n->n2, m);
  12.498+		n->n3 = elidecasts(n->n3, m);
  12.499+		if(n->n2->upper == n->n3->upper){
  12.500+			n->databits = max(n->n2->databits, n->n3->databits);
  12.501+			n->upper = n->n2->upper;
  12.502+		}else{
  12.503+			if(n->n3->upper == UPSX)
  12.504+				n->databits = max(min(64, n->n2->databits + 1), n->n3->databits);
  12.505+			else
  12.506+				n->databits = max(min(64, n->n3->databits + 1), n->n2->databits);
  12.507+			n->upper = UPSX;
  12.508+		}
  12.509+		break;
  12.510+	default: sysfatal("elidecasts: unknown type %α", n->type);
  12.511+	}
  12.512+//	print("need %d got %d%c %ε\n", n->needbits, n->databits, "ZS"[n->upper], n);
  12.513+	return n;
  12.514+}
  12.515+
  12.516+
  12.517+Node *
  12.518+exprcheck(Node *n, int pred)
  12.519+{
  12.520+	if(dflag) print("start       %ε\n", n);
  12.521+	n = typecheck(n);
  12.522+	if(errors) return n;
  12.523+	if(dflag) print("typecheck   %ε\n", n);
  12.524+	n = cfold(n);
  12.525+	if(dflag) print("cfold       %ε\n", n);
  12.526+	if(!pred){
  12.527+		n = insrecord(calcrecsize(n));
  12.528+		if(dflag) print("insrecord   %ε\n", n);
  12.529+	}
  12.530+	n = elidecasts(n, 64);
  12.531+	if(dflag) print("elidecasts  %ε\n", n);
  12.532+	return n;
  12.533+}
    13.1new file mode 100644
    13.2--- /dev/null
    13.3+++ b/sys/src/libdtracy/chan.c
    13.4@@ -0,0 +1,222 @@
    13.5+#include <u.h>
    13.6+#include <libc.h>
    13.7+#include <dtracy.h>
    13.8+
    13.9+int dtnmach;
   13.10+
   13.11+void
   13.12+dtinit(int nmach)
   13.13+{
   13.14+	DTProvider **p;
   13.15+
   13.16+	dtnmach = nmach;
   13.17+	
   13.18+	/* sanity */
   13.19+	for(p = dtproviders; *p != nil; p++){
   13.20+		assert((*p)->name != nil);
   13.21+		assert((*p)->provide != nil);
   13.22+		assert((*p)->enable != nil);
   13.23+		assert((*p)->disable != nil);
   13.24+	}
   13.25+}
   13.26+
   13.27+void
   13.28+dtsync(void)
   13.29+{
   13.30+	int i;
   13.31+	
   13.32+	for(i = 0; i < dtnmach; i++){
   13.33+		dtmachlock(i);
   13.34+		dtmachunlock(i);
   13.35+	}
   13.36+}
   13.37+
   13.38+DTChan *
   13.39+dtcnew(void)
   13.40+{
   13.41+	DTChan *c;
   13.42+	int i;
   13.43+	
   13.44+	c = dtmalloc(sizeof(DTChan));
   13.45+	c->rdbufs = dtmalloc(sizeof(DTBuf *) * dtnmach);
   13.46+	c->wrbufs = dtmalloc(sizeof(DTBuf *) * dtnmach);
   13.47+	for(i = 0; i < dtnmach; i++){
   13.48+		c->rdbufs[i] = dtmalloc(sizeof(DTBuf));
   13.49+		c->wrbufs[i] = dtmalloc(sizeof(DTBuf));
   13.50+	}
   13.51+	return c;
   13.52+}
   13.53+
   13.54+void
   13.55+dtcfree(DTChan *ch)
   13.56+{
   13.57+	int i;
   13.58+
   13.59+	if(ch == nil) return;
   13.60+
   13.61+	dtcrun(ch, DTCSTOP);
   13.62+	dtcreset(ch);
   13.63+	dtsync();
   13.64+	for(i = 0; i < dtnmach; i++){
   13.65+		free(ch->rdbufs[i]);
   13.66+		free(ch->wrbufs[i]);
   13.67+	}
   13.68+	free(ch->rdbufs);
   13.69+	free(ch->wrbufs);
   13.70+	free(ch);
   13.71+}
   13.72+
   13.73+int
   13.74+dtcaddgr(DTChan *c, DTName name, DTActGr *gr)
   13.75+{
   13.76+	DTProbe **l, *p;
   13.77+	DTEnab *ep;
   13.78+	int i, nl, n;
   13.79+	
   13.80+	if(dtgverify(gr) < 0)
   13.81+		return -1;
   13.82+	gr->chan = c;
   13.83+	
   13.84+	nl = dtpmatch(name, &l);
   13.85+	n = 0;
   13.86+	for(i = 0; i < nl; i++){
   13.87+		p = l[i];
   13.88+		if(p->nenable == 0)
   13.89+			if(p->prov->enable(p) < 0)
   13.90+				continue;
   13.91+		ep = dtmalloc(sizeof(DTEnab));
   13.92+		ep->epid = c->epidalloc++;
   13.93+		ep->gr = gr;
   13.94+		ep->prob = p;
   13.95+		ep->probnext = &p->enablist;
   13.96+		ep->probprev = p->enablist.probprev;
   13.97+		ep->probnext->probprev = ep;
   13.98+		ep->channext = c->enab;
   13.99+		c->enab = ep;
  13.100+		gr->ref++;
  13.101+		n++;
  13.102+		p->nenable++;
  13.103+		/* careful, has to be atomic for dtptrigger */
  13.104+		dtcoherence();
  13.105+		ep->probprev->probnext = ep;
  13.106+	}
  13.107+	dtfree(l);
  13.108+	return n;
  13.109+}
  13.110+
  13.111+static int
  13.112+dtnamesplit(char *s, DTName *rp)
  13.113+{
  13.114+	char *p;
  13.115+	
  13.116+	p = strchr(s, ':');
  13.117+	if(p == nil) return -1;
  13.118+	rp->provider = dtmalloc(p - s + 1);
  13.119+	memcpy(rp->provider, s, p - s);
  13.120+	s = p + 1;
  13.121+	p = strchr(s, ':');
  13.122+	if(p == nil){
  13.123+		free(rp->provider);
  13.124+		rp->provider = nil;
  13.125+		return -1;
  13.126+	}
  13.127+	rp->function = dtmalloc(p - s + 1);
  13.128+	memcpy(rp->function, s, p - s);
  13.129+	s = p + 1;
  13.130+	if(strchr(s, ':') != nil){
  13.131+		free(rp->provider);
  13.132+		rp->provider = nil;
  13.133+		free(rp->function);
  13.134+		rp->function = nil;
  13.135+		return -1;
  13.136+	}
  13.137+	rp->name = dtstrdup(s);
  13.138+	return 0;
  13.139+}
  13.140+
  13.141+int
  13.142+dtcaddcl(DTChan *c, DTClause *cl)
  13.143+{
  13.144+	DTName n;
  13.145+	int i, rc;
  13.146+
  13.147+	rc = 0;
  13.148+	for(i = 0; i < cl->nprob; i++){
  13.149+		if(dtnamesplit(cl->probs[i], &n) < 0){
  13.150+			werrstr("invalid probe name '%s'", cl->probs[i]);
  13.151+			return -1;
  13.152+		}
  13.153+		rc += dtcaddgr(c, n, cl->gr);
  13.154+		dtfree(n.provider);
  13.155+		dtfree(n.function);
  13.156+		dtfree(n.name);
  13.157+	}
  13.158+	return rc;
  13.159+}
  13.160+
  13.161+static void
  13.162+dtcbufswap(DTChan *c, int n)
  13.163+{
  13.164+	DTBuf *z;
  13.165+
  13.166+	dtmachlock(n);
  13.167+	z = c->rdbufs[n];
  13.168+	c->rdbufs[n] = c->wrbufs[n];
  13.169+	c->wrbufs[n] = z;
  13.170+	dtmachunlock(n);
  13.171+}
  13.172+
  13.173+int
  13.174+dtcread(DTChan *c, void *buf, int n)
  13.175+{
  13.176+	int i, swapped;
  13.177+	
  13.178+	if(c->state == DTCFAULT){
  13.179+		werrstr("%s", c->errstr);
  13.180+		return -1;
  13.181+	}
  13.182+	for(i = 0; i < dtnmach; i++){
  13.183+		if(swapped = c->rdbufs[i]->wr == 0)
  13.184+			dtcbufswap(c, i);
  13.185+		if(c->rdbufs[i]->wr != 0){
  13.186+			if(c->rdbufs[i]->wr > n){
  13.187+				werrstr("short read");
  13.188+				return -1;
  13.189+			}
  13.190+			n = c->rdbufs[i]->wr;
  13.191+			memmove(buf, c->rdbufs[i]->data, n);
  13.192+			c->rdbufs[i]->wr = 0;
  13.193+			if(!swapped)
  13.194+				dtcbufswap(c, i);
  13.195+			return n;
  13.196+		}
  13.197+	}
  13.198+	return 0;
  13.199+}
  13.200+
  13.201+void
  13.202+dtcreset(DTChan *c)
  13.203+{
  13.204+	DTEnab *ep, *eq;
  13.205+	
  13.206+	for(ep = c->enab; ep != nil; ep = ep->channext){
  13.207+		/* careful! has to look atomic for etptrigger */
  13.208+		ep->probprev->probnext = ep->probnext;
  13.209+		ep->probnext->probprev = ep->probprev;
  13.210+	}
  13.211+	dtsync();
  13.212+	for(ep = c->enab; ep != nil; eq = ep->channext, free(ep), ep = eq){
  13.213+		if(--ep->gr->ref == 0)
  13.214+			dtgfree(ep->gr);
  13.215+		if(--ep->prob->nenable == 0)
  13.216+			ep->prob->prov->disable(ep->prob);
  13.217+	}
  13.218+	c->enab = nil;
  13.219+}
  13.220+
  13.221+void
  13.222+dtcrun(DTChan *c, int newstate)
  13.223+{
  13.224+	assert(newstate == DTCSTOP || newstate == DTCGO);
  13.225+	c->state = newstate;
  13.226+}
    14.1new file mode 100644
    14.2--- /dev/null
    14.3+++ b/sys/src/libdtracy/dtefmt.c
    14.4@@ -0,0 +1,114 @@
    14.5+#include <u.h>
    14.6+#include <libc.h>
    14.7+#include <dtracy.h>
    14.8+
    14.9+char *dtvarnames[DTNVARS] = {
   14.10+	[DTV_ARG0] "arg0",
   14.11+	[DTV_ARG1] "arg1",
   14.12+	[DTV_ARG2] "arg2",
   14.13+	[DTV_ARG3] "arg3",
   14.14+	[DTV_ARG4] "arg4",
   14.15+	[DTV_ARG5] "arg5",
   14.16+	[DTV_ARG6] "arg6",
   14.17+	[DTV_ARG7] "arg7",
   14.18+	[DTV_ARG8] "arg8",
   14.19+	[DTV_ARG9] "arg9",
   14.20+	[DTV_PID] "pid",
   14.21+	[DTV_TIME] "time",
   14.22+	[DTV_PROBE] "probe",
   14.23+	[DTV_MACHNO] "machno",
   14.24+};
   14.25+
   14.26+int
   14.27+dtefmt(Fmt *f)
   14.28+{
   14.29+	u32int ins;
   14.30+	u8int op, a, b, c;
   14.31+	u64int x;
   14.32+	static char *opcodes[] = {
   14.33+		[DTE_ADD] "ADD",
   14.34+		[DTE_SUB] "SUB",
   14.35+		[DTE_MUL] "MUL",
   14.36+		[DTE_UDIV] "UDIV",
   14.37+		[DTE_UMOD] "UMOD",
   14.38+		[DTE_SDIV] "SDIV",
   14.39+		[DTE_SMOD] "SMOD",
   14.40+		[DTE_AND] "AND",
   14.41+		[DTE_OR] "OR",
   14.42+		[DTE_XOR] "XOR",
   14.43+		[DTE_XNOR] "XNOR",
   14.44+		[DTE_LSL] "LSL",
   14.45+		[DTE_LSR] "LSR",
   14.46+		[DTE_ASR] "ASR",
   14.47+		[DTE_SEQ] "SEQ",
   14.48+		[DTE_SNE] "SNE",
   14.49+		[DTE_SLT] "SLT",
   14.50+		[DTE_SLE] "SLE",
   14.51+		[DTE_LDI] "LDI",
   14.52+		[DTE_XORI] "XORI",
   14.53+		[DTE_BEQ] "BEQ",
   14.54+		[DTE_BNE] "BNE",
   14.55+		[DTE_BLT] "BLT",
   14.56+		[DTE_BLE] "BLE",
   14.57+		[DTE_LDV] "LDV",
   14.58+		[DTE_RET] "RET",
   14.59+		[DTE_ZXT] "ZXT",
   14.60+		[DTE_SXT] "SXT",
   14.61+	};
   14.62+	
   14.63+	ins = va_arg(f->args, u32int);
   14.64+	op = ins >> 24;
   14.65+	a = ins >> 16;
   14.66+	b = ins >> 8;
   14.67+	c = ins;
   14.68+	switch(op){
   14.69+	case DTE_ADD:
   14.70+	case DTE_SUB:
   14.71+	case DTE_MUL:
   14.72+	case DTE_UDIV:
   14.73+	case DTE_UMOD:
   14.74+	case DTE_SDIV:
   14.75+	case DTE_SMOD:
   14.76+	case DTE_AND:
   14.77+	case DTE_OR:
   14.78+	case DTE_XOR:
   14.79+	case DTE_XNOR:
   14.80+	case DTE_LSL:
   14.81+	case DTE_LSR:
   14.82+	case DTE_ASR:
   14.83+	case DTE_SEQ:
   14.84+	case DTE_SNE:
   14.85+	case DTE_SLT:
   14.86+	case DTE_SLE:
   14.87+		fmtprint(f, "%s R%d, R%d, R%d", opcodes[op], a, b, c);
   14.88+		break;
   14.89+	case DTE_LDI:
   14.90+	case DTE_XORI:
   14.91+		x = (s64int)ins << 40 >> 54 << (ins >> 8 & 63);
   14.92+		fmtprint(f, "%s $%#llx, R%d", opcodes[op], x, c);
   14.93+		break;
   14.94+	case DTE_BEQ:
   14.95+	case DTE_BNE:
   14.96+	case DTE_BLT:
   14.97+	case DTE_BLE:
   14.98+		fmtprint(f, "%s R%d, R%d, +%d", opcodes[op], a, b, c);
   14.99+		break;
  14.100+	case DTE_LDV:
  14.101+		if(a >= DTNVARS || dtvarnames[a] == nil)
  14.102+			fmtprint(f, "%s V%d, R%d", opcodes[op], a, b);
  14.103+		else
  14.104+			fmtprint(f, "%s %s, R%d", opcodes[op], dtvarnames[a], b);
  14.105+		break;
  14.106+	case DTE_ZXT:
  14.107+	case DTE_SXT:
  14.108+		fmtprint(f, "%s R%d, $%d, R%d", opcodes[op], a, b, c);
  14.109+		break;
  14.110+	case DTE_RET:
  14.111+		fmtprint(f, "RET R%d", a);
  14.112+		break;
  14.113+	default:
  14.114+		fmtprint(f, "??? (%#.8ux)", op);
  14.115+		break;
  14.116+	}
  14.117+	return 0;
  14.118+}
    15.1new file mode 100644
    15.2--- /dev/null
    15.3+++ b/sys/src/libdtracy/mkfile
    15.4@@ -0,0 +1,20 @@
    15.5+</$objtype/mkfile
    15.6+
    15.7+LIB=/$objtype/lib/libdtracy.a
    15.8+
    15.9+OFILES=\
   15.10+	prov.$O\
   15.11+	prog.$O\
   15.12+	dtefmt.$O\
   15.13+	pack.$O\
   15.14+	chan.$O\
   15.15+
   15.16+HFILES=\
   15.17+	/sys/include/dtracy.h\
   15.18+
   15.19+UPDATE=\
   15.20+	mkfile\
   15.21+	$HFILES\
   15.22+	${OFILES:%.$O=%.c}\
   15.23+
   15.24+</sys/src/cmd/mksyslib
    16.1new file mode 100644
    16.2--- /dev/null
    16.3+++ b/sys/src/libdtracy/pack.c
    16.4@@ -0,0 +1,191 @@
    16.5+#include <u.h>
    16.6+#include <libc.h>
    16.7+#include <dtracy.h>
    16.8+
    16.9+static void
   16.10+dtepack(Fmt *f, DTExpr *e)
   16.11+{
   16.12+	int i;
   16.13+
   16.14+	fmtprint(f, "e%d\n", e->n);
   16.15+	for(i = 0; i < e->n; i++)
   16.16+		fmtprint(f, "%#.8ux\n", e->b[i]);
   16.17+}
   16.18+
   16.19+void
   16.20+dtgpack(Fmt *f, DTActGr *g)
   16.21+{
   16.22+	int i;
   16.23+
   16.24+	fmtprint(f, "g%ud\n", g->id);
   16.25+	if(g->pred != nil){
   16.26+		fmtprint(f, "p");
   16.27+		dtepack(f, g->pred);
   16.28+	}
   16.29+	fmtprint(f, "a%d\n", g->nact);
   16.30+	for(i = 0; i < g->nact; i++){
   16.31+		fmtprint(f, "t%d\n", g->acts[i].type);
   16.32+		fmtprint(f, "s%d\n", g->acts[i].size);
   16.33+		dtepack(f, g->acts[i].p);
   16.34+	}
   16.35+	fmtprint(f, "G");
   16.36+}
   16.37+
   16.38+void
   16.39+dtclpack(Fmt *f, DTClause *c)
   16.40+{
   16.41+	int i;
   16.42+
   16.43+	fmtprint(f, "c%d\n", c->nprob);
   16.44+	for(i = 0; i < c->nprob; i++)
   16.45+		fmtprint(f, "%s\n", c->probs[i]);
   16.46+	dtgpack(f, c->gr);
   16.47+}
   16.48+
   16.49+static char *
   16.50+u32unpack(char *s, u32int *np)
   16.51+{
   16.52+	char *r;
   16.53+	
   16.54+	*np = strtoul(s, &r, 0);
   16.55+	if(r == s || *r != '\n') return nil;
   16.56+	return r + 1;
   16.57+}
   16.58+
   16.59+static char *
   16.60+dteunpack(char *s, DTExpr **rp)
   16.61+{
   16.62+	int i;
   16.63+	u32int n;
   16.64+	DTExpr *e;
   16.65+
   16.66+	*rp = nil;
   16.67+	if(*s++ != 'e') return nil;
   16.68+	s = u32unpack(s, &n);
   16.69+	if(s == nil) return nil;
   16.70+	e = dtmalloc(sizeof(DTExpr) + n * sizeof(u32int));
   16.71+	e->n = n;
   16.72+	e->b = (void*)(e + 1);
   16.73+	for(i = 0; i < n; i++){
   16.74+		s = u32unpack(s, &e->b[i]);
   16.75+		if(s == nil){
   16.76+			dtfree(e);
   16.77+			return nil;
   16.78+		}
   16.79+	}
   16.80+	*rp = e;
   16.81+	return s;
   16.82+}
   16.83+
   16.84+void
   16.85+dtgfree(DTActGr *g)
   16.86+{
   16.87+	int i;
   16.88+
   16.89+	if(g == nil) return;
   16.90+	for(i = 0; i < g->nact; i++)
   16.91+		dtfree(g->acts[i].p);
   16.92+	dtfree(g->acts);
   16.93+	dtfree(g->pred);
   16.94+	dtfree(g);
   16.95+
   16.96+}
   16.97+
   16.98+char *
   16.99+dtgunpack(char *s, DTActGr **rp)
  16.100+{
  16.101+	DTActGr *g;
  16.102+	u32int n;
  16.103+	int i;
  16.104+
  16.105+	*rp = nil;
  16.106+	g = dtmalloc(sizeof(DTActGr));
  16.107+	g->reclen = 12;
  16.108+	g->ref = 1;
  16.109+	if(*s++ != 'g') goto fail;
  16.110+	s = u32unpack(s, &g->id);
  16.111+	if(s == nil) goto fail;
  16.112+	for(;;)
  16.113+		switch(*s++){
  16.114+		case 'p':
  16.115+			s = dteunpack(s, &g->pred);
  16.116+			if(s == nil) goto fail;
  16.117+			break;
  16.118+		case 'a':
  16.119+			s = u32unpack(s, &n);
  16.120+			if(s == nil) goto fail;
  16.121+			g->acts = dtmalloc(n * sizeof(DTAct));
  16.122+			g->nact = n;
  16.123+			for(i = 0; i < n; i++){
  16.124+				if(*s++ != 't') goto fail;
  16.125+				s = u32unpack(s, (u32int *) &g->acts[i].type);
  16.126+				if(s == nil) goto fail;
  16.127+				if(*s++ != 's') goto fail;
  16.128+				s = u32unpack(s, (u32int *) &g->acts[i].size);
  16.129+				if(s == nil) goto fail;
  16.130+				s = dteunpack(s, &g->acts[i].p);
  16.131+				if(s == nil) goto fail;
  16.132+				switch(g->acts[i].type){
  16.133+				case ACTTRACE:
  16.134+					g->reclen += g->acts[i].size;
  16.135+					break;
  16.136+				case ACTTRACESTR:
  16.137+					g->reclen += g->acts[i].size;
  16.138+					break;
  16.139+				default:
  16.140+					goto fail;
  16.141+				}
  16.142+			}
  16.143+			break;
  16.144+		case 'G':
  16.145+			*rp = g;
  16.146+			return s;
  16.147+		default: goto fail;
  16.148+		}
  16.149+fail:
  16.150+	dtgfree(g);
  16.151+	return nil;
  16.152+}
  16.153+
  16.154+char *
  16.155+dtclunpack(char *s, DTClause **rp)
  16.156+{
  16.157+	DTClause *c;
  16.158+	char *e;
  16.159+	int i;
  16.160+	
  16.161+	*rp = nil;
  16.162+	c = dtmalloc(sizeof(DTClause));
  16.163+	if(*s++ != 'c') goto fail;
  16.164+	s = u32unpack(s, (u32int*) &c->nprob);
  16.165+	if(s == nil) goto fail;
  16.166+	c->probs = dtmalloc(sizeof(char *) * c->nprob);
  16.167+	for(i = 0; i < c->nprob; i++){
  16.168+		e = strchr(s, '\n');
  16.169+		if(e == nil) goto fail;
  16.170+		c->probs[i] = dtmalloc(e - s + 1);
  16.171+		memmove(c->probs[i], s, e - s);
  16.172+		s = e + 1;
  16.173+	}
  16.174+	s = dtgunpack(s, &c->gr);
  16.175+	if(s == nil) goto fail;
  16.176+	*rp = c;
  16.177+	return s;
  16.178+fail:
  16.179+	dtclfree(c);
  16.180+	return nil;
  16.181+}
  16.182+
  16.183+void
  16.184+dtclfree(DTClause *c)
  16.185+{
  16.186+	int i;
  16.187+
  16.188+	if(c == nil) return;
  16.189+	if(--c->gr->ref == 0)
  16.190+		dtgfree(c->gr);
  16.191+	for(i = 0; i < c->nprob; i++)
  16.192+		free(c->probs[i]);
  16.193+	free(c->probs);
  16.194+	free(c);
  16.195+}
    17.1new file mode 100644
    17.2--- /dev/null
    17.3+++ b/sys/src/libdtracy/prog.c
    17.4@@ -0,0 +1,286 @@
    17.5+#include <u.h>
    17.6+#include <libc.h>
    17.7+#include <dtracy.h>
    17.8+
    17.9+int
   17.10+dteverify(DTExpr *p)
   17.11+{
   17.12+	int i, nregs;
   17.13+	u32int ins;
   17.14+	u8int a, b, c;
   17.15+	
   17.16+	nregs = 16;
   17.17+	for(i = 0; i < p->n; i++){
   17.18+		ins = p->b[i];
   17.19+		
   17.20+		a = ins >> 16;
   17.21+		b = ins >> 8;
   17.22+		c = ins;
   17.23+		switch(ins>>24){
   17.24+		case DTE_ADD:
   17.25+			if(ins == 0) continue;
   17.26+			/* wet floor */
   17.27+		case DTE_SUB:
   17.28+		case DTE_MUL:
   17.29+		case DTE_UDIV:
   17.30+		case DTE_UMOD:
   17.31+		case DTE_SDIV:
   17.32+		case DTE_SMOD:
   17.33+		case DTE_AND:
   17.34+		case DTE_OR:
   17.35+		case DTE_XOR:
   17.36+		case DTE_XNOR:
   17.37+		case DTE_LSL:
   17.38+		case DTE_LSR:
   17.39+		case DTE_ASR:
   17.40+		case DTE_SEQ:
   17.41+		case DTE_SNE:
   17.42+		case DTE_SLT:
   17.43+		case DTE_SLE:
   17.44+			if(a >= nregs || b >= nregs || c >= nregs || c == 0)
   17.45+				goto invalid;
   17.46+			break;
   17.47+		case DTE_LDI:
   17.48+		case DTE_XORI:
   17.49+			if(c >= nregs || c == 0)
   17.50+				goto invalid;
   17.51+			break;
   17.52+		case DTE_BEQ:
   17.53+		case DTE_BNE:
   17.54+		case DTE_BLT:
   17.55+		case DTE_BLE:
   17.56+			if(a >= nregs || b >= nregs || i + 1 + c >= p->n)
   17.57+				goto invalid;
   17.58+			break;
   17.59+		case DTE_RET:
   17.60+			if(a >= nregs || b != 0 || c != 0)
   17.61+				goto invalid;
   17.62+			break;
   17.63+		case DTE_LDV:
   17.64+			if(a >= DTNVARS || b >= nregs)
   17.65+				goto invalid;
   17.66+			break;
   17.67+		case DTE_ZXT:
   17.68+		case DTE_SXT:
   17.69+			if(a >= nregs || b == 0 || b > 64 || c >= nregs)
   17.70+				goto invalid;
   17.71+		default: goto invalid;
   17.72+		}
   17.73+	}
   17.74+	if(p->n == 0 || p->b[p->n - 1] >> 24 != DTE_RET){
   17.75+		werrstr("must end with RET");
   17.76+		return -1;
   17.77+	}
   17.78+	return 0;
   17.79+
   17.80+invalid:
   17.81+	werrstr("invalid instruction %#.8ux @ %#.4ux", ins, i);
   17.82+	return -1;
   17.83+}
   17.84+
   17.85+int
   17.86+dtgverify(DTActGr *g)
   17.87+{
   17.88+	int i;
   17.89+
   17.90+	if(g->pred != nil && dteverify(g->pred) < 0)
   17.91+		return -1;
   17.92+	for(i = 0; i < g->nact; i++)
   17.93+		switch(g->acts[i].type){
   17.94+		case ACTTRACE:
   17.95+			if(g->acts[i].p == nil || dteverify(g->acts[i].p) < 0 || (uint)g->acts[i].size > 8)
   17.96+				return -1;
   17.97+			break;
   17.98+		case ACTTRACESTR:
   17.99+			if(g->acts[i].p == nil || dteverify(g->acts[i].p) < 0 || (uint)g->acts[i].size > DTRECMAX)
  17.100+				return -1;
  17.101+			break;
  17.102+		default:
  17.103+			return -1;
  17.104+		}
  17.105+	return 0;
  17.106+}
  17.107+
  17.108+typedef struct ExecInfo ExecInfo;
  17.109+struct ExecInfo {
  17.110+	int machno;
  17.111+	int epid;
  17.112+	u64int ts;
  17.113+	u64int arg[10];
  17.114+	DTChan *ch;
  17.115+};
  17.116+
  17.117+int
  17.118+dteexec(DTExpr *p, ExecInfo *info, s64int *retv)
  17.119+{
  17.120+	s64int R[16];
  17.121+	u32int ins;
  17.122+	u8int a, b, c;
  17.123+	int i;
  17.124+	
  17.125+	R[0] = 0;
  17.126+	for(i = 0;; i++){
  17.127+		ins = p->b[i];
  17.128+		a = ins >> 16;
  17.129+		b = ins >> 8;
  17.130+		c = ins;
  17.131+		switch(ins >> 24){
  17.132+		case DTE_ADD: R[c] = R[a] + R[b]; break;
  17.133+		case DTE_SUB: R[c] = R[a] - R[b]; break;
  17.134+		case DTE_MUL: R[c] = R[a] * R[b]; break;
  17.135+		case DTE_SDIV: if(R[b] == 0) goto div0; R[c] = R[a] / R[b]; break;
  17.136+		case DTE_SMOD: if(R[b] == 0) goto div0; R[c] = R[a] % R[b]; break;
  17.137+		case DTE_UDIV: if(R[b] == 0) goto div0; R[c] = (uvlong)R[a] / (uvlong)R[b]; break;
  17.138+		case DTE_UMOD: if(R[b] == 0) goto div0; R[c] = (uvlong)R[a] % (uvlong)R[b]; break;
  17.139+		case DTE_AND: R[c] = R[a] & R[b]; break;
  17.140+		case DTE_OR: R[c] = R[a] | R[b]; break;
  17.141+		case DTE_XOR: R[c] = R[a] ^ R[b]; break;
  17.142+		case DTE_XNOR: R[c] = ~(R[a] ^ R[b]); break;
  17.143+		case DTE_LDI: R[c] = (s64int)ins << 40 >> 54 << (ins >> 8 & 63); break;
  17.144+		case DTE_XORI: R[c] |= (s64int)ins << 40 >> 54 << (ins >> 8 & 63); break;
  17.145+		case DTE_LSL:
  17.146+			if((u64int)R[b] >= 64)
  17.147+				R[c] = 0;
  17.148+			else
  17.149+				R[c] = R[a] << R[b];
  17.150+			break;
  17.151+		case DTE_LSR:
  17.152+			if((u64int)R[b] >= 64)
  17.153+				R[c] = 0;
  17.154+			else
  17.155+				R[c] = (u64int)R[a] >> R[b];
  17.156+			break;
  17.157+		case DTE_ASR:
  17.158+			if((u64int)R[b] >= 64)
  17.159+				R[c] = R[a] >> 63;
  17.160+			else
  17.161+				R[c] = R[a] >> R[b];
  17.162+			break;
  17.163+		case DTE_SEQ: R[c] = R[a] == R[b]; break;
  17.164+		case DTE_SNE: R[c] = R[a] != R[b]; break;
  17.165+		case DTE_SLT: R[c] = R[a] < R[b]; break;
  17.166+		case DTE_SLE: R[c] = R[a] <= R[b]; break;
  17.167+		case DTE_BEQ: if(R[a] == R[b]) i += c; break;
  17.168+		case DTE_BNE: if(R[a] != R[b]) i += c; break;
  17.169+		case DTE_BLT: if(R[a] < R[b]) i += c; break;
  17.170+		case DTE_BLE: if(R[a] <= R[b]) i += c; break;
  17.171+		case DTE_LDV:
  17.172+			switch(a){
  17.173+			case DTV_ARG0:
  17.174+			case DTV_ARG1:
  17.175+			case DTV_ARG2:
  17.176+			case DTV_ARG3:
  17.177+			case DTV_ARG4:
  17.178+			case DTV_ARG5:
  17.179+			case DTV_ARG6:
  17.180+			case DTV_ARG7:
  17.181+			case DTV_ARG8:
  17.182+			case DTV_ARG9:
  17.183+				R[b] = info->arg[a - DTV_ARG0];
  17.184+				break;
  17.185+			case DTV_TIME: R[b] = info->ts; break;
  17.186+			case DTV_MACHNO: R[b] = info->machno; break;
  17.187+			default:
  17.188+				R[b] = dtgetvar(a);
  17.189+				break;
  17.190+			}
  17.191+		case DTE_ZXT: R[c] = (uvlong)R[a] << 64 - b >> 64 - b; break;
  17.192+		case DTE_SXT: R[c] = (vlong)R[a] << 64 - b >> 64 - b; break;
  17.193+		case DTE_RET: *retv = R[a]; return 0;
  17.194+		}
  17.195+	}
  17.196+
  17.197+div0:
  17.198+	snprint(info->ch->errstr, sizeof(info->ch->errstr), "division by zero");
  17.199+	return -1;
  17.200+}
  17.201+
  17.202+int
  17.203+dtpeekstr(uvlong addr, u8int *v, int len)
  17.204+{
  17.205+	int i;
  17.206+	
  17.207+	for(i = 0; i < len; i++){
  17.208+		if(addr + i < addr || dtpeek(addr + i, &v[i], 1) < 0){
  17.209+			memset(v, 0, len);
  17.210+			return -1;
  17.211+		}
  17.212+		if(v[i] == 0)
  17.213+			break;
  17.214+	}
  17.215+	if(i < len)
  17.216+		memset(&v[i], 0, len - i);
  17.217+	return 0;
  17.218+}
  17.219+
  17.220+#define PUT1(c) *bp++ = c;
  17.221+#define PUT2(c) *bp++ = c; *bp++ = c >> 8;
  17.222+#define PUT4(c) *bp++ = c; *bp++ = c >> 8; *bp++ = c >> 16; *bp++ = c >> 24;
  17.223+#define PUT8(c) PUT4(c); PUT4(c>>32);
  17.224+
  17.225+static int
  17.226+dtgexec(DTActGr *g, ExecInfo *info)
  17.227+{
  17.228+	DTBuf *b;
  17.229+	u8int *bp;
  17.230+	s64int v;
  17.231+	int i, j;
  17.232+	
  17.233+	b = g->chan->wrbufs[info->machno];
  17.234+	if(b->wr + g->reclen > DTBUFSZ)
  17.235+		return 0;
  17.236+	if(g->pred != nil){
  17.237+		if(dteexec(g->pred, info, &v) < 0)
  17.238+			return -1;
  17.239+		if(v == 0)
  17.240+			return 0;
  17.241+	}
  17.242+	bp = &b->data[b->wr];
  17.243+	PUT4(info->epid);
  17.244+	PUT8(info->ts);
  17.245+	for(i = 0; i < g->nact; i++){
  17.246+		if(dteexec(g->acts[i].p, info, &v) < 0)
  17.247+			return -1;
  17.248+		switch(g->acts[i].type){
  17.249+		case ACTTRACE:
  17.250+			for(j = 0; j < g->acts[i].size; j++){
  17.251+				*bp++ = v;
  17.252+				v >>= 8;
  17.253+			}
  17.254+			break;
  17.255+		case ACTTRACESTR:
  17.256+			if(dtpeekstr(v, bp, g->acts[i].size) < 0){
  17.257+				snprint(info->ch->errstr, sizeof(info->ch->errstr), "fault @ %#llux", v);
  17.258+				return -1;
  17.259+			}
  17.260+			bp += g->acts[i].size;
  17.261+			break;
  17.262+		}
  17.263+	}
  17.264+	assert(bp - b->data - b->wr == g->reclen);
  17.265+	b->wr = bp - b->data;
  17.266+	return 0;
  17.267+}
  17.268+
  17.269+void
  17.270+dtptrigger(DTProbe *p, int machno, uvlong arg0, uvlong arg1, uvlong arg2, uvlong arg3)
  17.271+{
  17.272+	DTEnab *e;
  17.273+	ExecInfo info;
  17.274+	
  17.275+	info.ts = dttime();
  17.276+	dtmachlock(machno);
  17.277+	info.machno = machno;
  17.278+	info.arg[0] = arg0;
  17.279+	info.arg[1] = arg1;
  17.280+	info.arg[2] = arg2;
  17.281+	info.arg[3] = arg3;
  17.282+	for(e = p->enablist.probnext; e != &p->enablist; e = e->probnext)
  17.283+		if(e->gr->chan->state == DTCGO){
  17.284+			info.ch = e->gr->chan;
  17.285+			info.epid = e->epid;
  17.286+			if(dtgexec(e->gr, &info) < 0)
  17.287+				e->gr->chan->state = DTCFAULT;
  17.288+		}
  17.289+	dtmachunlock(machno);
  17.290+}
    18.1new file mode 100644
    18.2--- /dev/null
    18.3+++ b/sys/src/libdtracy/prov.c
    18.4@@ -0,0 +1,76 @@
    18.5+#include <u.h>
    18.6+#include <libc.h>
    18.7+#include <dtracy.h>
    18.8+
    18.9+char *
   18.10+dtstrdup(char *n)
   18.11+{
   18.12+	char *m;
   18.13+	
   18.14+	m = dtmalloc(strlen(n) + 1);
   18.15+	strcpy(m, n);
   18.16+	setmalloctag(m, getcallerpc(&n));
   18.17+	return m;
   18.18+}
   18.19+
   18.20+DTProbe *
   18.21+dtpnew(DTName name, DTProvider *prov, void *aux)
   18.22+{
   18.23+	DTProbe *p, **pp;
   18.24+
   18.25+	p = dtmalloc(sizeof(DTProbe));
   18.26+	p->provider = dtstrdup(name.provider);
   18.27+	p->function = dtstrdup(name.function);
   18.28+	p->name = dtstrdup(name.name);
   18.29+	p->prov = prov;
   18.30+	p->aux = aux;
   18.31+	p->enablist.probnext = p->enablist.probprev = &p->enablist;
   18.32+	for(pp = &prov->probes; *pp != nil; pp = &(*pp)->provnext)
   18.33+		;
   18.34+	*pp = p;
   18.35+	return p;
   18.36+}
   18.37+
   18.38+int
   18.39+dtstrmatch(char *a, char *b)
   18.40+{
   18.41+	if(a == nil || *a == 0) return 1;
   18.42+	if(b == nil) return 0;
   18.43+	return strcmp(a, b) == 0;
   18.44+}
   18.45+
   18.46+int
   18.47+dtpmatch(DTName name, DTProbe ***ret)
   18.48+{
   18.49+	DTProbe **l;
   18.50+	int nl;
   18.51+	DTProvider **provp, *prov;
   18.52+	DTProbe **pp, *p;
   18.53+	
   18.54+	l = nil;
   18.55+	nl = 0;
   18.56+	for(provp = dtproviders; prov = *provp, prov != nil; provp++){
   18.57+		if(!dtstrmatch(name.provider, prov->name))
   18.58+			continue;
   18.59+		for(pp = &prov->probes; p = *pp, p != nil; pp = &p->provnext)
   18.60+			if(dtstrmatch(name.function, p->function) && dtstrmatch(name.name, p->name)){
   18.61+				if(ret != nil){
   18.62+					l = dtrealloc(l, (nl + 1) * sizeof(DTProbe *));
   18.63+					l[nl] = p;
   18.64+				}
   18.65+				nl++;
   18.66+			}
   18.67+		prov->provide(prov, name);
   18.68+		for(; p = *pp, p != nil; pp = &p->provnext)
   18.69+			if(dtstrmatch(name.function, p->function) && dtstrmatch(name.name, p->name)){
   18.70+				if(ret != nil){
   18.71+					l = dtrealloc(l, (nl + 1) * sizeof(DTProbe *));
   18.72+					l[nl] = p;
   18.73+				}
   18.74+				nl++;
   18.75+			}
   18.76+	}
   18.77+	if(ret != nil)
   18.78+		*ret = l;
   18.79+	return nl;
   18.80+}