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