📄 devproc.c
字号:
#include "u.h"#include "trace.h"#include "tos.h"#include "lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "error.h"#include "ureg.h"extern uchar _end[]; // Plan 9 VXenum{ Qdir, Qtrace, Qargs, Qctl, Qfd, Qfpregs, Qkregs, Qmem, Qnote, Qnoteid, Qnotepg, Qns, Qproc, Qregs, Qsegment, Qstatus, Qtext, Qwait, Qprofile,};enum{ CMclose, CMclosefiles, CMfixedpri, CMhang, CMkill, CMnohang, CMnoswap, CMpri, CMprivate, CMprofile, CMstart, CMstartstop, CMstartsyscall, CMstop, CMwaitstop, CMwired, CMtrace,};enum{ Nevents = 0x4000, Emask = Nevents - 1,};#define STATSIZE (2*KNAMELEN+12+9*12)/* * Status, fd, and ns are left fully readable (0444) because of their use in debugging, * particularly on shared servers. * Arguably, ns and fd shouldn't be readable; if you'd prefer, change them to 0000 */Dirtab procdir[] ={ "args", {Qargs}, 0, 0660, "ctl", {Qctl}, 0, 0000, "fd", {Qfd}, 0, 0444, "fpregs", {Qfpregs}, sizeof(FPsave), 0000, "kregs", {Qkregs}, sizeof(Ureg), 0400, "mem", {Qmem}, 0, 0000, "note", {Qnote}, 0, 0000, "noteid", {Qnoteid}, 0, 0664, "notepg", {Qnotepg}, 0, 0000, "ns", {Qns}, 0, 0444, "proc", {Qproc}, 0, 0400, "regs", {Qregs}, sizeof(Ureg), 0000, "segment", {Qsegment}, 0, 0444, "status", {Qstatus}, STATSIZE, 0444, "text", {Qtext}, 0, 0000, "wait", {Qwait}, 0, 0400, "profile", {Qprofile}, 0, 0400,};staticCmdtab proccmd[] = { CMclose, "close", 2, CMclosefiles, "closefiles", 1, CMfixedpri, "fixedpri", 2, CMhang, "hang", 1, CMnohang, "nohang", 1, CMnoswap, "noswap", 1, CMkill, "kill", 1, CMpri, "pri", 2, CMprivate, "private", 1, CMprofile, "profile", 1, CMstart, "start", 1, CMstartstop, "startstop", 1, CMstartsyscall, "startsyscall", 1, CMstop, "stop", 1, CMwaitstop, "waitstop", 1, CMwired, "wired", 2, CMtrace, "trace", 0,};/* Segment type from portdat.h */static char *sname[]={ "Text", "Data", "Bss", "Stack", "Shared", "Phys", };/* * Qids are, in path: * 4 bits of file type (qids above) * 23 bits of process slot number + 1 * in vers, * 32 bits of pid, for consistency checking * If notepg, c->pgrpid.path is pgrp slot, .vers is noteid. */#define QSHIFT 5 /* location in qid of proc slot # */#define QID(q) ((((ulong)(q).path)&0x0000001F)>>0)#define SLOT(q) (((((ulong)(q).path)&0x07FFFFFE0)>>QSHIFT)-1)#define PID(q) ((q).vers)#define NOTEID(q) ((q).vers)void procctlreq(Proc*, char*, int);int procctlmemio(Proc*, ulong, int, void*, int);Chan* proctext(Chan*, Proc*);Segment* txt2data(Proc*, Segment*);int procstopped(void*);void mntscan(Mntwalk*, Proc*);static Traceevent *tevents;static Lock tlock;static int topens;static int tproduced, tconsumed;void (*proctrace)(Proc*, int, vlong);extern int unfair;static voidprofclock(Ureg *ur, Timer *t){#if 0 Tos *tos; if(up == 0 || up->state != Running) return; /* user profiling clock */ if(userureg(ur)){ tos = (Tos*)(USTKTOP-sizeof(Tos)); tos->clock += TK2MS(1); segclock(ur->pc); }#endif}static intprocgen(Chan *c, char *name, Dirtab *tab, int _, int s, Dir *dp){ Qid qid; Proc *p; char *ename; Segment *q; ulong pid, path, perm, len; if(s == DEVDOTDOT){ mkqid(&qid, Qdir, 0, QTDIR); devdir(c, qid, "#p", 0, eve, 0555, dp); return 1; } if(c->qid.path == Qdir){ if(s == 0){ strcpy(up->genbuf, "trace"); mkqid(&qid, Qtrace, -1, QTFILE); devdir(c, qid, up->genbuf, 0, eve, 0444, dp); return 1; } if(name != nil){ /* ignore s and use name to find pid */ pid = strtol(name, &ename, 10); if(pid==0 || ename[0]!='\0') return -1; s = procindex(pid); if(s < 0) return -1; } else if(--s >= conf.nproc) return -1; p = proctab(s); pid = p->pid; if(pid == 0) return 0; sprint(up->genbuf, "%lud", pid); /* * String comparison is done in devwalk so name must match its formatted pid */ if(name != nil && strcmp(name, up->genbuf) != 0) return -1; mkqid(&qid, (s+1)<<QSHIFT, pid, QTDIR); devdir(c, qid, up->genbuf, 0, p->user, DMDIR|0555, dp); return 1; } if(c->qid.path == Qtrace){ strcpy(up->genbuf, "trace"); mkqid(&qid, Qtrace, -1, QTFILE); devdir(c, qid, up->genbuf, 0, eve, 0444, dp); return 1; } if(s >= nelem(procdir)) return -1; if(tab) panic("procgen"); tab = &procdir[s]; path = c->qid.path&~(((1<<QSHIFT)-1)); /* slot component */ p = proctab(SLOT(c->qid)); perm = tab->perm; if(perm == 0) perm = p->procmode; else /* just copy read bits */ perm |= p->procmode & 0444; len = tab->length; switch(QID(c->qid)) { case Qwait: len = p->nwait; /* incorrect size, but >0 means there's something to read */ break; case Qprofile: q = p->seg[TSEG]; if(q && q->profile) { len = (q->top-q->base)>>LRESPROF; len *= sizeof(*q->profile); } break; } mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE); devdir(c, qid, tab->name, len, p->user, perm, dp); return 1;}static void_proctrace(Proc* p, int etype, vlong ts){ Traceevent *te; if (p->trace == 0 || topens == 0 || tproduced - tconsumed >= Nevents) return; te = &tevents[tproduced&Emask]; te->pid = p->pid; te->etype = etype; if (ts == 0) te->time = todget(nil); else te->time = ts; tproduced++;}static voidprocinit(void){ if(conf.nproc >= (1<<(16-QSHIFT))-1) print("warning: too many procs for devproc\n"); addclock0link((void (*)(void))profclock, 113); /* Relative prime to HZ */}static Chan*procattach(char *spec){ return devattach('p', spec);}static Walkqid*procwalk(Chan *c, Chan *nc, char **name, int nname){ return devwalk(c, nc, name, nname, 0, 0, procgen);}static intprocstat(Chan *c, uchar *db, int n){ return devstat(c, db, n, 0, 0, procgen);}/* * none can't read or write state on other * processes. This is to contain access of * servers running as none should they be * subverted by, for example, a stack attack. */static voidnonone(Proc *p){ if(p == up) return; if(strcmp(up->user, "none") != 0) return; if(iseve()) return; error(Eperm);}static Chan*procopen(Chan *c, int omode){ Proc *p; Pgrp *pg; Chan *tc; int pid; if(c->qid.type & QTDIR) return devopen(c, omode, 0, 0, procgen); if(QID(c->qid) == Qtrace){ if (omode != OREAD) error(Eperm); lock(&tlock); if (waserror()){ unlock(&tlock); nexterror(); } if (topens > 0) error("already open"); topens++; if (tevents == nil){ tevents = (Traceevent*)malloc(sizeof(Traceevent) * Nevents); if(tevents == nil) error(Enomem); tproduced = tconsumed = 0; } proctrace = _proctrace; unlock(&tlock); poperror(); c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; return c; } p = proctab(SLOT(c->qid)); qlock(&p->debug); if(waserror()){ qunlock(&p->debug); nexterror(); } pid = PID(c->qid); if(p->pid != pid) error(Eprocdied); omode = openmode(omode); switch(QID(c->qid)){ case Qtext: if(omode != OREAD) error(Eperm); tc = proctext(c, p); tc->offset = 0; qunlock(&p->debug); poperror(); return tc; case Qproc: case Qkregs: case Qsegment: case Qprofile: case Qfd: if(omode != OREAD) error(Eperm); break; case Qnote: if(p->privatemem) error(Eperm); break; case Qmem: case Qctl: if(p->privatemem) error(Eperm); nonone(p); break; case Qargs: case Qnoteid: case Qstatus: case Qwait: case Qregs: case Qfpregs: nonone(p); break; case Qns: if(omode != OREAD) error(Eperm); c->aux = malloc(sizeof(Mntwalk)); break; case Qnotepg: nonone(p); pg = p->pgrp; if(pg == nil) error(Eprocdied); if(omode!=OWRITE || pg->pgrpid == 1) error(Eperm); c->pgrpid.path = pg->pgrpid+1; c->pgrpid.vers = p->noteid; break; default: pprint("procopen %lux\n", c->qid); error(Egreg); } /* Affix pid to qid */ if(p->state != Dead) c->qid.vers = p->pid; /* make sure the process slot didn't get reallocated while we were playing */ coherence(); if(p->pid != pid) error(Eprocdied); tc = devopen(c, omode, 0, 0, procgen); qunlock(&p->debug); poperror(); return tc;}static intprocwstat(Chan *c, uchar *db, int n){ Proc *p; Dir *d; if(c->qid.type&QTDIR) error(Eperm); if(QID(c->qid) == Qtrace) return devwstat(c, db, n); p = proctab(SLOT(c->qid)); nonone(p); d = nil; if(waserror()){ free(d); qunlock(&p->debug); nexterror(); } qlock(&p->debug); if(p->pid != PID(c->qid)) error(Eprocdied); if(strcmp(up->user, p->user) != 0 && strcmp(up->user, eve) != 0) error(Eperm); d = smalloc(sizeof(Dir)+n); n = convM2D(db, n, &d[0], (char*)&d[1]); if(n == 0) error(Eshortstat); if(!emptystr(d->uid) && strcmp(d->uid, p->user) != 0){ if(strcmp(up->user, eve) != 0) error(Eperm); else kstrdup(&p->user, d->uid); } if(d->mode != ~0UL) p->procmode = d->mode&0777; poperror(); free(d); qunlock(&p->debug); return n;}static longprocoffset(long offset, char *va, int *np){ if(offset > 0) { offset -= *np; if(offset < 0) { memmove(va, va+*np+offset, -offset); *np = -offset; } else *np = 0; } return offset;}static intprocqidwidth(Chan *c){ char buf[32]; return sprint(buf, "%lud", c->qid.vers);}intprocfdprint(Chan *c, int fd, int w, char *s, int ns){ int n; if(w == 0) w = procqidwidth(c); n = snprint(s, ns, "%3d %.2s %C %4ld (%.16llux %*lud %.2ux) %5ld %8lld %s\n", fd, &"r w rw"[(c->mode&3)<<1], devtab[c->type]->dc, c->dev, c->qid.path, w, c->qid.vers, c->qid.type, c->iounit, c->offset, c->path->s); return n;}static intprocfds(Proc *p, char *va, int count, long offset){ Fgrp *f; Chan *c; char buf[256]; int n, i, w, ww; char *a; /* print to buf to avoid holding fgrp lock while writing to user space */ if(count > sizeof buf) count = sizeof buf; a = buf; qlock(&p->debug); f = p->fgrp; if(f == nil){ qunlock(&p->debug); return 0; } lock(&f->ref.lk); if(waserror()){ unlock(&f->ref.lk); qunlock(&p->debug); nexterror(); } n = readstr(0, a, count, p->dot->path->s); n += snprint(a+n, count-n, "\n"); offset = procoffset(offset, a, &n); /* compute width of qid.path */ w = 0; for(i = 0; i <= f->maxfd; i++) { c = f->fd[i]; if(c == nil) continue; ww = procqidwidth(c); if(ww > w) w = ww; } for(i = 0; i <= f->maxfd; i++) { c = f->fd[i]; if(c == nil) continue; n += procfdprint(c, i, w, a+n, count-n); offset = procoffset(offset, a, &n); } unlock(&f->ref.lk); qunlock(&p->debug); poperror(); /* copy result to user space, now that locks are released */ memmove(va, buf, n); return n;}static voidprocclose(Chan * c){ if(QID(c->qid) == Qtrace){ lock(&tlock); if(topens > 0) topens--; if(topens == 0) proctrace = nil; unlock(&tlock); } if(QID(c->qid) == Qns && c->aux != 0) free(c->aux);}static voidint2flag(int flag, char *s){ if(flag == 0){ *s = '\0'; return; } *s++ = '-'; if(flag & MAFTER) *s++ = 'a'; if(flag & MBEFORE) *s++ = 'b'; if(flag & MCREATE) *s++ = 'c'; if(flag & MCACHE) *s++ = 'C'; *s = '\0';}static intprocargs(Proc *p, char *buf, int nbuf){ int j, k, m; char *a; int n; a = p->args; if(p->setargs){ snprint(buf, nbuf, "%s [%s]", p->text, p->args); return strlen(buf); } n = p->nargs; for(j = 0; j < nbuf - 1; j += m){ if(n <= 0) break; if(j != 0) buf[j++] = ' '; m = snprint(buf+j, nbuf-j, "%q", a); k = strlen(a) + 1; a += k; n -= k; } return j;}static inteventsavailable(void *_){ return tproduced > tconsumed;}static longprocread(Chan *c, void *va, long n, vlong off){ /* NSEG*32 was too small for worst cases */ char *a, flag[10], *sps, *srv, statbuf[NSEG*64]; int i, j, m, navail, ne, pid, rsize; long l; uchar *rptr; ulong offset; Mntwalk *mw; Proc *p; Segment *sg, *s; Ureg kur; Waitq *wq; a = va; offset = off; if(c->qid.type & QTDIR) return devdirread(c, a, n, 0, 0, procgen); if(QID(c->qid) == Qtrace){ if(!eventsavailable(nil)) return 0; rptr = (uchar*)va; navail = tproduced - tconsumed; if(navail > n / sizeof(Traceevent)) navail = n / sizeof(Traceevent); while(navail > 0) { ne = ((tconsumed & Emask) + navail > Nevents)? Nevents - (tconsumed & Emask): navail; memmove(rptr, &tevents[tconsumed & Emask], ne * sizeof(Traceevent)); tconsumed += ne; rptr += ne * sizeof(Traceevent); navail -= ne; } return rptr - (uchar*)va; } p = proctab(SLOT(c->qid)); if(p->pid != PID(c->qid)) error(Eprocdied); switch(QID(c->qid)){ case Qargs: qlock(&p->debug); j = procargs(p, up->genbuf, sizeof up->genbuf); qunlock(&p->debug); if(offset >= j) return 0; if(offset+n > j) n = j-offset; memmove(a, &up->genbuf[offset], n); return n; case Qmem: if(offset < USTKTOP) return procctlmemio(p, offset, n, va, 1); error("no kernel memory access"); case Qprofile: s = p->seg[TSEG]; if(s == 0 || s->profile == 0) error("profile is off"); i = (s->top-s->base)>>LRESPROF; i *= sizeof(*s->profile); if(offset >= i) return 0; if(offset+n > i) n = i - offset; memmove(a, ((char*)s->profile)+offset, n); return n; case Qnote:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -