xref: /plan9-contrib/sys/src/9k/port/devptrace.c (revision d46407a37b53d968b453d19c0e464c526df5e227)
1*d46407a3SDavid du Colombier #include	"u.h"
2*d46407a3SDavid du Colombier #include	"../port/lib.h"
3*d46407a3SDavid du Colombier #include	"mem.h"
4*d46407a3SDavid du Colombier #include	"dat.h"
5*d46407a3SDavid du Colombier #include	"fns.h"
6*d46407a3SDavid du Colombier #include	"../port/error.h"
7*d46407a3SDavid du Colombier #include	"netif.h"
8*d46407a3SDavid du Colombier 
9*d46407a3SDavid du Colombier #include	<ptrace.h>
10*d46407a3SDavid du Colombier 
11*d46407a3SDavid du Colombier 
12*d46407a3SDavid du Colombier enum {
13*d46407a3SDavid du Colombier 	Qdir,
14*d46407a3SDavid du Colombier 	Qctl,
15*d46407a3SDavid du Colombier 	Qdata,
16*d46407a3SDavid du Colombier };
17*d46407a3SDavid du Colombier 
18*d46407a3SDavid du Colombier enum {
19*d46407a3SDavid du Colombier 	CMsize,
20*d46407a3SDavid du Colombier 	CMtrace,
21*d46407a3SDavid du Colombier };
22*d46407a3SDavid du Colombier 
23*d46407a3SDavid du Colombier static Dirtab tracedir[]=
24*d46407a3SDavid du Colombier {
25*d46407a3SDavid du Colombier 	".",			{Qdir, 0, QTDIR},	0,		DMDIR|0555,
26*d46407a3SDavid du Colombier 	"ptracectl",	{Qctl},		0,		0664,
27*d46407a3SDavid du Colombier 	"ptrace",		{Qdata},	0,		0440,
28*d46407a3SDavid du Colombier };
29*d46407a3SDavid du Colombier 
30*d46407a3SDavid du Colombier static Lock tlk;
31*d46407a3SDavid du Colombier static int topens;
32*d46407a3SDavid du Colombier static int tproduced, tconsumed, ntevents, ntmask;
33*d46407a3SDavid du Colombier static uchar *tevents;
34*d46407a3SDavid du Colombier 
35*d46407a3SDavid du Colombier static Chan*
traceattach(char * spec)36*d46407a3SDavid du Colombier traceattach(char *spec)
37*d46407a3SDavid du Colombier {
38*d46407a3SDavid du Colombier 	return devattach(L'σ', spec);
39*d46407a3SDavid du Colombier }
40*d46407a3SDavid du Colombier 
41*d46407a3SDavid du Colombier static Walkqid*
tracewalk(Chan * c,Chan * nc,char ** name,int nname)42*d46407a3SDavid du Colombier tracewalk(Chan *c, Chan *nc, char **name, int nname)
43*d46407a3SDavid du Colombier {
44*d46407a3SDavid du Colombier 	return devwalk(c, nc, name, nname, tracedir, nelem(tracedir), devgen);
45*d46407a3SDavid du Colombier }
46*d46407a3SDavid du Colombier 
47*d46407a3SDavid du Colombier static long
tracestat(Chan * c,uchar * db,long n)48*d46407a3SDavid du Colombier tracestat(Chan *c, uchar *db, long n)
49*d46407a3SDavid du Colombier {
50*d46407a3SDavid du Colombier 	return devstat(c, db, n, tracedir, nelem(tracedir), devgen);
51*d46407a3SDavid du Colombier }
52*d46407a3SDavid du Colombier 
53*d46407a3SDavid du Colombier static void
_ptrace(Proc * p,int etype,vlong ts,vlong arg)54*d46407a3SDavid du Colombier _ptrace(Proc *p, int etype, vlong ts, vlong arg)
55*d46407a3SDavid du Colombier {
56*d46407a3SDavid du Colombier 	int i;
57*d46407a3SDavid du Colombier 	uchar *te;
58*d46407a3SDavid du Colombier 
59*d46407a3SDavid du Colombier 	if (p->trace == 0 || topens == 0)
60*d46407a3SDavid du Colombier 		return;
61*d46407a3SDavid du Colombier 
62*d46407a3SDavid du Colombier 	lock(&tlk);
63*d46407a3SDavid du Colombier 	if (p->trace == 0 || topens == 0 || tproduced - tconsumed >= ntevents){
64*d46407a3SDavid du Colombier 		unlock(&tlk);
65*d46407a3SDavid du Colombier 		return;
66*d46407a3SDavid du Colombier 	}
67*d46407a3SDavid du Colombier 	if(ts == 0)
68*d46407a3SDavid du Colombier 		ts = todget(nil);
69*d46407a3SDavid du Colombier 	i = (tproduced&ntmask) * PTsize;
70*d46407a3SDavid du Colombier 	te = &tevents[i];
71*d46407a3SDavid du Colombier 	PBIT32(te, (int)p->pid);
72*d46407a3SDavid du Colombier 	te += BIT32SZ;
73*d46407a3SDavid du Colombier 	PBIT32(te, etype);
74*d46407a3SDavid du Colombier 	te += BIT32SZ;
75*d46407a3SDavid du Colombier 	PBIT32(te, m->machno);
76*d46407a3SDavid du Colombier 	te += BIT32SZ;
77*d46407a3SDavid du Colombier 	PBIT64(te, ts);
78*d46407a3SDavid du Colombier 	te += BIT64SZ;
79*d46407a3SDavid du Colombier 	PBIT64(te, arg);
80*d46407a3SDavid du Colombier 	tproduced++;
81*d46407a3SDavid du Colombier 	if(etype == SDead)
82*d46407a3SDavid du Colombier 		p->trace = 0;
83*d46407a3SDavid du Colombier 	unlock(&tlk);
84*d46407a3SDavid du Colombier }
85*d46407a3SDavid du Colombier 
86*d46407a3SDavid du Colombier 
87*d46407a3SDavid du Colombier static Chan*
traceopen(Chan * c,int omode)88*d46407a3SDavid du Colombier traceopen(Chan *c, int omode)
89*d46407a3SDavid du Colombier {
90*d46407a3SDavid du Colombier 	int q;
91*d46407a3SDavid du Colombier 
92*d46407a3SDavid du Colombier 	q = c->qid.path;
93*d46407a3SDavid du Colombier 	switch(q){
94*d46407a3SDavid du Colombier 	case Qdata:
95*d46407a3SDavid du Colombier 		lock(&tlk);
96*d46407a3SDavid du Colombier 		if (waserror()){
97*d46407a3SDavid du Colombier 			unlock(&tlk);
98*d46407a3SDavid du Colombier 			nexterror();
99*d46407a3SDavid du Colombier 		}
100*d46407a3SDavid du Colombier 		if(topens > 0)
101*d46407a3SDavid du Colombier 			error(Einuse);
102*d46407a3SDavid du Colombier 		if(ntevents == 0)
103*d46407a3SDavid du Colombier 			error("must set trace size first");
104*d46407a3SDavid du Colombier 		if(up->trace != 0)
105*d46407a3SDavid du Colombier 			error("a traced process can't open the trace device");
106*d46407a3SDavid du Colombier 		tproduced = tconsumed = 0;
107*d46407a3SDavid du Colombier 		proctrace = _ptrace;
108*d46407a3SDavid du Colombier 		topens++;
109*d46407a3SDavid du Colombier 		poperror();
110*d46407a3SDavid du Colombier 		unlock(&tlk);
111*d46407a3SDavid du Colombier 		break;
112*d46407a3SDavid du Colombier 	}
113*d46407a3SDavid du Colombier 	c = devopen(c, omode, tracedir, nelem(tracedir), devgen);
114*d46407a3SDavid du Colombier 	return c;
115*d46407a3SDavid du Colombier }
116*d46407a3SDavid du Colombier 
117*d46407a3SDavid du Colombier static void
traceclose(Chan * c)118*d46407a3SDavid du Colombier traceclose(Chan *c)
119*d46407a3SDavid du Colombier {
120*d46407a3SDavid du Colombier 	int q;
121*d46407a3SDavid du Colombier 
122*d46407a3SDavid du Colombier 	q = c->qid.path;
123*d46407a3SDavid du Colombier 	switch(q){
124*d46407a3SDavid du Colombier 	case Qdata:
125*d46407a3SDavid du Colombier 		if(c->flag & COPEN){
126*d46407a3SDavid du Colombier 			lock(&tlk);
127*d46407a3SDavid du Colombier 			topens--;
128*d46407a3SDavid du Colombier 			tproduced = tconsumed = 0;
129*d46407a3SDavid du Colombier 			proctrace = nil;
130*d46407a3SDavid du Colombier 			unlock(&tlk);
131*d46407a3SDavid du Colombier 		}
132*d46407a3SDavid du Colombier 	}
133*d46407a3SDavid du Colombier }
134*d46407a3SDavid du Colombier 
135*d46407a3SDavid du Colombier static long
traceread(Chan * c,void * a,long n,vlong offset)136*d46407a3SDavid du Colombier traceread(Chan *c, void *a, long n, vlong offset)
137*d46407a3SDavid du Colombier {
138*d46407a3SDavid du Colombier 	int q, xopens, xevents, xprod, xcons, navail, ne, i;
139*d46407a3SDavid du Colombier 	char *s, *e;
140*d46407a3SDavid du Colombier 
141*d46407a3SDavid du Colombier 	q = c->qid.path;
142*d46407a3SDavid du Colombier 	switch(q){
143*d46407a3SDavid du Colombier 	case Qdir:
144*d46407a3SDavid du Colombier 		return devdirread(c, a, n, tracedir, nelem(tracedir), devgen);
145*d46407a3SDavid du Colombier 		break;
146*d46407a3SDavid du Colombier 	case Qctl:
147*d46407a3SDavid du Colombier 		e = up->genbuf + sizeof up->genbuf;
148*d46407a3SDavid du Colombier 		lock(&tlk);
149*d46407a3SDavid du Colombier 		xopens = topens;
150*d46407a3SDavid du Colombier 		xevents = ntevents;
151*d46407a3SDavid du Colombier 		xprod = tproduced;
152*d46407a3SDavid du Colombier 		xcons = tconsumed;
153*d46407a3SDavid du Colombier 		unlock(&tlk);
154*d46407a3SDavid du Colombier 		s = seprint(up->genbuf, e, "opens %d\n", xopens);
155*d46407a3SDavid du Colombier 		s = seprint(s, e, "size %d\n", xevents);
156*d46407a3SDavid du Colombier 		s = seprint(s, e, "produced %d\n", xprod);
157*d46407a3SDavid du Colombier 		seprint(s, e, "consumed %d\n", xcons);
158*d46407a3SDavid du Colombier 		return readstr(offset, a, n, up->genbuf);
159*d46407a3SDavid du Colombier 		break;
160*d46407a3SDavid du Colombier 	case Qdata:
161*d46407a3SDavid du Colombier 		/* no locks! */
162*d46407a3SDavid du Colombier 		navail = tproduced - tconsumed;
163*d46407a3SDavid du Colombier 		if(navail <= 0)
164*d46407a3SDavid du Colombier 			return 0;
165*d46407a3SDavid du Colombier 		if(navail > n / PTsize)
166*d46407a3SDavid du Colombier 			navail = n / PTsize;
167*d46407a3SDavid du Colombier 		s = a;
168*d46407a3SDavid du Colombier 		e = a;
169*d46407a3SDavid du Colombier 		while(navail > 0) {
170*d46407a3SDavid du Colombier 			if((tconsumed & ntmask) + navail > ntevents)
171*d46407a3SDavid du Colombier 				ne = ntevents - (tconsumed & ntmask);
172*d46407a3SDavid du Colombier 			else
173*d46407a3SDavid du Colombier 				ne = navail;
174*d46407a3SDavid du Colombier 			i = ne * PTsize;
175*d46407a3SDavid du Colombier 			memmove(e, &tevents[(tconsumed & ntmask)*PTsize], i);
176*d46407a3SDavid du Colombier 
177*d46407a3SDavid du Colombier 			tconsumed += ne;
178*d46407a3SDavid du Colombier 			e += i;
179*d46407a3SDavid du Colombier 			navail -= ne;
180*d46407a3SDavid du Colombier 		}
181*d46407a3SDavid du Colombier 		return e - s;
182*d46407a3SDavid du Colombier 		break;
183*d46407a3SDavid du Colombier 	default:
184*d46407a3SDavid du Colombier 		error(Egreg);
185*d46407a3SDavid du Colombier 	}
186*d46407a3SDavid du Colombier 	error("not yet implemented");
187*d46407a3SDavid du Colombier 	return -1;
188*d46407a3SDavid du Colombier }
189*d46407a3SDavid du Colombier 
190*d46407a3SDavid du Colombier static Cmdtab proccmd[] =
191*d46407a3SDavid du Colombier {
192*d46407a3SDavid du Colombier 	CMsize,		"size",		2,
193*d46407a3SDavid du Colombier 	CMtrace,	"trace",	0,
194*d46407a3SDavid du Colombier };
195*d46407a3SDavid du Colombier 
196*d46407a3SDavid du Colombier static long
tracewrite(Chan * c,void * a,long n,vlong)197*d46407a3SDavid du Colombier tracewrite(Chan *c, void *a, long n, vlong)
198*d46407a3SDavid du Colombier {
199*d46407a3SDavid du Colombier 	int i, q, sz, msk, pid;
200*d46407a3SDavid du Colombier 	Cmdbuf *cb;
201*d46407a3SDavid du Colombier 	Cmdtab *ct;
202*d46407a3SDavid du Colombier 	uchar *nt;
203*d46407a3SDavid du Colombier 	Proc *p;
204*d46407a3SDavid du Colombier 
205*d46407a3SDavid du Colombier 	q = c->qid.path;
206*d46407a3SDavid du Colombier 	switch(q){
207*d46407a3SDavid du Colombier 	case Qctl:
208*d46407a3SDavid du Colombier 		break;
209*d46407a3SDavid du Colombier 	default:
210*d46407a3SDavid du Colombier 		error(Egreg);
211*d46407a3SDavid du Colombier 	}
212*d46407a3SDavid du Colombier 	cb = parsecmd(a, n);
213*d46407a3SDavid du Colombier 	if(waserror()){
214*d46407a3SDavid du Colombier 		free(cb);
215*d46407a3SDavid du Colombier 		nexterror();
216*d46407a3SDavid du Colombier 	}
217*d46407a3SDavid du Colombier 	ct = lookupcmd(cb, proccmd, nelem(proccmd));
218*d46407a3SDavid du Colombier 
219*d46407a3SDavid du Colombier 	switch(ct->index){
220*d46407a3SDavid du Colombier 	case CMsize:
221*d46407a3SDavid du Colombier 		sz = atoi(cb->f[1]);
222*d46407a3SDavid du Colombier 		if(sz == 0){
223*d46407a3SDavid du Colombier 			lock(&tlk);
224*d46407a3SDavid du Colombier 			ntevents = 0;
225*d46407a3SDavid du Colombier 			ntmask = 0;
226*d46407a3SDavid du Colombier 			unlock(&tlk);
227*d46407a3SDavid du Colombier 		}
228*d46407a3SDavid du Colombier 		msk = sz-1;
229*d46407a3SDavid du Colombier 		if((sz&msk) != 0)
230*d46407a3SDavid du Colombier 			error("wrong size. use a power of two.");
231*d46407a3SDavid du Colombier 		if(sz > 512*1024)
232*d46407a3SDavid du Colombier 			error("size is too large");
233*d46407a3SDavid du Colombier 		lock(&tlk);
234*d46407a3SDavid du Colombier 		if(waserror()){
235*d46407a3SDavid du Colombier 			unlock(&tlk);
236*d46407a3SDavid du Colombier 			nexterror();
237*d46407a3SDavid du Colombier 		}
238*d46407a3SDavid du Colombier 		if(sz > ntevents){
239*d46407a3SDavid du Colombier 			nt = realloc(tevents, PTsize * sz);
240*d46407a3SDavid du Colombier 			if(nt == nil)
241*d46407a3SDavid du Colombier 				error("not enough memory");
242*d46407a3SDavid du Colombier 			tevents = nt;
243*d46407a3SDavid du Colombier 			ntevents = sz;
244*d46407a3SDavid du Colombier 			ntmask = msk;
245*d46407a3SDavid du Colombier 		}
246*d46407a3SDavid du Colombier 		tproduced = 0;
247*d46407a3SDavid du Colombier 		tconsumed = 0;
248*d46407a3SDavid du Colombier 		poperror();
249*d46407a3SDavid du Colombier 		unlock(&tlk);
250*d46407a3SDavid du Colombier 		break;
251*d46407a3SDavid du Colombier 	case CMtrace:
252*d46407a3SDavid du Colombier 		if(cb->nf != 2 && cb->nf != 3)
253*d46407a3SDavid du Colombier 			error(Ebadctl);
254*d46407a3SDavid du Colombier 		pid = atoi(cb->f[1]);
255*d46407a3SDavid du Colombier 		i = psindex(pid);
256*d46407a3SDavid du Colombier 		if(i < 0)
257*d46407a3SDavid du Colombier 			error(Eprocdied);
258*d46407a3SDavid du Colombier 		p = psincref(i);
259*d46407a3SDavid du Colombier 		if(p == nil)
260*d46407a3SDavid du Colombier 			error(Eprocdied);
261*d46407a3SDavid du Colombier 		qlock(&p->debug);
262*d46407a3SDavid du Colombier 		if(waserror()){
263*d46407a3SDavid du Colombier 			qunlock(&p->debug);
264*d46407a3SDavid du Colombier 			psdecref(p);
265*d46407a3SDavid du Colombier 			nexterror();
266*d46407a3SDavid du Colombier 		}
267*d46407a3SDavid du Colombier 		if(p->pid != pid)
268*d46407a3SDavid du Colombier 			error(Eprocdied);
269*d46407a3SDavid du Colombier 		if(cb->nf == 2)
270*d46407a3SDavid du Colombier 			p->trace ^= p->trace;
271*d46407a3SDavid du Colombier 		else
272*d46407a3SDavid du Colombier 			p->trace = (atoi(cb->f[2]) != 0);
273*d46407a3SDavid du Colombier 		poperror();
274*d46407a3SDavid du Colombier 		qunlock(&p->debug);
275*d46407a3SDavid du Colombier 		psdecref(p);
276*d46407a3SDavid du Colombier 		break;
277*d46407a3SDavid du Colombier 	}
278*d46407a3SDavid du Colombier 
279*d46407a3SDavid du Colombier 	poperror();
280*d46407a3SDavid du Colombier 	free(cb);
281*d46407a3SDavid du Colombier 	return n;
282*d46407a3SDavid du Colombier }
283*d46407a3SDavid du Colombier 
284*d46407a3SDavid du Colombier Dev ptracedevtab = {
285*d46407a3SDavid du Colombier 	L'σ',
286*d46407a3SDavid du Colombier 	"ptrace",
287*d46407a3SDavid du Colombier 	devreset,
288*d46407a3SDavid du Colombier 	devinit,
289*d46407a3SDavid du Colombier 	devshutdown,
290*d46407a3SDavid du Colombier 	traceattach,
291*d46407a3SDavid du Colombier 	tracewalk,
292*d46407a3SDavid du Colombier 	tracestat,
293*d46407a3SDavid du Colombier 	traceopen,
294*d46407a3SDavid du Colombier 	devcreate,
295*d46407a3SDavid du Colombier 	traceclose,
296*d46407a3SDavid du Colombier 	traceread,
297*d46407a3SDavid du Colombier 	devbread,
298*d46407a3SDavid du Colombier 	tracewrite,
299*d46407a3SDavid du Colombier 	devbwrite,
300*d46407a3SDavid du Colombier 	devremove,
301*d46407a3SDavid du Colombier 	devwstat,
302*d46407a3SDavid du Colombier };
303