xref: /plan9-contrib/sys/src/9k/port/devprobe.c (revision 9ef1f84b659abcb917c5c090acbce0772e494f21)
1*9ef1f84bSDavid du Colombier #include	"u.h"
2*9ef1f84bSDavid du Colombier #include	"../port/lib.h"
3*9ef1f84bSDavid du Colombier #include	"mem.h"
4*9ef1f84bSDavid du Colombier #include	"dat.h"
5*9ef1f84bSDavid du Colombier #include	"fns.h"
6*9ef1f84bSDavid du Colombier #include	"../port/error.h"
7*9ef1f84bSDavid du Colombier 
8*9ef1f84bSDavid du Colombier #include	"probe.h"
9*9ef1f84bSDavid du Colombier 
10*9ef1f84bSDavid du Colombier enum {
11*9ef1f84bSDavid du Colombier 	Qdir,
12*9ef1f84bSDavid du Colombier 	Qctl,
13*9ef1f84bSDavid du Colombier 	Qdata,
14*9ef1f84bSDavid du Colombier };
15*9ef1f84bSDavid du Colombier 
16*9ef1f84bSDavid du Colombier enum {
17*9ef1f84bSDavid du Colombier 	ProbeEntry = 1,
18*9ef1f84bSDavid du Colombier 	ProbeExit
19*9ef1f84bSDavid du Colombier };
20*9ef1f84bSDavid du Colombier 
21*9ef1f84bSDavid du Colombier /* fix me make this programmable */
22*9ef1f84bSDavid du Colombier enum {
23*9ef1f84bSDavid du Colombier 	defaultlogsize = 1024,
24*9ef1f84bSDavid du Colombier 	printsize = 64,
25*9ef1f84bSDavid du Colombier };
26*9ef1f84bSDavid du Colombier 
27*9ef1f84bSDavid du Colombier typedef struct Probelog Probelog;
28*9ef1f84bSDavid du Colombier struct Probelog {
29*9ef1f84bSDavid du Colombier 	uvlong ticks;
30*9ef1f84bSDavid du Colombier 	/* yeah, waste a whole int on something stupid but ... */
31*9ef1f84bSDavid du Colombier 	int info;
32*9ef1f84bSDavid du Colombier 	ulong pc;
33*9ef1f84bSDavid du Colombier 	/* these are different depending on type */
34*9ef1f84bSDavid du Colombier 	long dat[4];
35*9ef1f84bSDavid du Colombier };
36*9ef1f84bSDavid du Colombier 
37*9ef1f84bSDavid du Colombier static Rendez probesleep;
38*9ef1f84bSDavid du Colombier static QLock probeslk;
39*9ef1f84bSDavid du Colombier static Probe *probes;
40*9ef1f84bSDavid du Colombier static Lock loglk;
41*9ef1f84bSDavid du Colombier static Probelog *probelog = nil;
42*9ef1f84bSDavid du Colombier /* probe indices. These are just unsigned longs. You mask them
43*9ef1f84bSDavid du Colombier  * to get an index. This makes fifo empty/full etc. trivial.
44*9ef1f84bSDavid du Colombier  */
45*9ef1f84bSDavid du Colombier static ulong pw = 0, pr = 0;
46*9ef1f84bSDavid du Colombier static int probesactive = 0;
47*9ef1f84bSDavid du Colombier static unsigned long logsize = defaultlogsize, logmask = defaultlogsize - 1;
48*9ef1f84bSDavid du Colombier 
49*9ef1f84bSDavid du Colombier static char eventname[] = {
50*9ef1f84bSDavid du Colombier 	[ProbeEntry] = 'E',
51*9ef1f84bSDavid du Colombier 	[ProbeExit] = 'X'
52*9ef1f84bSDavid du Colombier };
53*9ef1f84bSDavid du Colombier 
54*9ef1f84bSDavid du Colombier static Dirtab probedir[]={
55*9ef1f84bSDavid du Colombier 	".",		{Qdir, 0, QTDIR},	0,		DMDIR|0555,
56*9ef1f84bSDavid du Colombier 	"probectl",	{Qctl},		0,		0664,
57*9ef1f84bSDavid du Colombier 	"probe",	{Qdata},	0,		0440,
58*9ef1f84bSDavid du Colombier };
59*9ef1f84bSDavid du Colombier 
60*9ef1f84bSDavid du Colombier char hex[] = {
61*9ef1f84bSDavid du Colombier 	'0',
62*9ef1f84bSDavid du Colombier 	'1',
63*9ef1f84bSDavid du Colombier 	'2',
64*9ef1f84bSDavid du Colombier 	'3',
65*9ef1f84bSDavid du Colombier 	'4',
66*9ef1f84bSDavid du Colombier 	'5',
67*9ef1f84bSDavid du Colombier 	'6',
68*9ef1f84bSDavid du Colombier 	'7',
69*9ef1f84bSDavid du Colombier 	'8',
70*9ef1f84bSDavid du Colombier 	'9',
71*9ef1f84bSDavid du Colombier 	'A',
72*9ef1f84bSDavid du Colombier 	'B',
73*9ef1f84bSDavid du Colombier 	'C',
74*9ef1f84bSDavid du Colombier 	'D',
75*9ef1f84bSDavid du Colombier 	'E',
76*9ef1f84bSDavid du Colombier 	'F',
77*9ef1f84bSDavid du Colombier };
78*9ef1f84bSDavid du Colombier 
79*9ef1f84bSDavid du Colombier /* big-endian ... */
80*9ef1f84bSDavid du Colombier void
hex32(ulong l,char * c)81*9ef1f84bSDavid du Colombier hex32(ulong l, char *c)
82*9ef1f84bSDavid du Colombier {
83*9ef1f84bSDavid du Colombier 	int i;
84*9ef1f84bSDavid du Colombier 	for(i = 8; i; i--){
85*9ef1f84bSDavid du Colombier 		c[i-1] = hex[l&0xf];
86*9ef1f84bSDavid du Colombier 		l >>= 4;
87*9ef1f84bSDavid du Colombier 	}
88*9ef1f84bSDavid du Colombier }
89*9ef1f84bSDavid du Colombier 
90*9ef1f84bSDavid du Colombier void
hex64(uvlong l,char * c)91*9ef1f84bSDavid du Colombier hex64(uvlong l, char *c)
92*9ef1f84bSDavid du Colombier {
93*9ef1f84bSDavid du Colombier 	hex32(l>>32, c);
94*9ef1f84bSDavid du Colombier 	hex32(l, &c[8]);
95*9ef1f84bSDavid du Colombier }
96*9ef1f84bSDavid du Colombier static int
lognonempty(void *)97*9ef1f84bSDavid du Colombier lognonempty(void *)
98*9ef1f84bSDavid du Colombier {
99*9ef1f84bSDavid du Colombier 	return pw - pr;
100*9ef1f84bSDavid du Colombier }
101*9ef1f84bSDavid du Colombier 
102*9ef1f84bSDavid du Colombier static int
logfull(void)103*9ef1f84bSDavid du Colombier logfull(void)
104*9ef1f84bSDavid du Colombier {
105*9ef1f84bSDavid du Colombier 	return (pw - pr) >= logsize;
106*9ef1f84bSDavid du Colombier }
107*9ef1f84bSDavid du Colombier 
108*9ef1f84bSDavid du Colombier static ulong
idx(ulong f)109*9ef1f84bSDavid du Colombier idx(ulong f)
110*9ef1f84bSDavid du Colombier {
111*9ef1f84bSDavid du Colombier 	return f & logmask;
112*9ef1f84bSDavid du Colombier }
113*9ef1f84bSDavid du Colombier 
114*9ef1f84bSDavid du Colombier /* can return NULL, meaning, no record for you */
115*9ef1f84bSDavid du Colombier static struct Probelog *
newpl(void)116*9ef1f84bSDavid du Colombier newpl(void)
117*9ef1f84bSDavid du Colombier {
118*9ef1f84bSDavid du Colombier 	ulong index;
119*9ef1f84bSDavid du Colombier 
120*9ef1f84bSDavid du Colombier 	if (logfull()){
121*9ef1f84bSDavid du Colombier 		wakeup(&probesleep);
122*9ef1f84bSDavid du Colombier 		return nil;
123*9ef1f84bSDavid du Colombier 	}
124*9ef1f84bSDavid du Colombier 
125*9ef1f84bSDavid du Colombier 	ilock(&loglk);
126*9ef1f84bSDavid du Colombier 	index = pw++;
127*9ef1f84bSDavid du Colombier 	iunlock(&loglk);
128*9ef1f84bSDavid du Colombier 
129*9ef1f84bSDavid du Colombier 	return &probelog[idx(index)];
130*9ef1f84bSDavid du Colombier 
131*9ef1f84bSDavid du Colombier }
132*9ef1f84bSDavid du Colombier 
133*9ef1f84bSDavid du Colombier static void
probeentry(Probe * p)134*9ef1f84bSDavid du Colombier probeentry(Probe *p)
135*9ef1f84bSDavid du Colombier {
136*9ef1f84bSDavid du Colombier 	struct Probelog *pl;
137*9ef1f84bSDavid du Colombier //print("probeentry %p p %p func %p argp %p\n", &p, p, p->func, p->argp);
138*9ef1f84bSDavid du Colombier 	pl = newpl();
139*9ef1f84bSDavid du Colombier 	if (! pl)
140*9ef1f84bSDavid du Colombier 		return;
141*9ef1f84bSDavid du Colombier 	cycles(&pl->ticks);
142*9ef1f84bSDavid du Colombier 	pl->pc = (ulong)p->func;
143*9ef1f84bSDavid du Colombier 	pl->dat[0] = p->argp[0];
144*9ef1f84bSDavid du Colombier 	pl->dat[1] = p->argp[1];
145*9ef1f84bSDavid du Colombier 	pl->dat[2] = p->argp[2];
146*9ef1f84bSDavid du Colombier 	pl->dat[3] = p->argp[3];
147*9ef1f84bSDavid du Colombier 	pl->info = ProbeEntry;
148*9ef1f84bSDavid du Colombier }
149*9ef1f84bSDavid du Colombier 
150*9ef1f84bSDavid du Colombier static void
probeexit(Probe * p)151*9ef1f84bSDavid du Colombier probeexit(Probe *p)
152*9ef1f84bSDavid du Colombier {
153*9ef1f84bSDavid du Colombier //print("probeexit %p p %p func %p argp %p\n", &p, p, p->func, p->argp);
154*9ef1f84bSDavid du Colombier 	struct Probelog *pl;
155*9ef1f84bSDavid du Colombier 	pl = newpl();
156*9ef1f84bSDavid du Colombier 	if (! pl)
157*9ef1f84bSDavid du Colombier 		return;
158*9ef1f84bSDavid du Colombier 	cycles(&pl->ticks);
159*9ef1f84bSDavid du Colombier 	pl->pc = (ulong)p->func;
160*9ef1f84bSDavid du Colombier 	pl->dat[0] = p->rval;
161*9ef1f84bSDavid du Colombier 	pl->info = ProbeExit;
162*9ef1f84bSDavid du Colombier }
163*9ef1f84bSDavid du Colombier 
164*9ef1f84bSDavid du Colombier static Chan*
probeattach(char * spec)165*9ef1f84bSDavid du Colombier probeattach(char *spec)
166*9ef1f84bSDavid du Colombier {
167*9ef1f84bSDavid du Colombier 	return devattach('+', spec);
168*9ef1f84bSDavid du Colombier }
169*9ef1f84bSDavid du Colombier 
170*9ef1f84bSDavid du Colombier static Walkqid*
probewalk(Chan * c,Chan * nc,char ** name,int nname)171*9ef1f84bSDavid du Colombier probewalk(Chan *c, Chan *nc, char **name, int nname)
172*9ef1f84bSDavid du Colombier {
173*9ef1f84bSDavid du Colombier 	return devwalk(c, nc, name, nname, probedir, nelem(probedir), devgen);
174*9ef1f84bSDavid du Colombier }
175*9ef1f84bSDavid du Colombier 
176*9ef1f84bSDavid du Colombier static long
probestat(Chan * c,uchar * db,long n)177*9ef1f84bSDavid du Colombier probestat(Chan *c, uchar *db, long n)
178*9ef1f84bSDavid du Colombier {
179*9ef1f84bSDavid du Colombier 	return devstat(c, db, n, probedir, nelem(probedir), devgen);
180*9ef1f84bSDavid du Colombier }
181*9ef1f84bSDavid du Colombier 
182*9ef1f84bSDavid du Colombier static Chan*
probeopen(Chan * c,int omode)183*9ef1f84bSDavid du Colombier probeopen(Chan *c, int omode)
184*9ef1f84bSDavid du Colombier {
185*9ef1f84bSDavid du Colombier 	/* if there is no probelog, allocate one. Open always fails
186*9ef1f84bSDavid du Colombier 	  * if the basic alloc fails. You can resize it later.
187*9ef1f84bSDavid du Colombier 	  */
188*9ef1f84bSDavid du Colombier 	if (! probelog)
189*9ef1f84bSDavid du Colombier 		probelog = malloc(sizeof(*probelog)*logsize);
190*9ef1f84bSDavid du Colombier 	/* I guess malloc doesn't toss an error */
191*9ef1f84bSDavid du Colombier 	if (! probelog)
192*9ef1f84bSDavid du Colombier 		error("probelog malloc failed");
193*9ef1f84bSDavid du Colombier 
194*9ef1f84bSDavid du Colombier 	c = devopen(c, omode, probedir, nelem(probedir), devgen);
195*9ef1f84bSDavid du Colombier 	return c;
196*9ef1f84bSDavid du Colombier }
197*9ef1f84bSDavid du Colombier 
198*9ef1f84bSDavid du Colombier static void
probeclose(Chan *)199*9ef1f84bSDavid du Colombier probeclose(Chan *)
200*9ef1f84bSDavid du Colombier {
201*9ef1f84bSDavid du Colombier }
202*9ef1f84bSDavid du Colombier 
203*9ef1f84bSDavid du Colombier static long
proberead(Chan * c,void * a,long n,vlong offset)204*9ef1f84bSDavid du Colombier proberead(Chan *c, void *a, long n, vlong offset)
205*9ef1f84bSDavid du Colombier {
206*9ef1f84bSDavid du Colombier 	char *buf;
207*9ef1f84bSDavid du Colombier 	char *cp = a;
208*9ef1f84bSDavid du Colombier 	struct Probelog *pl;
209*9ef1f84bSDavid du Colombier 	Probe *p;
210*9ef1f84bSDavid du Colombier 	int i;
211*9ef1f84bSDavid du Colombier 	static QLock gate;
212*9ef1f84bSDavid du Colombier 	if(c->qid.type == QTDIR)
213*9ef1f84bSDavid du Colombier 		return devdirread(c, a, n, probedir, nelem(probedir), devgen);
214*9ef1f84bSDavid du Colombier 	switch((ulong)c->qid.path){
215*9ef1f84bSDavid du Colombier 	default:
216*9ef1f84bSDavid du Colombier 		error("proberead: bad qid");
217*9ef1f84bSDavid du Colombier 	case Qctl:
218*9ef1f84bSDavid du Colombier 		buf = malloc(READSTR);
219*9ef1f84bSDavid du Colombier 		i = 0;
220*9ef1f84bSDavid du Colombier 		qlock(&probeslk);
221*9ef1f84bSDavid du Colombier 		i += snprint(buf + i, READSTR - i, "logsize %lud\n", logsize);
222*9ef1f84bSDavid du Colombier 		for(p = probes; p != nil; p = p->next)
223*9ef1f84bSDavid du Colombier 			i += snprint(buf + i, READSTR - i, "probe %p new %s\n",
224*9ef1f84bSDavid du Colombier 				p->func, p->name);
225*9ef1f84bSDavid du Colombier 
226*9ef1f84bSDavid du Colombier 		for(p = probes; p != nil; p = p->next)
227*9ef1f84bSDavid du Colombier 			if (p->enabled)
228*9ef1f84bSDavid du Colombier 				i += snprint(buf + i, READSTR - i, "probe %s on\n",
229*9ef1f84bSDavid du Colombier 				p->name);
230*9ef1f84bSDavid du Colombier 		i += snprint(buf + i, READSTR - i, "#probehits %lud, in queue %lud\n",
231*9ef1f84bSDavid du Colombier 				pw, pw-pr);
232*9ef1f84bSDavid du Colombier 		snprint(buf + i, READSTR - i, "#probelog %p\n", probelog);
233*9ef1f84bSDavid du Colombier 		qunlock(&probeslk);
234*9ef1f84bSDavid du Colombier 		n = readstr(offset, a, n, buf);
235*9ef1f84bSDavid du Colombier 		free(buf);
236*9ef1f84bSDavid du Colombier 		break;
237*9ef1f84bSDavid du Colombier 	case Qdata:
238*9ef1f84bSDavid du Colombier 		qlock(&gate);
239*9ef1f84bSDavid du Colombier 		if(waserror()){
240*9ef1f84bSDavid du Colombier 			qunlock(&gate);
241*9ef1f84bSDavid du Colombier 			nexterror();
242*9ef1f84bSDavid du Colombier 		}
243*9ef1f84bSDavid du Colombier 		while(!lognonempty(nil))
244*9ef1f84bSDavid du Colombier 			tsleep(&probesleep, lognonempty, nil, 5000);
245*9ef1f84bSDavid du Colombier 		i = 0;
246*9ef1f84bSDavid du Colombier 		while(lognonempty((void *)0)){
247*9ef1f84bSDavid du Colombier 			int j;
248*9ef1f84bSDavid du Colombier 			pl = probelog + idx(pr);
249*9ef1f84bSDavid du Colombier 
250*9ef1f84bSDavid du Colombier 			if ((i + printsize) >= n)
251*9ef1f84bSDavid du Colombier 				break;
252*9ef1f84bSDavid du Colombier 			/* simple format */
253*9ef1f84bSDavid du Colombier 			cp[0] = eventname[pl->info];
254*9ef1f84bSDavid du Colombier 			cp ++;
255*9ef1f84bSDavid du Colombier 			*cp++ = ' ';
256*9ef1f84bSDavid du Colombier 			hex32(pl->pc, cp);
257*9ef1f84bSDavid du Colombier 			cp[8] = ' ';
258*9ef1f84bSDavid du Colombier 			cp += 9;
259*9ef1f84bSDavid du Colombier 			hex64(pl->ticks, cp);
260*9ef1f84bSDavid du Colombier 			cp[16] = ' ';
261*9ef1f84bSDavid du Colombier 			cp += 17;
262*9ef1f84bSDavid du Colombier 			for(j = 0; j < 4; j++){
263*9ef1f84bSDavid du Colombier 				hex32(pl->dat[j], cp);
264*9ef1f84bSDavid du Colombier 				cp[8] = ' ';
265*9ef1f84bSDavid du Colombier 				cp += 9;
266*9ef1f84bSDavid du Colombier 			}
267*9ef1f84bSDavid du Colombier 			/* adjust for extra skip above */
268*9ef1f84bSDavid du Colombier 			cp--;
269*9ef1f84bSDavid du Colombier 			*cp++ = '\n';
270*9ef1f84bSDavid du Colombier 			pr++;
271*9ef1f84bSDavid du Colombier 			i += printsize;
272*9ef1f84bSDavid du Colombier 		}
273*9ef1f84bSDavid du Colombier 		poperror();
274*9ef1f84bSDavid du Colombier 		qunlock(&gate);
275*9ef1f84bSDavid du Colombier 		n = i;
276*9ef1f84bSDavid du Colombier 		break;
277*9ef1f84bSDavid du Colombier 	}
278*9ef1f84bSDavid du Colombier 	return n;
279*9ef1f84bSDavid du Colombier }
280*9ef1f84bSDavid du Colombier 
281*9ef1f84bSDavid du Colombier static long
probewrite(Chan * c,void * a,long n,vlong)282*9ef1f84bSDavid du Colombier probewrite(Chan *c, void *a, long n, vlong)
283*9ef1f84bSDavid du Colombier {
284*9ef1f84bSDavid du Colombier 	char *tok[5];
285*9ef1f84bSDavid du Colombier 	char *ep, *s = nil;
286*9ef1f84bSDavid du Colombier 	Probe *p, **pp;
287*9ef1f84bSDavid du Colombier 	int ntok;
288*9ef1f84bSDavid du Colombier 
289*9ef1f84bSDavid du Colombier 	qlock(&probeslk);
290*9ef1f84bSDavid du Colombier 	if(waserror()){
291*9ef1f84bSDavid du Colombier 		qunlock(&probeslk);
292*9ef1f84bSDavid du Colombier 		if(s != nil) free(s);
293*9ef1f84bSDavid du Colombier 		nexterror();
294*9ef1f84bSDavid du Colombier 	}
295*9ef1f84bSDavid du Colombier 	switch((ulong)c->qid.path){
296*9ef1f84bSDavid du Colombier 	default:
297*9ef1f84bSDavid du Colombier 		error("proberead: bad qid");
298*9ef1f84bSDavid du Colombier 	case Qctl:
299*9ef1f84bSDavid du Colombier 		s = malloc(n + 1);
300*9ef1f84bSDavid du Colombier 		memmove(s, a, n);
301*9ef1f84bSDavid du Colombier 		s[n] = 0;
302*9ef1f84bSDavid du Colombier 		ntok = tokenize(s, tok, nelem(tok));
303*9ef1f84bSDavid du Colombier 		if(!strcmp(tok[0], "probe")){	/* 'probe' ktextaddr 'on'|'off'|'mk'|'del' [name] */
304*9ef1f84bSDavid du Colombier 			if(ntok < 3)
305*9ef1f84bSDavid du Colombier 				error("devprobe: usage: 'probe' [ktextaddr|name] 'on'|'off'|'mk'|'del' [name]");
306*9ef1f84bSDavid du Colombier 			for(pp = &probes; *pp != nil; pp = &(*pp)->next)
307*9ef1f84bSDavid du Colombier 				if(!strcmp(tok[1], (*pp)->name))
308*9ef1f84bSDavid du Colombier 					break;
309*9ef1f84bSDavid du Colombier 			p = *pp;
310*9ef1f84bSDavid du Colombier 			if(!strcmp(tok[2], "new")){
311*9ef1f84bSDavid du Colombier 				ulong addr;
312*9ef1f84bSDavid du Colombier 				void *func;
313*9ef1f84bSDavid du Colombier 				addr = strtoul(tok[1], &ep, 0);
314*9ef1f84bSDavid du Colombier 				func = (void*)addr;
315*9ef1f84bSDavid du Colombier 				if(*ep)
316*9ef1f84bSDavid du Colombier 					error("devprobe: address not in recognized format");
317*9ef1f84bSDavid du Colombier 			//	if(addr < ((ulong) start) || addr > ((ulong) end))
318*9ef1f84bSDavid du Colombier 			//		error("devprobe: address out of bounds");
319*9ef1f84bSDavid du Colombier 				if(p != nil)
320*9ef1f84bSDavid du Colombier 					error("devprobe: %#p already has probe");
321*9ef1f84bSDavid du Colombier 				p = mkprobe(func, probeentry, probeexit);
322*9ef1f84bSDavid du Colombier 				p->next = probes;
323*9ef1f84bSDavid du Colombier 				if(ntok < 4)
324*9ef1f84bSDavid du Colombier 					snprint(p->name, sizeof p->name, "%p", func);
325*9ef1f84bSDavid du Colombier 				else
326*9ef1f84bSDavid du Colombier 					strncpy(p->name, tok[3], sizeof p->name);
327*9ef1f84bSDavid du Colombier 				probes = p;
328*9ef1f84bSDavid du Colombier 			} else if(!strcmp(tok[2], "on")){
329*9ef1f84bSDavid du Colombier 				if(p == nil)
330*9ef1f84bSDavid du Colombier 					error("devprobe: probe not found");
331*9ef1f84bSDavid du Colombier 				if(!p->enabled)
332*9ef1f84bSDavid du Colombier 					probeinstall(p);
333*9ef1f84bSDavid du Colombier print("probeinstall in devprobe\n");
334*9ef1f84bSDavid du Colombier 				probesactive++;
335*9ef1f84bSDavid du Colombier 			} else if(!strcmp(tok[2], "off")){
336*9ef1f84bSDavid du Colombier 				if(p == nil)
337*9ef1f84bSDavid du Colombier 					error("devprobe: probe not found");
338*9ef1f84bSDavid du Colombier 				if(p->enabled)
339*9ef1f84bSDavid du Colombier 					probeuninstall(p);
340*9ef1f84bSDavid du Colombier 				probesactive--;
341*9ef1f84bSDavid du Colombier 			} else if(!strcmp(tok[2], "del")){
342*9ef1f84bSDavid du Colombier 				if(p == nil)
343*9ef1f84bSDavid du Colombier 					error("devprobe: probe not found");
344*9ef1f84bSDavid du Colombier 				if(p->enabled)
345*9ef1f84bSDavid du Colombier 					probeuninstall(p);
346*9ef1f84bSDavid du Colombier 				probesactive--;
347*9ef1f84bSDavid du Colombier 				*pp = p->next;
348*9ef1f84bSDavid du Colombier 				freeprobe(p);
349*9ef1f84bSDavid du Colombier 			} else if(!strcmp(tok[2], "mv")){
350*9ef1f84bSDavid du Colombier 				if(p == nil)
351*9ef1f84bSDavid du Colombier 					error("devprobe: probe not found");
352*9ef1f84bSDavid du Colombier 				if(ntok < 4)
353*9ef1f84bSDavid du Colombier 					error("devprobe: rename without new name?");
354*9ef1f84bSDavid du Colombier 				strncpy(p->name, tok[3], sizeof p->name);
355*9ef1f84bSDavid du Colombier 			}
356*9ef1f84bSDavid du Colombier 		} else if(!strcmp(tok[0], "size")){
357*9ef1f84bSDavid du Colombier 			int l, size;
358*9ef1f84bSDavid du Colombier 			struct Probelog *newprobelog;
359*9ef1f84bSDavid du Colombier 			l = strtoul(tok[1], &ep, 0);
360*9ef1f84bSDavid du Colombier 			if(*ep)
361*9ef1f84bSDavid du Colombier 				error("devprobe: size not in recognized format");
362*9ef1f84bSDavid du Colombier 			size = 1 << l;
363*9ef1f84bSDavid du Colombier 			/* sort of foolish. Alloc new probe first, then free old. */
364*9ef1f84bSDavid du Colombier 			/* and too bad if there are unread probes */
365*9ef1f84bSDavid du Colombier 			newprobelog = malloc(sizeof(*newprobelog)*size);
366*9ef1f84bSDavid du Colombier 			/* does malloc throw waserror? I don't know */
367*9ef1f84bSDavid du Colombier 			free(probelog);
368*9ef1f84bSDavid du Colombier 			probelog = newprobelog;
369*9ef1f84bSDavid du Colombier 			logsize = size;
370*9ef1f84bSDavid du Colombier 			pr = pw = 0;
371*9ef1f84bSDavid du Colombier 		} else {
372*9ef1f84bSDavid du Colombier 			error("devprobe:  usage: 'probe' [ktextaddr|name] 'on'|'off'|'mk'|'del' [name] or:  'size' buffersize (power of 2)");
373*9ef1f84bSDavid du Colombier 		}
374*9ef1f84bSDavid du Colombier 		free(s);
375*9ef1f84bSDavid du Colombier 		break;
376*9ef1f84bSDavid du Colombier 	}
377*9ef1f84bSDavid du Colombier 	poperror();
378*9ef1f84bSDavid du Colombier 	qunlock(&probeslk);
379*9ef1f84bSDavid du Colombier 	return n;
380*9ef1f84bSDavid du Colombier }
381*9ef1f84bSDavid du Colombier 
382*9ef1f84bSDavid du Colombier Dev probedevtab = {
383*9ef1f84bSDavid du Colombier 	'+',
384*9ef1f84bSDavid du Colombier 	"probe",
385*9ef1f84bSDavid du Colombier 	devreset,
386*9ef1f84bSDavid du Colombier 	devinit,
387*9ef1f84bSDavid du Colombier 	devshutdown,
388*9ef1f84bSDavid du Colombier 	probeattach,
389*9ef1f84bSDavid du Colombier 	probewalk,
390*9ef1f84bSDavid du Colombier 	probestat,
391*9ef1f84bSDavid du Colombier 	probeopen,
392*9ef1f84bSDavid du Colombier 	devcreate,
393*9ef1f84bSDavid du Colombier 	probeclose,
394*9ef1f84bSDavid du Colombier 	proberead,
395*9ef1f84bSDavid du Colombier 	devbread,
396*9ef1f84bSDavid du Colombier 	probewrite,
397*9ef1f84bSDavid du Colombier 	devbwrite,
398*9ef1f84bSDavid du Colombier 	devremove,
399*9ef1f84bSDavid du Colombier 	devwstat,
400*9ef1f84bSDavid du Colombier };
401