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