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