xref: /plan9/sys/src/9/port/devproc.c (revision 4e3613ab15c331a9ada113286cc0f2a35bc0373d)
1 #include	"u.h"
2 #include	<trace.h>
3 #include	"tos.h"
4 #include	"../port/lib.h"
5 #include	"mem.h"
6 #include	"dat.h"
7 #include	"fns.h"
8 #include	"../port/error.h"
9 #include	"ureg.h"
10 #include	"../port/edf.h"
11 
12 enum
13 {
14 	Qdir,
15 	Qtrace,
16 	Qargs,
17 	Qctl,
18 	Qfd,
19 	Qfpregs,
20 	Qkregs,
21 	Qmem,
22 	Qnote,
23 	Qnoteid,
24 	Qnotepg,
25 	Qns,
26 	Qproc,
27 	Qregs,
28 	Qsegment,
29 	Qstatus,
30 	Qtext,
31 	Qwait,
32 	Qprofile,
33 	Qsyscall,
34 };
35 
36 enum
37 {
38 	CMclose,
39 	CMclosefiles,
40 	CMfixedpri,
41 	CMhang,
42 	CMkill,
43 	CMnohang,
44 	CMnoswap,
45 	CMpri,
46 	CMprivate,
47 	CMprofile,
48 	CMstart,
49 	CMstartstop,
50 	CMstartsyscall,
51 	CMstop,
52 	CMwaitstop,
53 	CMwired,
54 	CMtrace,
55 	/* real time */
56 	CMperiod,
57 	CMdeadline,
58 	CMcost,
59 	CMsporadic,
60 	CMdeadlinenotes,
61 	CMadmit,
62 	CMextra,
63 	CMexpel,
64 	CMevent,
65 };
66 
67 enum{
68 	Nevents = 0x4000,
69 	Emask = Nevents - 1,
70 };
71 
72 #define	STATSIZE	(2*KNAMELEN+12+9*12)
73 /*
74  * Status, fd, and ns are left fully readable (0444) because of their use in debugging,
75  * particularly on shared servers.
76  * Arguably, ns and fd shouldn't be readable; if you'd prefer, change them to 0000
77  */
78 Dirtab procdir[] =
79 {
80 	"args",		{Qargs},	0,			0660,
81 	"ctl",		{Qctl},		0,			0000,
82 	"fd",		{Qfd},		0,			0444,
83 	"fpregs",	{Qfpregs},	sizeof(FPsave),		0000,
84 	"kregs",	{Qkregs},	sizeof(Ureg),		0400,
85 	"mem",		{Qmem},		0,			0000,
86 	"note",		{Qnote},	0,			0000,
87 	"noteid",	{Qnoteid},	0,			0664,
88 	"notepg",	{Qnotepg},	0,			0000,
89 	"ns",		{Qns},		0,			0444,
90 	"proc",		{Qproc},	0,			0400,
91 	"regs",		{Qregs},	sizeof(Ureg),		0000,
92 	"segment",	{Qsegment},	0,			0444,
93 	"status",	{Qstatus},	STATSIZE,		0444,
94 	"text",		{Qtext},	0,			0000,
95 	"wait",		{Qwait},	0,			0400,
96 	"profile",	{Qprofile},	0,			0400,
97 	"syscall",	{Qsyscall},	0,			0400,
98 };
99 
100 static
101 Cmdtab proccmd[] = {
102 	CMclose,		"close",		2,
103 	CMclosefiles,		"closefiles",		1,
104 	CMfixedpri,		"fixedpri",		2,
105 	CMhang,			"hang",			1,
106 	CMnohang,		"nohang",		1,
107 	CMnoswap,		"noswap",		1,
108 	CMkill,			"kill",			1,
109 	CMpri,			"pri",			2,
110 	CMprivate,		"private",		1,
111 	CMprofile,		"profile",		1,
112 	CMstart,		"start",		1,
113 	CMstartstop,		"startstop",		1,
114 	CMstartsyscall,		"startsyscall",		1,
115 	CMstop,			"stop",			1,
116 	CMwaitstop,		"waitstop",		1,
117 	CMwired,		"wired",		2,
118 	CMtrace,		"trace",		0,
119 	CMperiod,		"period",		2,
120 	CMdeadline,		"deadline",		2,
121 	CMcost,			"cost",			2,
122 	CMsporadic,		"sporadic",		1,
123 	CMdeadlinenotes,	"deadlinenotes",	1,
124 	CMadmit,		"admit",		1,
125 	CMextra,		"extra",		1,
126 	CMexpel,		"expel",		1,
127 	CMevent,		"event",		1,
128 };
129 
130 /* Segment type from portdat.h */
131 static char *sname[]={ "Text", "Data", "Bss", "Stack", "Shared", "Phys", };
132 
133 /*
134  * Qids are, in path:
135  *	 5 bits of file type (qids above)
136  *	26 bits of process slot number + 1
137  *	     in vers,
138  *	32 bits of pid, for consistency checking
139  * If notepg, c->pgrpid.path is pgrp slot, .vers is noteid.
140  */
141 #define	QSHIFT	5	/* location in qid of proc slot # */
142 
143 #define	QID(q)		((((ulong)(q).path) & ((1<<QSHIFT)-1)) >> 0)
144 #define	SLOT(q)		(((((ulong)(q).path) & ~(1UL<<31)) >> QSHIFT) - 1)
145 #define	PID(q)		((q).vers)
146 #define	NOTEID(q)	((q).vers)
147 
148 void	procctlreq(Proc*, char*, int);
149 int	procctlmemio(Proc*, ulong, int, void*, int);
150 Chan*	proctext(Chan*, Proc*);
151 Segment* txt2data(Proc*, Segment*);
152 int	procstopped(void*);
153 void	mntscan(Mntwalk*, Proc*);
154 
155 static Traceevent *tevents;
156 static Lock tlock;
157 static int topens;
158 static int tproduced, tconsumed;
159 void (*proctrace)(Proc*, int, vlong);
160 
161 extern int unfair;
162 
163 static void
profclock(Ureg * ur,Timer *)164 profclock(Ureg *ur, Timer *)
165 {
166 	Tos *tos;
167 
168 	if(up == 0 || up->state != Running)
169 		return;
170 
171 	/* user profiling clock */
172 	if(userureg(ur)){
173 		tos = (Tos*)(USTKTOP-sizeof(Tos));
174 		tos->clock += TK2MS(1);
175 		segclock(ur->pc);
176 	}
177 }
178 
179 static int
procgen(Chan * c,char * name,Dirtab * tab,int,int s,Dir * dp)180 procgen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp)
181 {
182 	Qid qid;
183 	Proc *p;
184 	char *ename;
185 	Segment *q;
186 	ulong pid, path, perm, len;
187 
188 	if(s == DEVDOTDOT){
189 		mkqid(&qid, Qdir, 0, QTDIR);
190 		devdir(c, qid, "#p", 0, eve, 0555, dp);
191 		return 1;
192 	}
193 
194 	if(c->qid.path == Qdir){
195 		if(s == 0){
196 			strcpy(up->genbuf, "trace");
197 			mkqid(&qid, Qtrace, -1, QTFILE);
198 			devdir(c, qid, up->genbuf, 0, eve, 0444, dp);
199 			return 1;
200 		}
201 
202 		if(name != nil){
203 			/* ignore s and use name to find pid */
204 			pid = strtol(name, &ename, 10);
205 			if(pid==0 || ename[0]!='\0')
206 				return -1;
207 			s = procindex(pid);
208 			if(s < 0)
209 				return -1;
210 		}
211 		else if(--s >= conf.nproc)
212 			return -1;
213 
214 		p = proctab(s);
215 		pid = p->pid;
216 		if(pid == 0)
217 			return 0;
218 		snprint(up->genbuf, sizeof up->genbuf, "%lud", pid);
219 		/*
220 		 * String comparison is done in devwalk so name must match its formatted pid
221 		*/
222 		if(name != nil && strcmp(name, up->genbuf) != 0)
223 			return -1;
224 		mkqid(&qid, (s+1)<<QSHIFT, pid, QTDIR);
225 		devdir(c, qid, up->genbuf, 0, p->user, DMDIR|0555, dp);
226 		return 1;
227 	}
228 	if(c->qid.path == Qtrace){
229 		strcpy(up->genbuf, "trace");
230 		mkqid(&qid, Qtrace, -1, QTFILE);
231 		devdir(c, qid, up->genbuf, 0, eve, 0444, dp);
232 		return 1;
233 	}
234 	if(s >= nelem(procdir))
235 		return -1;
236 	if(tab)
237 		panic("procgen");
238 
239 	tab = &procdir[s];
240 	path = c->qid.path&~(((1<<QSHIFT)-1));	/* slot component */
241 
242 	/* p->procmode determines default mode for files in /proc */
243 	p = proctab(SLOT(c->qid));
244 	perm = tab->perm;
245 	if(perm == 0)
246 		perm = p->procmode;
247 	else	/* just copy read bits */
248 		perm |= p->procmode & 0444;
249 
250 	len = tab->length;
251 	switch(QID(c->qid)) {
252 	case Qwait:
253 		len = p->nwait;	/* incorrect size, but >0 means there's something to read */
254 		break;
255 	case Qprofile:
256 		q = p->seg[TSEG];
257 		if(q && q->profile) {
258 			len = (q->top-q->base)>>LRESPROF;
259 			len *= sizeof(*q->profile);
260 		}
261 		break;
262 	}
263 
264 	mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE);
265 	devdir(c, qid, tab->name, len, p->user, perm, dp);
266 	return 1;
267 }
268 
269 static void
_proctrace(Proc * p,Tevent etype,vlong ts)270 _proctrace(Proc* p, Tevent etype, vlong ts)
271 {
272 	Traceevent *te;
273 
274 	if (p->trace == 0 || topens == 0 ||
275 		tproduced - tconsumed >= Nevents)
276 		return;
277 
278 	te = &tevents[tproduced&Emask];
279 	te->pid = p->pid;
280 	te->etype = etype;
281 	if (ts == 0)
282 		te->time = todget(nil);
283 	else
284 		te->time = ts;
285 	tproduced++;
286 }
287 
288 static void
procinit(void)289 procinit(void)
290 {
291 	if(conf.nproc >= (1<<(31-QSHIFT))-1)
292 		print("warning: too many procs for devproc\n");
293 	addclock0link((void (*)(void))profclock, 113);	/* Relative prime to HZ */
294 }
295 
296 static Chan*
procattach(char * spec)297 procattach(char *spec)
298 {
299 	return devattach('p', spec);
300 }
301 
302 static Walkqid*
procwalk(Chan * c,Chan * nc,char ** name,int nname)303 procwalk(Chan *c, Chan *nc, char **name, int nname)
304 {
305 	return devwalk(c, nc, name, nname, 0, 0, procgen);
306 }
307 
308 static int
procstat(Chan * c,uchar * db,int n)309 procstat(Chan *c, uchar *db, int n)
310 {
311 	return devstat(c, db, n, 0, 0, procgen);
312 }
313 
314 /*
315  *  none can't read or write state on other
316  *  processes.  This is to contain access of
317  *  servers running as none should they be
318  *  subverted by, for example, a stack attack.
319  */
320 static void
nonone(Proc * p)321 nonone(Proc *p)
322 {
323 	if(p == up)
324 		return;
325 	if(strcmp(up->user, "none") != 0)
326 		return;
327 	if(iseve())
328 		return;
329 	error(Eperm);
330 }
331 
332 static Chan*
procopen(Chan * c,int omode)333 procopen(Chan *c, int omode)
334 {
335 	Proc *p;
336 	Pgrp *pg;
337 	Chan *tc;
338 	int pid;
339 
340 	if(c->qid.type & QTDIR)
341 		return devopen(c, omode, 0, 0, procgen);
342 
343 	if(QID(c->qid) == Qtrace){
344 		if (omode != OREAD)
345 			error(Eperm);
346 		lock(&tlock);
347 		if (waserror()){
348 			unlock(&tlock);
349 			nexterror();
350 		}
351 		if (topens > 0)
352 			error("already open");
353 		topens++;
354 		if (tevents == nil){
355 			tevents = (Traceevent*)malloc(sizeof(Traceevent) * Nevents);
356 			if(tevents == nil)
357 				error(Enomem);
358 			tproduced = tconsumed = 0;
359 		}
360 		proctrace = _proctrace;
361 		unlock(&tlock);
362 		poperror();
363 
364 		c->mode = openmode(omode);
365 		c->flag |= COPEN;
366 		c->offset = 0;
367 		return c;
368 	}
369 
370 	p = proctab(SLOT(c->qid));
371 	qlock(&p->debug);
372 	if(waserror()){
373 		qunlock(&p->debug);
374 		nexterror();
375 	}
376 	pid = PID(c->qid);
377 	if(p->pid != pid)
378 		error(Eprocdied);
379 
380 	omode = openmode(omode);
381 
382 	switch(QID(c->qid)){
383 	case Qtext:
384 		if(omode != OREAD)
385 			error(Eperm);
386 		tc = proctext(c, p);
387 		tc->offset = 0;
388 		qunlock(&p->debug);
389 		poperror();
390 		cclose(c);
391 		return tc;
392 
393 	case Qproc:
394 	case Qkregs:
395 	case Qsegment:
396 	case Qprofile:
397 	case Qfd:
398 		if(omode != OREAD)
399 			error(Eperm);
400 		break;
401 
402 	case Qnote:
403 		if(p->privatemem)
404 			error(Eperm);
405 		break;
406 
407 	case Qmem:
408 	case Qctl:
409 		if(p->privatemem)
410 			error(Eperm);
411 		nonone(p);
412 		break;
413 
414 	case Qargs:
415 	case Qnoteid:
416 	case Qstatus:
417 	case Qwait:
418 	case Qregs:
419 	case Qfpregs:
420 	case Qsyscall:
421 		nonone(p);
422 		break;
423 
424 	case Qns:
425 		if(omode != OREAD)
426 			error(Eperm);
427 		c->aux = malloc(sizeof(Mntwalk));
428 		break;
429 
430 	case Qnotepg:
431 		nonone(p);
432 		pg = p->pgrp;
433 		if(pg == nil)
434 			error(Eprocdied);
435 		if(omode!=OWRITE || pg->pgrpid == 1)
436 			error(Eperm);
437 		c->pgrpid.path = pg->pgrpid+1;
438 		c->pgrpid.vers = p->noteid;
439 		break;
440 
441 	default:
442 		pprint("procopen %#lux\n", QID(c->qid));
443 		error(Egreg);
444 	}
445 
446 	/* Affix pid to qid */
447 	if(p->state != Dead)
448 		c->qid.vers = p->pid;
449 
450 	/* make sure the process slot didn't get reallocated while we were playing */
451 	coherence();
452 	if(p->pid != pid)
453 		error(Eprocdied);
454 
455 	tc = devopen(c, omode, 0, 0, procgen);
456 	qunlock(&p->debug);
457 	poperror();
458 
459 	return tc;
460 }
461 
462 static int
procwstat(Chan * c,uchar * db,int n)463 procwstat(Chan *c, uchar *db, int n)
464 {
465 	Proc *p;
466 	Dir *d;
467 
468 	if(c->qid.type&QTDIR)
469 		error(Eperm);
470 
471 	if(QID(c->qid) == Qtrace)
472 		return devwstat(c, db, n);
473 
474 	p = proctab(SLOT(c->qid));
475 	nonone(p);
476 	d = nil;
477 	if(waserror()){
478 		free(d);
479 		qunlock(&p->debug);
480 		nexterror();
481 	}
482 	qlock(&p->debug);
483 
484 	if(p->pid != PID(c->qid))
485 		error(Eprocdied);
486 
487 	if(strcmp(up->user, p->user) != 0 && strcmp(up->user, eve) != 0)
488 		error(Eperm);
489 
490 	d = smalloc(sizeof(Dir)+n);
491 	n = convM2D(db, n, &d[0], (char*)&d[1]);
492 	if(n == 0)
493 		error(Eshortstat);
494 	if(!emptystr(d->uid) && strcmp(d->uid, p->user) != 0){
495 		if(strcmp(up->user, eve) != 0)
496 			error(Eperm);
497 		else
498 			kstrdup(&p->user, d->uid);
499 	}
500 	/* p->procmode determines default mode for files in /proc */
501 	if(d->mode != ~0UL)
502 		p->procmode = d->mode&0777;
503 
504 	poperror();
505 	free(d);
506 	qunlock(&p->debug);
507 	return n;
508 }
509 
510 
511 static long
procoffset(long offset,char * va,int * np)512 procoffset(long offset, char *va, int *np)
513 {
514 	if(offset > 0) {
515 		offset -= *np;
516 		if(offset < 0) {
517 			memmove(va, va+*np+offset, -offset);
518 			*np = -offset;
519 		}
520 		else
521 			*np = 0;
522 	}
523 	return offset;
524 }
525 
526 static int
procqidwidth(Chan * c)527 procqidwidth(Chan *c)
528 {
529 	char buf[32];
530 
531 	return snprint(buf, sizeof buf, "%lud", c->qid.vers);
532 }
533 
534 int
procfdprint(Chan * c,int fd,int w,char * s,int ns)535 procfdprint(Chan *c, int fd, int w, char *s, int ns)
536 {
537 	int n;
538 
539 	if(w == 0)
540 		w = procqidwidth(c);
541 	n = snprint(s, ns, "%3d %.2s %C %4ld (%.16llux %*lud %.2ux) %5ld %8lld %s\n",
542 		fd,
543 		&"r w rw"[(c->mode&3)<<1],
544 		devtab[c->type]->dc, c->dev,
545 		c->qid.path, w, c->qid.vers, c->qid.type,
546 		c->iounit, c->offset, c->path->s);
547 	return n;
548 }
549 
550 static int
procfds(Proc * p,char * va,int count,long offset)551 procfds(Proc *p, char *va, int count, long offset)
552 {
553 	Fgrp *f;
554 	Chan *c;
555 	char buf[256];
556 	int n, i, w, ww;
557 	char *a;
558 
559 	/* print to buf to avoid holding fgrp lock while writing to user space */
560 	if(count > sizeof buf)
561 		count = sizeof buf;
562 	a = buf;
563 
564 	qlock(&p->debug);
565 	f = p->fgrp;
566 	if(f == nil){
567 		qunlock(&p->debug);
568 		return 0;
569 	}
570 	lock(f);
571 	if(waserror()){
572 		unlock(f);
573 		qunlock(&p->debug);
574 		nexterror();
575 	}
576 
577 	n = readstr(0, a, count, p->dot->path->s);
578 	n += snprint(a+n, count-n, "\n");
579 	offset = procoffset(offset, a, &n);
580 	/* compute width of qid.path */
581 	w = 0;
582 	for(i = 0; i <= f->maxfd; i++) {
583 		c = f->fd[i];
584 		if(c == nil)
585 			continue;
586 		ww = procqidwidth(c);
587 		if(ww > w)
588 			w = ww;
589 	}
590 	for(i = 0; i <= f->maxfd; i++) {
591 		c = f->fd[i];
592 		if(c == nil)
593 			continue;
594 		n += procfdprint(c, i, w, a+n, count-n);
595 		offset = procoffset(offset, a, &n);
596 	}
597 	unlock(f);
598 	qunlock(&p->debug);
599 	poperror();
600 
601 	/* copy result to user space, now that locks are released */
602 	memmove(va, buf, n);
603 
604 	return n;
605 }
606 
607 static void
procclose(Chan * c)608 procclose(Chan * c)
609 {
610 	if(QID(c->qid) == Qtrace){
611 		lock(&tlock);
612 		if(topens > 0)
613 			topens--;
614 		if(topens == 0)
615 			proctrace = nil;
616 		unlock(&tlock);
617 	}
618 	if(QID(c->qid) == Qns && c->aux != 0)
619 		free(c->aux);
620 }
621 
622 static void
int2flag(int flag,char * s)623 int2flag(int flag, char *s)
624 {
625 	if(flag == 0){
626 		*s = '\0';
627 		return;
628 	}
629 	*s++ = '-';
630 	if(flag & MAFTER)
631 		*s++ = 'a';
632 	if(flag & MBEFORE)
633 		*s++ = 'b';
634 	if(flag & MCREATE)
635 		*s++ = 'c';
636 	if(flag & MCACHE)
637 		*s++ = 'C';
638 	*s = '\0';
639 }
640 
641 static int
procargs(Proc * p,char * buf,int nbuf)642 procargs(Proc *p, char *buf, int nbuf)
643 {
644 	int j, k, m;
645 	char *a;
646 	int n;
647 
648 	a = p->args;
649 	if(p->setargs){
650 		snprint(buf, nbuf, "%s [%s]", p->text, p->args);
651 		return strlen(buf);
652 	}
653 	n = p->nargs;
654 	for(j = 0; j < nbuf - 1; j += m){
655 		if(n <= 0)
656 			break;
657 		if(j != 0)
658 			buf[j++] = ' ';
659 		m = snprint(buf+j, nbuf-j, "%q",  a);
660 		k = strlen(a) + 1;
661 		a += k;
662 		n -= k;
663 	}
664 	return j;
665 }
666 
667 static int
eventsavailable(void *)668 eventsavailable(void *)
669 {
670 	return tproduced > tconsumed;
671 }
672 
673 static long
procread(Chan * c,void * va,long n,vlong off)674 procread(Chan *c, void *va, long n, vlong off)
675 {
676 	/* NSEG*32 was too small for worst cases */
677 	char *a, flag[10], *sps, *srv, statbuf[NSEG*64];
678 	int i, j, m, navail, ne, pid, rsize;
679 	long l;
680 	uchar *rptr;
681 	ulong offset;
682 	Confmem *cm;
683 	Mntwalk *mw;
684 	Proc *p;
685 	Segment *sg, *s;
686 	Ureg kur;
687 	Waitq *wq;
688 
689 	a = va;
690 	offset = off;
691 
692 	if(c->qid.type & QTDIR)
693 		return devdirread(c, a, n, 0, 0, procgen);
694 
695 	if(QID(c->qid) == Qtrace){
696 		if(!eventsavailable(nil))
697 			return 0;
698 
699 		rptr = (uchar*)va;
700 		navail = tproduced - tconsumed;
701 		if(navail > n / sizeof(Traceevent))
702 			navail = n / sizeof(Traceevent);
703 		while(navail > 0) {
704 			ne = ((tconsumed & Emask) + navail > Nevents)?
705 					Nevents - (tconsumed & Emask): navail;
706 			memmove(rptr, &tevents[tconsumed & Emask],
707 					ne * sizeof(Traceevent));
708 
709 			tconsumed += ne;
710 			rptr += ne * sizeof(Traceevent);
711 			navail -= ne;
712 		}
713 		return rptr - (uchar*)va;
714 	}
715 
716 	p = proctab(SLOT(c->qid));
717 	if(p->pid != PID(c->qid))
718 		error(Eprocdied);
719 
720 	switch(QID(c->qid)){
721 	case Qargs:
722 		qlock(&p->debug);
723 		j = procargs(p, up->genbuf, sizeof up->genbuf);
724 		qunlock(&p->debug);
725 		if(offset >= j)
726 			return 0;
727 		if(offset+n > j)
728 			n = j-offset;
729 		memmove(a, &up->genbuf[offset], n);
730 		return n;
731 	case Qsyscall:
732 		if(!p->syscalltrace)
733 			return 0;
734 		n = readstr(offset, a, n, p->syscalltrace);
735 		return n;
736 
737 	case Qmem:
738 		if(offset < KZERO)
739 			return procctlmemio(p, offset, n, va, 1);
740 
741 		if(!iseve())
742 			error(Eperm);
743 
744 		/* validate kernel addresses */
745 		if(offset < (ulong)end) {
746 			if(offset+n > (ulong)end)
747 				n = (ulong)end - offset;
748 			memmove(a, (char*)offset, n);
749 			return n;
750 		}
751 		for(i=0; i<nelem(conf.mem); i++){
752 			cm = &conf.mem[i];
753 			/* klimit-1 because klimit might be zero! */
754 			if(cm->kbase <= offset && offset <= cm->klimit-1){
755 				if(offset+n >= cm->klimit-1)
756 					n = cm->klimit - offset;
757 				memmove(a, (char*)offset, n);
758 				return n;
759 			}
760 		}
761 		error(Ebadarg);
762 
763 	case Qprofile:
764 		s = p->seg[TSEG];
765 		if(s == 0 || s->profile == 0)
766 			error("profile is off");
767 		i = (s->top-s->base)>>LRESPROF;
768 		i *= sizeof(*s->profile);
769 		if(offset >= i)
770 			return 0;
771 		if(offset+n > i)
772 			n = i - offset;
773 		memmove(a, ((char*)s->profile)+offset, n);
774 		return n;
775 
776 	case Qnote:
777 		qlock(&p->debug);
778 		if(waserror()){
779 			qunlock(&p->debug);
780 			nexterror();
781 		}
782 		if(p->pid != PID(c->qid))
783 			error(Eprocdied);
784 		if(n < 1)	/* must accept at least the '\0' */
785 			error(Etoosmall);
786 		if(p->nnote == 0)
787 			n = 0;
788 		else {
789 			m = strlen(p->note[0].msg) + 1;
790 			if(m > n)
791 				m = n;
792 			memmove(va, p->note[0].msg, m);
793 			((char*)va)[m-1] = '\0';
794 			p->nnote--;
795 			memmove(p->note, p->note+1, p->nnote*sizeof(Note));
796 			n = m;
797 		}
798 		if(p->nnote == 0)
799 			p->notepending = 0;
800 		poperror();
801 		qunlock(&p->debug);
802 		return n;
803 
804 	case Qproc:
805 		if(offset >= sizeof(Proc))
806 			return 0;
807 		if(offset+n > sizeof(Proc))
808 			n = sizeof(Proc) - offset;
809 		memmove(a, ((char*)p)+offset, n);
810 		return n;
811 
812 	case Qregs:
813 		rptr = (uchar*)p->dbgreg;
814 		rsize = sizeof(Ureg);
815 		goto regread;
816 
817 	case Qkregs:
818 		memset(&kur, 0, sizeof(Ureg));
819 		setkernur(&kur, p);
820 		rptr = (uchar*)&kur;
821 		rsize = sizeof(Ureg);
822 		goto regread;
823 
824 	case Qfpregs:
825 		rptr = (uchar*)&p->fpsave;
826 		rsize = sizeof(FPsave);
827 	regread:
828 		if(rptr == 0)
829 			error(Enoreg);
830 		if(offset >= rsize)
831 			return 0;
832 		if(offset+n > rsize)
833 			n = rsize - offset;
834 		memmove(a, rptr+offset, n);
835 		return n;
836 
837 	case Qstatus:
838 		if(offset >= STATSIZE)
839 			return 0;
840 		if(offset+n > STATSIZE)
841 			n = STATSIZE - offset;
842 
843 		sps = p->psstate;
844 		if(sps == 0)
845 			sps = statename[p->state];
846 		memset(statbuf, ' ', sizeof statbuf);
847 		readstr(0, statbuf+0*KNAMELEN, KNAMELEN-1, p->text);
848 		readstr(0, statbuf+1*KNAMELEN, KNAMELEN-1, p->user);
849 		readstr(0, statbuf+2*KNAMELEN, 11, sps);
850 		j = 2*KNAMELEN + 12;
851 
852 		for(i = 0; i < 6; i++) {
853 			l = p->time[i];
854 			if(i == TReal)
855 				l = MACHP(0)->ticks - l;
856 			l = TK2MS(l);
857 			readnum(0, statbuf+j+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
858 		}
859 		/* ignore stack, which is mostly non-existent */
860 		l = 0;
861 		for(i=1; i<NSEG; i++){
862 			s = p->seg[i];
863 			if(s)
864 				l += s->top - s->base;
865 		}
866 		readnum(0, statbuf+j+NUMSIZE*6, NUMSIZE, l>>10, NUMSIZE);
867 		readnum(0, statbuf+j+NUMSIZE*7, NUMSIZE, p->basepri, NUMSIZE);
868 		readnum(0, statbuf+j+NUMSIZE*8, NUMSIZE, p->priority, NUMSIZE);
869 		memmove(a, statbuf+offset, n);
870 		return n;
871 
872 	case Qsegment:
873 		j = 0;
874 		for(i = 0; i < NSEG; i++) {
875 			sg = p->seg[i];
876 			if(sg == 0)
877 				continue;
878 			j += snprint(statbuf+j, sizeof statbuf - j,
879 				"%-6s %c%c %.8lux %.8lux %4ld\n",
880 				sname[sg->type&SG_TYPE],
881 				sg->type&SG_RONLY ? 'R' : ' ',
882 				sg->profile ? 'P' : ' ',
883 				sg->base, sg->top, sg->ref);
884 		}
885 		if(offset >= j)
886 			return 0;
887 		if(offset+n > j)
888 			n = j-offset;
889 		if(n == 0 && offset == 0)
890 			exhausted("segments");
891 		memmove(a, &statbuf[offset], n);
892 		return n;
893 
894 	case Qwait:
895 		if(!canqlock(&p->qwaitr))
896 			error(Einuse);
897 
898 		if(waserror()) {
899 			qunlock(&p->qwaitr);
900 			nexterror();
901 		}
902 
903 		lock(&p->exl);
904 		if(up == p && p->nchild == 0 && p->waitq == 0) {
905 			unlock(&p->exl);
906 			error(Enochild);
907 		}
908 		pid = p->pid;
909 		while(p->waitq == 0) {
910 			unlock(&p->exl);
911 			sleep(&p->waitr, haswaitq, p);
912 			if(p->pid != pid)
913 				error(Eprocdied);
914 			lock(&p->exl);
915 		}
916 		wq = p->waitq;
917 		p->waitq = wq->next;
918 		p->nwait--;
919 		unlock(&p->exl);
920 
921 		qunlock(&p->qwaitr);
922 		poperror();
923 		n = snprint(a, n, "%d %lud %lud %lud %q",
924 			wq->w.pid,
925 			wq->w.time[TUser], wq->w.time[TSys], wq->w.time[TReal],
926 			wq->w.msg);
927 		free(wq);
928 		return n;
929 
930 	case Qns:
931 		qlock(&p->debug);
932 		if(waserror()){
933 			qunlock(&p->debug);
934 			nexterror();
935 		}
936 		if(p->pgrp == nil || p->pid != PID(c->qid))
937 			error(Eprocdied);
938 		mw = c->aux;
939 		if(mw == nil)
940 			error(Enomem);
941 		if(mw->cddone){
942 			qunlock(&p->debug);
943 			poperror();
944 			return 0;
945 		}
946 		mntscan(mw, p);
947 		if(mw->mh == 0){
948 			mw->cddone = 1;
949 			i = snprint(a, n, "cd %s\n", p->dot->path->s);
950 			qunlock(&p->debug);
951 			poperror();
952 			return i;
953 		}
954 		int2flag(mw->cm->mflag, flag);
955 		if(strcmp(mw->cm->to->path->s, "#M") == 0){
956 			srv = srvname(mw->cm->to->mchan);
957 			i = snprint(a, n, "mount %s %s %s %s\n", flag,
958 				srv==nil? mw->cm->to->mchan->path->s : srv,
959 				mw->mh->from->path->s, mw->cm->spec? mw->cm->spec : "");
960 			free(srv);
961 		}else
962 			i = snprint(a, n, "bind %s %s %s\n", flag,
963 				mw->cm->to->path->s, mw->mh->from->path->s);
964 		qunlock(&p->debug);
965 		poperror();
966 		return i;
967 
968 	case Qnoteid:
969 		return readnum(offset, va, n, p->noteid, NUMSIZE);
970 	case Qfd:
971 		return procfds(p, va, n, offset);
972 	}
973 	error(Egreg);
974 	return 0;		/* not reached */
975 }
976 
977 void
mntscan(Mntwalk * mw,Proc * p)978 mntscan(Mntwalk *mw, Proc *p)
979 {
980 	Pgrp *pg;
981 	Mount *t;
982 	Mhead *f;
983 	int nxt, i;
984 	ulong last, bestmid;
985 
986 	pg = p->pgrp;
987 	rlock(&pg->ns);
988 
989 	nxt = 0;
990 	bestmid = ~0;
991 
992 	last = 0;
993 	if(mw->mh)
994 		last = mw->cm->mountid;
995 
996 	for(i = 0; i < MNTHASH; i++) {
997 		for(f = pg->mnthash[i]; f; f = f->hash) {
998 			for(t = f->mount; t; t = t->next) {
999 				if(mw->mh == 0 ||
1000 				  (t->mountid > last && t->mountid < bestmid)) {
1001 					mw->cm = t;
1002 					mw->mh = f;
1003 					bestmid = mw->cm->mountid;
1004 					nxt = 1;
1005 				}
1006 			}
1007 		}
1008 	}
1009 	if(nxt == 0)
1010 		mw->mh = 0;
1011 
1012 	runlock(&pg->ns);
1013 }
1014 
1015 static long
procwrite(Chan * c,void * va,long n,vlong off)1016 procwrite(Chan *c, void *va, long n, vlong off)
1017 {
1018 	int id, m;
1019 	Proc *p, *t, *et;
1020 	char *a, *arg, buf[ERRMAX];
1021 	ulong offset = off;
1022 
1023 	a = va;
1024 	if(c->qid.type & QTDIR)
1025 		error(Eisdir);
1026 
1027 	p = proctab(SLOT(c->qid));
1028 
1029 	/* Use the remembered noteid in the channel rather
1030 	 * than the process pgrpid
1031 	 */
1032 	if(QID(c->qid) == Qnotepg) {
1033 		pgrpnote(NOTEID(c->pgrpid), va, n, NUser);
1034 		return n;
1035 	}
1036 
1037 	qlock(&p->debug);
1038 	if(waserror()){
1039 		qunlock(&p->debug);
1040 		nexterror();
1041 	}
1042 	if(p->pid != PID(c->qid))
1043 		error(Eprocdied);
1044 
1045 	switch(QID(c->qid)){
1046 	case Qargs:
1047 		if(n == 0)
1048 			error(Eshort);
1049 		if(n >= ERRMAX)
1050 			error(Etoobig);
1051 		arg = malloc(n+1);
1052 		if(arg == nil)
1053 			error(Enomem);
1054 		memmove(arg, va, n);
1055 		m = n;
1056 		if(arg[m-1] != 0)
1057 			arg[m++] = 0;
1058 		free(p->args);
1059 		p->nargs = m;
1060 		p->args = arg;
1061 		p->setargs = 1;
1062 		break;
1063 
1064 	case Qmem:
1065 		if(p->state != Stopped)
1066 			error(Ebadctl);
1067 
1068 		n = procctlmemio(p, offset, n, va, 0);
1069 		break;
1070 
1071 	case Qregs:
1072 		if(offset >= sizeof(Ureg))
1073 			n = 0;
1074 		else if(offset+n > sizeof(Ureg))
1075 			n = sizeof(Ureg) - offset;
1076 		if(p->dbgreg == 0)
1077 			error(Enoreg);
1078 		setregisters(p->dbgreg, (char*)(p->dbgreg)+offset, va, n);
1079 		break;
1080 
1081 	case Qfpregs:
1082 		if(offset >= sizeof(FPsave))
1083 			n = 0;
1084 		else if(offset+n > sizeof(FPsave))
1085 			n = sizeof(FPsave) - offset;
1086 		memmove((uchar*)&p->fpsave+offset, va, n);
1087 		break;
1088 
1089 	case Qctl:
1090 		procctlreq(p, va, n);
1091 		break;
1092 
1093 	case Qnote:
1094 		if(p->kp)
1095 			error(Eperm);
1096 		if(n >= ERRMAX-1)
1097 			error(Etoobig);
1098 		memmove(buf, va, n);
1099 		buf[n] = 0;
1100 		if(!postnote(p, 0, buf, NUser))
1101 			error("note not posted");
1102 		break;
1103 	case Qnoteid:
1104 		id = atoi(a);
1105 		if(id == p->pid) {
1106 			p->noteid = id;
1107 			break;
1108 		}
1109 		t = proctab(0);
1110 		for(et = t+conf.nproc; t < et; t++) {
1111 			if(t->state == Dead)
1112 				continue;
1113 			if(id == t->noteid) {
1114 				if(strcmp(p->user, t->user) != 0)
1115 					error(Eperm);
1116 				p->noteid = id;
1117 				break;
1118 			}
1119 		}
1120 		if(p->noteid != id)
1121 			error(Ebadarg);
1122 		break;
1123 	default:
1124 		pprint("unknown qid in procwrite\n");
1125 		error(Egreg);
1126 	}
1127 	poperror();
1128 	qunlock(&p->debug);
1129 	return n;
1130 }
1131 
1132 Dev procdevtab = {
1133 	'p',
1134 	"proc",
1135 
1136 	devreset,
1137 	procinit,
1138 	devshutdown,
1139 	procattach,
1140 	procwalk,
1141 	procstat,
1142 	procopen,
1143 	devcreate,
1144 	procclose,
1145 	procread,
1146 	devbread,
1147 	procwrite,
1148 	devbwrite,
1149 	devremove,
1150 	procwstat,
1151 };
1152 
1153 Chan*
proctext(Chan * c,Proc * p)1154 proctext(Chan *c, Proc *p)
1155 {
1156 	Chan *tc;
1157 	Image *i;
1158 	Segment *s;
1159 
1160 	s = p->seg[TSEG];
1161 	if(s == 0)
1162 		error(Enonexist);
1163 	if(p->state==Dead)
1164 		error(Eprocdied);
1165 
1166 	lock(s);
1167 	i = s->image;
1168 	if(i == 0) {
1169 		unlock(s);
1170 		error(Eprocdied);
1171 	}
1172 	unlock(s);
1173 
1174 	lock(i);
1175 	if(waserror()) {
1176 		unlock(i);
1177 		nexterror();
1178 	}
1179 
1180 	tc = i->c;
1181 	if(tc == 0)
1182 		error(Eprocdied);
1183 
1184 	if(incref(tc) == 1 || (tc->flag&COPEN) == 0 || tc->mode!=OREAD) {
1185 		cclose(tc);
1186 		error(Eprocdied);
1187 	}
1188 
1189 	if(p->pid != PID(c->qid)){
1190 		cclose(tc);
1191 		error(Eprocdied);
1192 	}
1193 
1194 	unlock(i);
1195 	poperror();
1196 
1197 	return tc;
1198 }
1199 
1200 void
procstopwait(Proc * p,int ctl)1201 procstopwait(Proc *p, int ctl)
1202 {
1203 	int pid;
1204 
1205 	if(p->pdbg)
1206 		error(Einuse);
1207 	if(procstopped(p) || p->state == Broken)
1208 		return;
1209 
1210 	if(ctl != 0)
1211 		p->procctl = ctl;
1212 	p->pdbg = up;
1213 	pid = p->pid;
1214 	qunlock(&p->debug);
1215 	up->psstate = "Stopwait";
1216 	if(waserror()) {
1217 		p->pdbg = 0;
1218 		qlock(&p->debug);
1219 		nexterror();
1220 	}
1221 	sleep(&up->sleep, procstopped, p);
1222 	poperror();
1223 	qlock(&p->debug);
1224 	if(p->pid != pid)
1225 		error(Eprocdied);
1226 }
1227 
1228 static void
procctlcloseone(Proc * p,Fgrp * f,int fd)1229 procctlcloseone(Proc *p, Fgrp *f, int fd)
1230 {
1231 	Chan *c;
1232 
1233 	c = f->fd[fd];
1234 	if(c == nil)
1235 		return;
1236 	f->fd[fd] = nil;
1237 	unlock(f);
1238 	qunlock(&p->debug);
1239 	cclose(c);
1240 	qlock(&p->debug);
1241 	lock(f);
1242 }
1243 
1244 void
procctlclosefiles(Proc * p,int all,int fd)1245 procctlclosefiles(Proc *p, int all, int fd)
1246 {
1247 	int i;
1248 	Fgrp *f;
1249 
1250 	f = p->fgrp;
1251 	if(f == nil)
1252 		error(Eprocdied);
1253 
1254 	lock(f);
1255 	f->ref++;
1256 	if(all)
1257 		for(i = 0; i < f->maxfd; i++)
1258 			procctlcloseone(p, f, i);
1259 	else
1260 		procctlcloseone(p, f, fd);
1261 	unlock(f);
1262 	closefgrp(f);
1263 }
1264 
1265 static char *
parsetime(vlong * rt,char * s)1266 parsetime(vlong *rt, char *s)
1267 {
1268 	uvlong ticks;
1269 	ulong l;
1270 	char *e, *p;
1271 	static int p10[] = {100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1};
1272 
1273 	if (s == nil)
1274 		return("missing value");
1275 	ticks=strtoul(s, &e, 10);
1276 	if (*e == '.'){
1277 		p = e+1;
1278 		l = strtoul(p, &e, 10);
1279 		if(e-p > nelem(p10))
1280 			return "too many digits after decimal point";
1281 		if(e-p == 0)
1282 			return "ill-formed number";
1283 		l *= p10[e-p-1];
1284 	}else
1285 		l = 0;
1286 	if (*e == '\0' || strcmp(e, "s") == 0){
1287 		ticks = 1000000000 * ticks + l;
1288 	}else if (strcmp(e, "ms") == 0){
1289 		ticks = 1000000 * ticks + l/1000;
1290 	}else if (strcmp(e, "µs") == 0 || strcmp(e, "us") == 0){
1291 		ticks = 1000 * ticks + l/1000000;
1292 	}else if (strcmp(e, "ns") != 0)
1293 		return "unrecognized unit";
1294 	*rt = ticks;
1295 	return nil;
1296 }
1297 
1298 void
procctlreq(Proc * p,char * va,int n)1299 procctlreq(Proc *p, char *va, int n)
1300 {
1301 	Segment *s;
1302 	int npc, pri;
1303 	Cmdbuf *cb;
1304 	Cmdtab *ct;
1305 	vlong time;
1306 	char *e;
1307 	void (*pt)(Proc*, int, vlong);
1308 
1309 	if(p->kp)	/* no ctl requests to kprocs */
1310 		error(Eperm);
1311 
1312 	cb = parsecmd(va, n);
1313 	if(waserror()){
1314 		free(cb);
1315 		nexterror();
1316 	}
1317 
1318 	ct = lookupcmd(cb, proccmd, nelem(proccmd));
1319 
1320 	switch(ct->index){
1321 	case CMclose:
1322 		procctlclosefiles(p, 0, atoi(cb->f[1]));
1323 		break;
1324 	case CMclosefiles:
1325 		procctlclosefiles(p, 1, 0);
1326 		break;
1327 	case CMhang:
1328 		p->hang = 1;
1329 		break;
1330 	case CMkill:
1331 		switch(p->state) {
1332 		case Broken:
1333 			unbreak(p);
1334 			break;
1335 		case Stopped:
1336 			p->procctl = Proc_exitme;
1337 			postnote(p, 0, "sys: killed", NExit);
1338 			ready(p);
1339 			break;
1340 		default:
1341 			p->procctl = Proc_exitme;
1342 			postnote(p, 0, "sys: killed", NExit);
1343 		}
1344 		break;
1345 	case CMnohang:
1346 		p->hang = 0;
1347 		break;
1348 	case CMnoswap:
1349 		p->noswap = 1;
1350 		break;
1351 	case CMpri:
1352 		pri = atoi(cb->f[1]);
1353 		if(pri > PriNormal && !iseve())
1354 			error(Eperm);
1355 		procpriority(p, pri, 0);
1356 		break;
1357 	case CMfixedpri:
1358 		pri = atoi(cb->f[1]);
1359 		if(pri > PriNormal && !iseve())
1360 			error(Eperm);
1361 		procpriority(p, pri, 1);
1362 		break;
1363 	case CMprivate:
1364 		p->privatemem = 1;
1365 		break;
1366 	case CMprofile:
1367 		s = p->seg[TSEG];
1368 		if(s == 0 || (s->type&SG_TYPE) != SG_TEXT)
1369 			error(Ebadctl);
1370 		if(s->profile != 0)
1371 			free(s->profile);
1372 		npc = (s->top-s->base)>>LRESPROF;
1373 		s->profile = malloc(npc*sizeof(*s->profile));
1374 		if(s->profile == 0)
1375 			error(Enomem);
1376 		break;
1377 	case CMstart:
1378 		if(p->state != Stopped)
1379 			error(Ebadctl);
1380 		ready(p);
1381 		break;
1382 	case CMstartstop:
1383 		if(p->state != Stopped)
1384 			error(Ebadctl);
1385 		p->procctl = Proc_traceme;
1386 		ready(p);
1387 		procstopwait(p, Proc_traceme);
1388 		break;
1389 	case CMstartsyscall:
1390 		if(p->state != Stopped)
1391 			error(Ebadctl);
1392 		p->procctl = Proc_tracesyscall;
1393 		ready(p);
1394 		procstopwait(p, Proc_tracesyscall);
1395 		break;
1396 	case CMstop:
1397 		procstopwait(p, Proc_stopme);
1398 		break;
1399 	case CMwaitstop:
1400 		procstopwait(p, 0);
1401 		break;
1402 	case CMwired:
1403 		procwired(p, atoi(cb->f[1]));
1404 		break;
1405 	case CMtrace:
1406 		switch(cb->nf){
1407 		case 1:
1408 			p->trace ^= 1;
1409 			break;
1410 		case 2:
1411 			p->trace = (atoi(cb->f[1]) != 0);
1412 			break;
1413 		default:
1414 			error("args");
1415 		}
1416 		break;
1417 	/* real time */
1418 	case CMperiod:
1419 		if(p->edf == nil)
1420 			edfinit(p);
1421 		if(e=parsetime(&time, cb->f[1]))	/* time in ns */
1422 			error(e);
1423 		edfstop(p);
1424 		p->edf->T = time/1000;	/* Edf times are in µs */
1425 		break;
1426 	case CMdeadline:
1427 		if(p->edf == nil)
1428 			edfinit(p);
1429 		if(e=parsetime(&time, cb->f[1]))
1430 			error(e);
1431 		edfstop(p);
1432 		p->edf->D = time/1000;
1433 		break;
1434 	case CMcost:
1435 		if(p->edf == nil)
1436 			edfinit(p);
1437 		if(e=parsetime(&time, cb->f[1]))
1438 			error(e);
1439 		edfstop(p);
1440 		p->edf->C = time/1000;
1441 		break;
1442 	case CMsporadic:
1443 		if(p->edf == nil)
1444 			edfinit(p);
1445 		p->edf->flags |= Sporadic;
1446 		break;
1447 	case CMdeadlinenotes:
1448 		if(p->edf == nil)
1449 			edfinit(p);
1450 		p->edf->flags |= Sendnotes;
1451 		break;
1452 	case CMadmit:
1453 		if(p->edf == 0)
1454 			error("edf params");
1455 		if(e = edfadmit(p))
1456 			error(e);
1457 		break;
1458 	case CMextra:
1459 		if(p->edf == nil)
1460 			edfinit(p);
1461 		p->edf->flags |= Extratime;
1462 		break;
1463 	case CMexpel:
1464 		if(p->edf)
1465 			edfstop(p);
1466 		break;
1467 	case CMevent:
1468 		pt = proctrace;
1469 		if(up->trace && pt)
1470 			pt(up, SUser, 0);
1471 		break;
1472 	}
1473 
1474 	poperror();
1475 	free(cb);
1476 }
1477 
1478 int
procstopped(void * a)1479 procstopped(void *a)
1480 {
1481 	Proc *p = a;
1482 	return p->state == Stopped;
1483 }
1484 
1485 int
procctlmemio(Proc * p,ulong offset,int n,void * va,int read)1486 procctlmemio(Proc *p, ulong offset, int n, void *va, int read)
1487 {
1488 	KMap *k;
1489 	Pte *pte;
1490 	Page *pg;
1491 	Segment *s;
1492 	ulong soff, l;
1493 	char *a = va, *b;
1494 
1495 	for(;;) {
1496 		s = seg(p, offset, 1);
1497 		if(s == 0)
1498 			error(Ebadarg);
1499 
1500 		if(offset+n >= s->top)
1501 			n = s->top-offset;
1502 
1503 		if(!read && (s->type&SG_TYPE) == SG_TEXT)
1504 			s = txt2data(p, s);
1505 
1506 		s->steal++;
1507 		soff = offset-s->base;
1508 		if(waserror()) {
1509 			s->steal--;
1510 			nexterror();
1511 		}
1512 		if(fixfault(s, offset, read, 0) == 0)
1513 			break;
1514 		poperror();
1515 		s->steal--;
1516 	}
1517 	poperror();
1518 	pte = s->map[soff/PTEMAPMEM];
1519 	if(pte == 0)
1520 		panic("procctlmemio");
1521 	pg = pte->pages[(soff&(PTEMAPMEM-1))/BY2PG];
1522 	if(pagedout(pg))
1523 		panic("procctlmemio1");
1524 
1525 	l = BY2PG - (offset&(BY2PG-1));
1526 	if(n > l)
1527 		n = l;
1528 
1529 	k = kmap(pg);
1530 	if(waserror()) {
1531 		s->steal--;
1532 		kunmap(k);
1533 		nexterror();
1534 	}
1535 	b = (char*)VA(k);
1536 	b += offset&(BY2PG-1);
1537 	if(read == 1)
1538 		memmove(a, b, n);	/* This can fault */
1539 	else
1540 		memmove(b, a, n);
1541 	kunmap(k);
1542 	poperror();
1543 
1544 	/* Ensure the process sees text page changes */
1545 	if(s->flushme)
1546 		memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
1547 
1548 	s->steal--;
1549 
1550 	if(read == 0)
1551 		p->newtlb = 1;
1552 
1553 	return n;
1554 }
1555 
1556 Segment*
txt2data(Proc * p,Segment * s)1557 txt2data(Proc *p, Segment *s)
1558 {
1559 	int i;
1560 	Segment *ps;
1561 
1562 	ps = newseg(SG_DATA, s->base, s->size);
1563 	ps->image = s->image;
1564 	incref(ps->image);
1565 	ps->fstart = s->fstart;
1566 	ps->flen = s->flen;
1567 	ps->flushme = 1;
1568 
1569 	qlock(&p->seglock);
1570 	for(i = 0; i < NSEG; i++)
1571 		if(p->seg[i] == s)
1572 			break;
1573 	if(i == NSEG)
1574 		panic("segment gone");
1575 
1576 	qunlock(&s->lk);
1577 	putseg(s);
1578 	qlock(&ps->lk);
1579 	p->seg[i] = ps;
1580 	qunlock(&p->seglock);
1581 
1582 	return ps;
1583 }
1584 
1585 Segment*
data2txt(Segment * s)1586 data2txt(Segment *s)
1587 {
1588 	Segment *ps;
1589 
1590 	ps = newseg(SG_TEXT, s->base, s->size);
1591 	ps->image = s->image;
1592 	incref(ps->image);
1593 	ps->fstart = s->fstart;
1594 	ps->flen = s->flen;
1595 	ps->flushme = 1;
1596 
1597 	return ps;
1598 }
1599