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