4 #include "../port/lib.h"
8 #include "../port/error.h"
75 #define STATSIZE (2*KNAMELEN+12+9*12)
77 * Status, fd, and ns are left fully readable (0444) because of their use in debugging,
78 * particularly on shared servers.
79 * Arguably, ns and fd shouldn't be readable; if you'd prefer, change them to 0000
83 "args", {Qargs}, 0, 0660,
84 "ctl", {Qctl}, 0, 0000,
86 "fpregs", {Qfpregs}, sizeof(FPsave), 0000,
87 "kregs", {Qkregs}, sizeof(Ureg), 0400,
88 "mem", {Qmem}, 0, 0000,
89 "note", {Qnote}, 0, 0000,
90 "noteid", {Qnoteid}, 0, 0664,
91 "notepg", {Qnotepg}, 0, 0000,
93 "ppid", {Qppid}, 0, 0444,
94 "proc", {Qproc}, 0, 0400,
95 "regs", {Qregs}, sizeof(Ureg), 0000,
96 "segment", {Qsegment}, 0, 0444,
97 "status", {Qstatus}, STATSIZE, 0444,
98 "text", {Qtext}, 0, 0000,
99 "wait", {Qwait}, 0, 0400,
100 "profile", {Qprofile}, 0, 0400,
101 "syscall", {Qsyscall}, 0, 0400,
107 CMclosefiles, "closefiles", 1,
108 CMfixedpri, "fixedpri", 2,
110 CMnohang, "nohang", 1,
111 CMnoswap, "noswap", 1,
114 CMprivate, "private", 1,
115 CMprofile, "profile", 1,
117 CMstartstop, "startstop", 1,
118 CMstartsyscall, "startsyscall", 1,
120 CMwaitstop, "waitstop", 1,
123 CMinterrupt, "interrupt", 1,
124 CMnointerrupt, "nointerrupt", 1,
125 CMperiod, "period", 2,
126 CMdeadline, "deadline", 2,
128 CMsporadic, "sporadic", 1,
129 CMdeadlinenotes, "deadlinenotes", 1,
136 /* Segment type from portdat.h */
137 static char *sname[]={ "Text", "Data", "Bss", "Stack", "Shared", "Phys", };
141 * 4 bits of file type (qids above)
142 * 23 bits of process slot number + 1
144 * 32 bits of pid, for consistency checking
145 * If notepg, c->pgrpid.path is pgrp slot, .vers is noteid.
147 #define QSHIFT 5 /* location in qid of proc slot # */
149 #define QID(q) ((((ulong)(q).path)&0x0000001F)>>0)
150 #define SLOT(q) (((((ulong)(q).path)&0x07FFFFFE0)>>QSHIFT)-1)
151 #define PID(q) ((q).vers)
152 #define NOTEID(q) ((q).vers)
154 void procctlreq(Proc*, char*, int);
155 int procctlmemio(Proc*, uintptr, int, void*, int);
156 Chan* proctext(Chan*, Proc*);
157 int procstopped(void*);
158 void mntscan(Mntwalk*, Proc*);
159 ulong procpagecount(Proc *);
161 static Traceevent *tevents;
164 static int tproduced, tconsumed;
165 void (*proctrace)(Proc*, int, vlong);
170 profclock(Ureg *ur, Timer *)
174 if(up == nil || up->state != Running)
177 /* user profiling clock */
179 tos = (Tos*)(USTKTOP-sizeof(Tos));
180 tos->clock += TK2MS(1);
186 procgen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp)
192 ulong pid, path, perm, len;
195 mkqid(&qid, Qdir, 0, QTDIR);
196 devdir(c, qid, "#p", 0, eve, 0555, dp);
200 if(c->qid.path == Qdir){
202 strcpy(up->genbuf, "trace");
203 mkqid(&qid, Qtrace, -1, QTFILE);
204 devdir(c, qid, up->genbuf, 0, eve, 0444, dp);
209 /* ignore s and use name to find pid */
210 pid = strtol(name, &ename, 10);
211 if(pid==0 || ename[0]!='\0')
217 else if(--s >= conf.nproc)
224 sprint(up->genbuf, "%lud", pid);
226 * String comparison is done in devwalk so name must match its formatted pid
228 if(name != nil && strcmp(name, up->genbuf) != 0)
230 mkqid(&qid, (s+1)<<QSHIFT, pid, QTDIR);
231 devdir(c, qid, up->genbuf, 0, p->user, DMDIR|0555, dp);
234 if(c->qid.path == Qtrace){
235 strcpy(up->genbuf, "trace");
236 mkqid(&qid, Qtrace, -1, QTFILE);
237 devdir(c, qid, up->genbuf, 0, eve, 0444, dp);
240 if(s >= nelem(procdir))
246 path = c->qid.path&~(((1<<QSHIFT)-1)); /* slot component */
248 /* p->procmode determines default mode for files in /proc */
249 p = proctab(SLOT(c->qid));
253 else /* just copy read bits */
254 perm |= p->procmode & 0444;
257 switch(QID(c->qid)) {
259 len = p->nwait; /* incorrect size, but >0 means there's something to read */
263 if(q != nil && q->profile != nil) {
264 len = (q->top-q->base)>>LRESPROF;
265 len *= sizeof(*q->profile);
270 mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE);
271 devdir(c, qid, tab->name, len, p->user, perm, dp);
276 _proctrace(Proc* p, Tevent etype, vlong ts)
280 if (p->trace == 0 || topens == 0 ||
281 tproduced - tconsumed >= Nevents)
284 te = &tevents[tproduced&Emask];
288 te->time = todget(nil);
297 if(conf.nproc >= (1<<(16-QSHIFT))-1)
298 print("warning: too many procs for devproc\n");
299 addclock0link((void (*)(void))profclock, 113); /* Relative prime to HZ */
303 procattach(char *spec)
305 return devattach('p', spec);
309 procwalk(Chan *c, Chan *nc, char **name, int nname)
311 return devwalk(c, nc, name, nname, 0, 0, procgen);
315 procstat(Chan *c, uchar *db, int n)
317 return devstat(c, db, n, 0, 0, procgen);
321 * none can't read or write state on other
322 * processes. This is to contain access of
323 * servers running as none should they be
324 * subverted by, for example, a stack attack.
331 if(strcmp(up->user, "none") != 0)
339 procopen(Chan *c, int omode)
346 if(c->qid.type & QTDIR)
347 return devopen(c, omode, 0, 0, procgen);
349 if(QID(c->qid) == Qtrace){
359 error("already open");
361 tevents = (Traceevent*)malloc(sizeof(Traceevent) * Nevents);
364 tproduced = tconsumed = 0;
366 proctrace = _proctrace;
370 c->mode = openmode(omode);
376 p = proctab(SLOT(c->qid));
386 omode = openmode(omode);
434 c->aux = smalloc(sizeof(Mntwalk));
444 c->pgrpid.path = pg->pgrpid+1;
445 c->pgrpid.vers = p->noteid;
449 print("procopen %#lux\n", QID(c->qid));
453 /* Affix pid to qid */
455 c->qid.vers = p->pid;
457 /* make sure the process slot didn't get reallocated while we were playing */
462 tc = devopen(c, omode, 0, 0, procgen);
470 procwstat(Chan *c, uchar *db, int n)
475 if(c->qid.type&QTDIR)
478 if(QID(c->qid) == Qtrace)
479 return devwstat(c, db, n);
481 p = proctab(SLOT(c->qid));
492 if(p->pid != PID(c->qid))
495 if(strcmp(up->user, p->user) != 0 && !iseve())
498 d = smalloc(sizeof(Dir)+n);
499 n = convM2D(db, n, &d[0], (char*)&d[1]);
502 if(!emptystr(d->uid) && strcmp(d->uid, p->user) != 0){
505 kstrdup(&p->user, d->uid);
507 /* p->procmode determines default mode for files in /proc */
509 p->procmode = d->mode&0777;
519 procoffset(long offset, char *va, int *np)
524 memmove(va, va+*np+offset, -offset);
534 procqidwidth(Chan *c)
538 return sprint(buf, "%lud", c->qid.vers);
542 procfdprint(Chan *c, int fd, int w, char *s, int ns)
548 n = snprint(s, ns, "%3d %.2s %C %4ld (%.16llux %*lud %.2ux) %5ld %8lld %s\n",
550 &"r w rw"[(c->mode&3)<<1],
551 devtab[c->type]->dc, c->dev,
552 c->qid.path, w, c->qid.vers, c->qid.type,
553 c->iounit, c->offset, c->path->s);
558 procfds(Proc *p, char *va, int count, long offset)
566 /* print to buf to avoid holding fgrp lock while writing to user space */
567 if(count > sizeof buf)
573 if(f == nil || p->dot == nil){
584 n = readstr(0, a, count, p->dot->path->s);
585 n += snprint(a+n, count-n, "\n");
586 offset = procoffset(offset, a, &n);
587 /* compute width of qid.path */
589 for(i = 0; i <= f->maxfd; i++) {
593 ww = procqidwidth(c);
597 for(i = 0; i <= f->maxfd; i++) {
601 n += procfdprint(c, i, w, a+n, count-n);
602 offset = procoffset(offset, a, &n);
608 /* copy result to user space, now that locks are released */
617 if(QID(c->qid) == Qtrace && (c->flag & COPEN) != 0){
625 if(QID(c->qid) == Qns && c->aux != nil){
632 int2flag(int flag, char *s)
651 procargs(Proc *p, char *buf, int nbuf)
659 snprint(buf, nbuf, "%s [%s]", p->text, p->args);
663 for(j = 0; j < nbuf - 1; j += m){
668 m = snprint(buf+j, nbuf-j, "%q", a);
677 eventsavailable(void *)
679 return tproduced > tconsumed;
683 prochaswaitq(void *x)
689 p = proctab(SLOT(c->qid));
690 return p->pid != PID(c->qid) || p->waitq != nil;
694 * userspace can't pass negative file offset for a
695 * 64 bit kernel address, so we use 63 bit and sign
707 procread(Chan *c, void *va, long n, vlong off)
709 /* NSEG*32 was too small for worst cases */
710 char *a, flag[10], *sps, *srv, statbuf[NSEG*64];
711 int i, j, m, navail, ne, rsize;
725 if(c->qid.type & QTDIR)
726 return devdirread(c, a, n, 0, 0, procgen);
728 if(QID(c->qid) == Qtrace){
729 if(!eventsavailable(nil))
733 navail = tproduced - tconsumed;
734 if(navail > n / sizeof(Traceevent))
735 navail = n / sizeof(Traceevent);
737 ne = ((tconsumed & Emask) + navail > Nevents)?
738 Nevents - (tconsumed & Emask): navail;
739 memmove(rptr, &tevents[tconsumed & Emask],
740 ne * sizeof(Traceevent));
743 rptr += ne * sizeof(Traceevent);
746 return rptr - (uchar*)va;
749 p = proctab(SLOT(c->qid));
750 if(p->pid != PID(c->qid))
756 j = procargs(p, up->genbuf, sizeof up->genbuf);
762 memmove(a, &up->genbuf[offset], n);
770 if(p->pid != PID(c->qid))
772 if(p->syscalltrace != nil)
773 n = readstr(offset, a, n, p->syscalltrace);
781 addr = off2addr(off);
783 return procctlmemio(p, addr, n, va, 1);
788 /* validate kernel addresses */
789 if(addr < (uintptr)end) {
790 if(addr+n > (uintptr)end)
791 n = (uintptr)end - addr;
792 memmove(a, (char*)addr, n);
795 for(i=0; i<nelem(conf.mem); i++){
797 /* klimit-1 because klimit might be zero! */
798 if(cm->kbase <= addr && addr <= cm->klimit-1){
799 if(addr+n >= cm->klimit-1)
800 n = cm->klimit - addr;
801 memmove(a, (char*)addr, n);
809 if(s == nil || s->profile == nil)
810 error("profile is off");
811 i = (s->top-s->base)>>LRESPROF;
812 i *= sizeof(s->profile[0]);
813 if(i < 0 || offset >= i)
817 memmove(a, ((char*)s->profile)+offset, n);
826 if(p->pid != PID(c->qid))
828 if(n < 1) /* must accept at least the '\0' */
833 m = strlen(p->note[0].msg) + 1;
836 memmove(va, p->note[0].msg, m-1);
837 ((char*)va)[m-1] = '\0';
839 memmove(p->note, p->note+1, p->nnote*sizeof(Note));
849 if(offset >= sizeof(Proc))
851 if(offset+n > sizeof(Proc))
852 n = sizeof(Proc) - offset;
853 memmove(a, ((char*)p)+offset, n);
857 rptr = (uchar*)p->dbgreg;
858 rsize = sizeof(Ureg);
862 memset(&kur, 0, sizeof(Ureg));
865 rsize = sizeof(Ureg);
869 rptr = (uchar*)&p->fpsave;
870 rsize = sizeof(FPsave);
878 memmove(a, rptr+offset, n);
882 if(offset >= STATSIZE)
884 if(offset+n > STATSIZE)
885 n = STATSIZE - offset;
889 sps = statename[p->state];
891 memset(statbuf, ' ', sizeof statbuf);
892 readstr(0, statbuf+0*KNAMELEN, KNAMELEN-1, p->text);
893 readstr(0, statbuf+1*KNAMELEN, KNAMELEN-1, p->user);
894 readstr(0, statbuf+2*KNAMELEN, 11, sps);
897 for(i = 0; i < 6; i++) {
900 l = MACHP(0)->ticks - l;
902 readnum(0, statbuf+j+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
905 readnum(0, statbuf+j+NUMSIZE*6, NUMSIZE, procpagecount(p)*BY2PG/1024, NUMSIZE);
906 readnum(0, statbuf+j+NUMSIZE*7, NUMSIZE, p->basepri, NUMSIZE);
907 readnum(0, statbuf+j+NUMSIZE*8, NUMSIZE, p->priority, NUMSIZE);
908 memmove(a, statbuf+offset, n);
913 for(i = 0; i < NSEG; i++) {
917 j += sprint(statbuf+j, "%-6s %c%c %8p %8p %4ld\n",
918 sname[sg->type&SG_TYPE],
919 sg->type&SG_RONLY ? 'R' : ' ',
920 sg->profile ? 'P' : ' ',
921 sg->base, sg->top, sg->ref);
927 if(n == 0 && offset == 0)
928 exhausted("segments");
929 memmove(a, &statbuf[offset], n);
933 if(!canqlock(&p->qwaitr))
942 while(p->waitq == nil && p->pid == PID(c->qid)) {
943 if(up == p && p->nchild == 0) {
948 sleep(&p->waitr, prochaswaitq, c);
951 if(p->pid != PID(c->qid)){
962 n = snprint(a, n, "%d %lud %lud %lud %q",
964 wq->w.time[TUser], wq->w.time[TSys], wq->w.time[TReal],
975 if(p->pgrp == nil || p->dot == nil || p->pid != PID(c->qid))
986 i = snprint(a, n, "cd %s\n", p->dot->path->s);
991 int2flag(mw->cm->mflag, flag);
992 if(strcmp(mw->cm->to->path->s, "#M") == 0){
993 srv = srvname(mw->cm->to->mchan);
994 i = snprint(a, n, "mount %s %s %s %s\n", flag,
995 srv==nil? mw->cm->to->mchan->path->s : srv,
996 mw->mh->from->path->s, mw->cm->spec? mw->cm->spec : "");
999 i = snprint(a, n, "bind %s %s %s\n", flag,
1000 mw->cm->to->path->s, mw->mh->from->path->s);
1006 return readnum(offset, va, n, p->noteid, NUMSIZE);
1008 return readnum(offset, va, n, p->parentpid, NUMSIZE);
1010 return procfds(p, va, n, offset);
1013 return 0; /* not reached */
1017 mntscan(Mntwalk *mw, Proc *p)
1023 ulong last, bestmid;
1033 last = mw->cm->mountid;
1035 for(i = 0; i < MNTHASH; i++) {
1036 for(f = pg->mnthash[i]; f != nil; f = f->hash) {
1037 for(t = f->mount; t != nil; t = t->next) {
1039 (t->mountid > last && t->mountid < bestmid)) {
1042 bestmid = mw->cm->mountid;
1055 procwrite(Chan *c, void *va, long n, vlong off)
1059 char *a, *arg, buf[ERRMAX];
1064 if(c->qid.type & QTDIR)
1067 p = proctab(SLOT(c->qid));
1069 /* Use the remembered noteid in the channel rather
1070 * than the process pgrpid
1072 if(QID(c->qid) == Qnotepg) {
1073 pgrpnote(NOTEID(c->pgrpid), va, n, NUser);
1082 if(p->pid != PID(c->qid))
1085 switch(QID(c->qid)){
1094 memmove(arg, va, n);
1105 if(p->state != Stopped)
1107 n = procctlmemio(p, off2addr(off), n, va, 0);
1111 if(offset >= sizeof(Ureg))
1113 else if(offset+n > sizeof(Ureg))
1114 n = sizeof(Ureg) - offset;
1115 if(p->dbgreg == nil)
1117 setregisters(p->dbgreg, (char*)(p->dbgreg)+offset, va, n);
1121 if(offset >= sizeof(FPsave))
1123 else if(offset+n > sizeof(FPsave))
1124 n = sizeof(FPsave) - offset;
1125 memmove((uchar*)&p->fpsave+offset, va, n);
1129 procctlreq(p, va, n);
1137 memmove(buf, va, n);
1139 if(!postnote(p, 0, buf, NUser))
1140 error("note not posted");
1153 for(et = t+conf.nproc; t < et; t++) {
1154 if(t->state == Dead || t->kp)
1156 if(id == t->noteid) {
1158 if(strcmp(p->user, t->user) != 0)
1168 print("unknown qid in procwrite\n");
1198 proctext(Chan *c, Proc *p)
1227 if(incref(tc) == 1 || (tc->flag&COPEN) == 0 || tc->mode != OREAD) {
1232 if(p->pid != PID(c->qid)) {
1244 procstopwait(Proc *p, int ctl)
1250 if(procstopped(p) || p->state == Broken)
1259 up->psstate = "Stopwait";
1265 sleep(&up->sleep, procstopped, p);
1273 procctlclosefiles(Proc *p, int all, int fd)
1286 while(fd <= f->maxfd){
1305 parsetime(vlong *rt, char *s)
1310 static int p10[] = {100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1};
1313 return("missing value");
1314 ticks=strtoul(s, &e, 10);
1317 l = strtoul(p, &e, 10);
1318 if(e-p > nelem(p10))
1319 return "too many digits after decimal point";
1321 return "ill-formed number";
1325 if (*e == '\0' || strcmp(e, "s") == 0){
1326 ticks = 1000000000 * ticks + l;
1327 }else if (strcmp(e, "ms") == 0){
1328 ticks = 1000000 * ticks + l/1000;
1329 }else if (strcmp(e, "µs") == 0 || strcmp(e, "us") == 0){
1330 ticks = 1000 * ticks + l/1000000;
1331 }else if (strcmp(e, "ns") != 0)
1332 return "unrecognized unit";
1338 procctlreq(Proc *p, char *va, int n)
1346 void (*pt)(Proc*, int, vlong);
1348 if(p->kp) /* no ctl requests to kprocs */
1351 cb = parsecmd(va, n);
1357 ct = lookupcmd(cb, proccmd, nelem(proccmd));
1361 procctlclosefiles(p, 0, atoi(cb->f[1]));
1364 procctlclosefiles(p, 1, 0);
1375 p->procctl = Proc_exitme;
1376 postnote(p, 0, "sys: killed", NExit);
1380 p->procctl = Proc_exitme;
1381 postnote(p, 0, "sys: killed", NExit);
1391 pri = atoi(cb->f[1]);
1392 if(pri > PriNormal && !iseve())
1394 procpriority(p, pri, 0);
1397 pri = atoi(cb->f[1]);
1398 if(pri > PriNormal && !iseve())
1400 procpriority(p, pri, 1);
1407 if(s == nil || (s->type&SG_TYPE) != SG_TEXT)
1409 if(s->profile != nil)
1411 npc = (s->top-s->base)>>LRESPROF;
1412 s->profile = malloc(npc*sizeof(*s->profile));
1413 if(s->profile == nil)
1417 if(p->state != Stopped)
1422 if(p->state != Stopped)
1424 p->procctl = Proc_traceme;
1426 procstopwait(p, Proc_traceme);
1428 case CMstartsyscall:
1429 if(p->state != Stopped)
1431 p->procctl = Proc_tracesyscall;
1433 procstopwait(p, Proc_tracesyscall);
1436 procstopwait(p, Proc_stopme);
1442 procwired(p, atoi(cb->f[1]));
1450 p->trace = (atoi(cb->f[1]) != 0);
1457 postnote(p, 0, nil, NUser);
1463 error("notes pending");
1469 if(e=parsetime(&time, cb->f[1])) /* time in ns */
1472 p->edf->T = time/1000; /* Edf times are in µs */
1477 if(e=parsetime(&time, cb->f[1]))
1480 p->edf->D = time/1000;
1485 if(e=parsetime(&time, cb->f[1]))
1488 p->edf->C = time/1000;
1493 p->edf->flags |= Sporadic;
1495 case CMdeadlinenotes:
1498 p->edf->flags |= Sendnotes;
1502 error("edf params");
1509 p->edf->flags |= Extratime;
1517 if(up->trace && pt != nil)
1527 procstopped(void *a)
1529 return ((Proc*)a)->state == Stopped;
1533 procctlmemio(Proc *p, uintptr offset, int n, void *va, int read)
1543 /* Only one page at a time */
1544 l = BY2PG - (offset&(BY2PG-1));
1549 * Make temporary copy to avoid fault while we have
1550 * segment locked as we would deadlock when trying
1551 * to read the calling procs memory.
1562 memmove(a, va, n); /* can fault */
1565 s = seg(p, offset, 0);
1569 eqlock(&p->seglock);
1571 qunlock(&p->seglock);
1575 for(i = 0; i < NSEG; i++) {
1580 error(Egreg); /* segment gone */
1587 if(!read && (s->type&SG_TYPE) == SG_TEXT) {
1592 qunlock(&p->seglock);
1595 /* segment s still locked, fixfault() unlocks */
1600 if(fixfault(s, offset, read, 0) == 0)
1607 * Only access the page while segment is locked
1608 * as the proc could segfree or relocate the pte
1616 if(offset+n >= s->top)
1618 soff = offset-s->base;
1619 pte = s->map[soff/PTEMAPMEM];
1621 error(Egreg); /* page gone, should retry? */
1622 pg = pte->pages[(soff&(PTEMAPMEM-1))/BY2PG];
1624 error(Egreg); /* page gone, should retry? */
1626 /* Map and copy the page */
1629 b += offset&(BY2PG-1);
1636 /* Ensure the process sees text page changes */
1638 memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
1649 memmove(va, a, n); /* can fault */