1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579 |
- #include "u.h"
- #include <trace.h>
- #include "tos.h"
- #include "../port/lib.h"
- #include "mem.h"
- #include "dat.h"
- #include "fns.h"
- #include "../port/error.h"
- #include "ureg.h"
- #include "edf.h"
- enum
- {
- 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,
- CMfair,
- CMunfair,
- CMtrace,
- /* real time */
- CMperiod,
- CMdeadline,
- CMcost,
- CMsporadic,
- CMdeadlinenotes,
- CMadmit,
- CMextra,
- CMexpel,
- };
- 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,
- };
- static
- Cmdtab 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,
- CMfair, "fair", 1,
- CMunfair, "unfair", 1,
- CMtrace, "trace", 0,
- CMperiod, "period", 2,
- CMdeadline, "deadline", 2,
- CMcost, "cost", 2,
- CMsporadic, "sporadic", 1,
- CMdeadlinenotes, "deadlinenotes", 1,
- CMadmit, "admit", 1,
- CMextra, "extra", 1,
- CMexpel, "expel", 1,
- };
- /* 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 void
- profclock(Ureg *ur, Timer *)
- {
- 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);
- }
- }
- static int
- procgen(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, Tevent 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 void
- procinit(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 int
- procstat(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 void
- nonone(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 int
- procwstat(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 long
- procoffset(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 int
- procqidwidth(Chan *c)
- {
- char buf[32];
- return sprint(buf, "%lud", c->qid.vers);
- }
- int
- procfdprint(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->name->s);
- return n;
- }
- static int
- procfds(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);
- if(waserror()){
- unlock(f);
- qunlock(&p->debug);
- nexterror();
- }
- n = readstr(0, a, count, p->dot->name->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);
- qunlock(&p->debug);
- poperror();
- /* copy result to user space, now that locks are released */
- memmove(va, buf, n);
- return n;
- }
- static void
- procclose(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 void
- int2flag(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 int
- procargs(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 int
- eventsavailable(void *)
- {
- return tproduced > tconsumed;
- }
- static long
- procread(Chan *c, void *va, long n, vlong off)
- {
- int m, navail, ne;
- long l;
- Proc *p;
- Waitq *wq;
- Ureg kur;
- uchar *rptr;
- Mntwalk *mw;
- Segment *sg, *s;
- char *a = va, *sps;
- int i, j, rsize, pid;
- char statbuf[NSEG*32], *srv, flag[10];
- ulong 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, p->genbuf, sizeof p->genbuf);
- qunlock(&p->debug);
- if(offset >= j)
- return 0;
- if(offset+n > j)
- n = j-offset;
- memmove(a, &p->genbuf[offset], n);
- return n;
- case Qmem:
- if(offset < KZERO
- || (offset >= USTKTOP-USTKSIZE && offset < USTKTOP))
- return procctlmemio(p, offset, n, va, 1);
- if(!iseve())
- error(Eperm);
- /* validate kernel addresses */
- if(offset < (ulong)end) {
- if(offset+n > (ulong)end)
- n = (ulong)end - offset;
- memmove(a, (char*)offset, n);
- return n;
- }
- /* conf.base* and conf.npage* are set by xinit to refer to kernel allocation, not user pages */
- if(offset >= conf.base0 && offset < conf.npage0){
- if(offset+n > conf.npage0)
- n = conf.npage0 - offset;
- memmove(a, (char*)offset, n);
- return n;
- }
- if(offset >= conf.base1 && offset < conf.npage1){
- if(offset+n > conf.npage1)
- n = conf.npage1 - offset;
- memmove(a, (char*)offset, n);
- return n;
- }
- error(Ebadarg);
- 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:
- qlock(&p->debug);
- if(waserror()){
- qunlock(&p->debug);
- nexterror();
- }
- if(p->pid != PID(c->qid))
- error(Eprocdied);
- if(n < 1) /* must accept at least the '\0' */
- error(Etoosmall);
- if(p->nnote == 0)
- n = 0;
- else {
- m = strlen(p->note[0].msg) + 1;
- if(m > n)
- m = n;
- memmove(va, p->note[0].msg, m);
- ((char*)va)[m-1] = '\0';
- p->nnote--;
- memmove(p->note, p->note+1, p->nnote*sizeof(Note));
- n = m;
- }
- if(p->nnote == 0)
- p->notepending = 0;
- poperror();
- qunlock(&p->debug);
- return n;
- case Qproc:
- if(offset >= sizeof(Proc))
- return 0;
- if(offset+n > sizeof(Proc))
- n = sizeof(Proc) - offset;
- memmove(a, ((char*)p)+offset, n);
- return n;
- case Qregs:
- rptr = (uchar*)p->dbgreg;
- rsize = sizeof(Ureg);
- goto regread;
- case Qkregs:
- memset(&kur, 0, sizeof(Ureg));
- setkernur(&kur, p);
- rptr = (uchar*)&kur;
- rsize = sizeof(Ureg);
- goto regread;
- case Qfpregs:
- rptr = (uchar*)&p->fpsave;
- rsize = sizeof(FPsave);
- regread:
- if(rptr == 0)
- error(Enoreg);
- if(offset >= rsize)
- return 0;
- if(offset+n > rsize)
- n = rsize - offset;
- memmove(a, rptr+offset, n);
- return n;
- case Qstatus:
- if(offset >= STATSIZE)
- return 0;
- if(offset+n > STATSIZE)
- n = STATSIZE - offset;
- sps = p->psstate;
- if(sps == 0)
- sps = statename[p->state];
- memset(statbuf, ' ', sizeof statbuf);
- memmove(statbuf+0*KNAMELEN, p->text, strlen(p->text));
- memmove(statbuf+1*KNAMELEN, p->user, strlen(p->user));
- memmove(statbuf+2*KNAMELEN, sps, strlen(sps));
- j = 2*KNAMELEN + 12;
- for(i = 0; i < 6; i++) {
- l = p->time[i];
- if(i == TReal)
- l = MACHP(0)->ticks - l;
- l = TK2MS(l);
- readnum(0, statbuf+j+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
- }
- /* ignore stack, which is mostly non-existent */
- l = 0;
- for(i=1; i<NSEG; i++){
- s = p->seg[i];
- if(s)
- l += s->top - s->base;
- }
- readnum(0, statbuf+j+NUMSIZE*6, NUMSIZE, l>>10, NUMSIZE);
- readnum(0, statbuf+j+NUMSIZE*7, NUMSIZE, p->basepri, NUMSIZE);
- readnum(0, statbuf+j+NUMSIZE*8, NUMSIZE, p->priority, NUMSIZE);
- memmove(a, statbuf+offset, n);
- return n;
- case Qsegment:
- j = 0;
- for(i = 0; i < NSEG; i++) {
- sg = p->seg[i];
- if(sg == 0)
- continue;
- j += sprint(statbuf+j, "%-6s %c%c %.8lux %.8lux %4ld\n",
- sname[sg->type&SG_TYPE],
- sg->type&SG_RONLY ? 'R' : ' ',
- sg->profile ? 'P' : ' ',
- sg->base, sg->top, sg->ref);
- }
- if(offset >= j)
- return 0;
- if(offset+n > j)
- n = j-offset;
- if(n == 0 && offset == 0)
- exhausted("segments");
- memmove(a, &statbuf[offset], n);
- return n;
- case Qwait:
- if(!canqlock(&p->qwaitr))
- error(Einuse);
- if(waserror()) {
- qunlock(&p->qwaitr);
- nexterror();
- }
- lock(&p->exl);
- if(up == p && p->nchild == 0 && p->waitq == 0) {
- unlock(&p->exl);
- error(Enochild);
- }
- pid = p->pid;
- while(p->waitq == 0) {
- unlock(&p->exl);
- sleep(&p->waitr, haswaitq, p);
- if(p->pid != pid)
- error(Eprocdied);
- lock(&p->exl);
- }
- wq = p->waitq;
- p->waitq = wq->next;
- p->nwait--;
- unlock(&p->exl);
- qunlock(&p->qwaitr);
- poperror();
- n = snprint(a, n, "%d %lud %lud %lud %q",
- wq->w.pid,
- wq->w.time[TUser], wq->w.time[TSys], wq->w.time[TReal],
- wq->w.msg);
- free(wq);
- return n;
- case Qns:
- qlock(&p->debug);
- if(waserror()){
- qunlock(&p->debug);
- nexterror();
- }
- if(p->pgrp == nil || p->pid != PID(c->qid))
- error(Eprocdied);
- mw = c->aux;
- if(mw->cddone){
- qunlock(&p->debug);
- poperror();
- return 0;
- }
- mntscan(mw, p);
- if(mw->mh == 0){
- mw->cddone = 1;
- i = snprint(a, n, "cd %s\n", p->dot->name->s);
- qunlock(&p->debug);
- poperror();
- return i;
- }
- int2flag(mw->cm->mflag, flag);
- if(strcmp(mw->cm->to->name->s, "#M") == 0){
- srv = srvname(mw->cm->to->mchan);
- i = snprint(a, n, "mount %s %s %s %s\n", flag,
- srv==nil? mw->cm->to->mchan->name->s : srv,
- mw->mh->from->name->s, mw->cm->spec? mw->cm->spec : "");
- free(srv);
- }else
- i = snprint(a, n, "bind %s %s %s\n", flag,
- mw->cm->to->name->s, mw->mh->from->name->s);
- qunlock(&p->debug);
- poperror();
- return i;
- case Qnoteid:
- return readnum(offset, va, n, p->noteid, NUMSIZE);
- case Qfd:
- return procfds(p, va, n, offset);
- }
- error(Egreg);
- return 0; /* not reached */
- }
- void
- mntscan(Mntwalk *mw, Proc *p)
- {
- Pgrp *pg;
- Mount *t;
- Mhead *f;
- int nxt, i;
- ulong last, bestmid;
- pg = p->pgrp;
- rlock(&pg->ns);
- nxt = 0;
- bestmid = ~0;
- last = 0;
- if(mw->mh)
- last = mw->cm->mountid;
- for(i = 0; i < MNTHASH; i++) {
- for(f = pg->mnthash[i]; f; f = f->hash) {
- for(t = f->mount; t; t = t->next) {
- if(mw->mh == 0 ||
- (t->mountid > last && t->mountid < bestmid)) {
- mw->cm = t;
- mw->mh = f;
- bestmid = mw->cm->mountid;
- nxt = 1;
- }
- }
- }
- }
- if(nxt == 0)
- mw->mh = 0;
- runlock(&pg->ns);
- }
- static long
- procwrite(Chan *c, void *va, long n, vlong off)
- {
- int id, m;
- Proc *p, *t, *et;
- char *a, *arg, buf[ERRMAX];
- ulong offset = off;
- a = va;
- if(c->qid.type & QTDIR)
- error(Eisdir);
- p = proctab(SLOT(c->qid));
- /* Use the remembered noteid in the channel rather
- * than the process pgrpid
- */
- if(QID(c->qid) == Qnotepg) {
- pgrpnote(NOTEID(c->pgrpid), va, n, NUser);
- return n;
- }
- qlock(&p->debug);
- if(waserror()){
- qunlock(&p->debug);
- nexterror();
- }
- if(p->pid != PID(c->qid))
- error(Eprocdied);
- switch(QID(c->qid)){
- case Qargs:
- if(n == 0)
- error(Eshort);
- if(n >= ERRMAX)
- error(Etoobig);
- arg = malloc(n+1);
- if(arg == nil)
- error(Enomem);
- memmove(arg, va, n);
- m = n;
- if(arg[m-1] != 0)
- arg[m++] = 0;
- free(p->args);
- p->nargs = m;
- p->args = arg;
- p->setargs = 1;
- break;
- case Qmem:
- if(p->state != Stopped)
- error(Ebadctl);
- n = procctlmemio(p, offset, n, va, 0);
- break;
- case Qregs:
- if(offset >= sizeof(Ureg))
- return 0;
- if(offset+n > sizeof(Ureg))
- n = sizeof(Ureg) - offset;
- if(p->dbgreg == 0)
- error(Enoreg);
- setregisters(p->dbgreg, (char*)(p->dbgreg)+offset, va, n);
- break;
- case Qfpregs:
- if(offset >= sizeof(FPsave))
- return 0;
- if(offset+n > sizeof(FPsave))
- n = sizeof(FPsave) - offset;
- memmove((uchar*)&p->fpsave+offset, va, n);
- break;
- case Qctl:
- procctlreq(p, va, n);
- break;
- case Qnote:
- if(p->kp)
- error(Eperm);
- if(n >= ERRMAX-1)
- error(Etoobig);
- memmove(buf, va, n);
- buf[n] = 0;
- if(!postnote(p, 0, buf, NUser))
- error("note not posted");
- break;
- case Qnoteid:
- id = atoi(a);
- if(id == p->pid) {
- p->noteid = id;
- break;
- }
- t = proctab(0);
- for(et = t+conf.nproc; t < et; t++) {
- if(t->state == Dead)
- continue;
- if(id == t->noteid) {
- if(strcmp(p->user, t->user) != 0)
- error(Eperm);
- p->noteid = id;
- break;
- }
- }
- if(p->noteid != id)
- error(Ebadarg);
- break;
- default:
- pprint("unknown qid in procwrite\n");
- error(Egreg);
- }
- poperror();
- qunlock(&p->debug);
- return n;
- }
- Dev procdevtab = {
- 'p',
- "proc",
- devreset,
- procinit,
- devshutdown,
- procattach,
- procwalk,
- procstat,
- procopen,
- devcreate,
- procclose,
- procread,
- devbread,
- procwrite,
- devbwrite,
- devremove,
- procwstat,
- };
- Chan*
- proctext(Chan *c, Proc *p)
- {
- Chan *tc;
- Image *i;
- Segment *s;
- s = p->seg[TSEG];
- if(s == 0)
- error(Enonexist);
- if(p->state==Dead)
- error(Eprocdied);
- lock(s);
- i = s->image;
- if(i == 0) {
- unlock(s);
- error(Eprocdied);
- }
- unlock(s);
- lock(i);
- if(waserror()) {
- unlock(i);
- nexterror();
- }
- tc = i->c;
- if(tc == 0)
- error(Eprocdied);
- if(incref(tc) == 1 || (tc->flag&COPEN) == 0 || tc->mode!=OREAD) {
- cclose(tc);
- error(Eprocdied);
- }
- if(p->pid != PID(c->qid))
- error(Eprocdied);
- unlock(i);
- poperror();
- return tc;
- }
- void
- procstopwait(Proc *p, int ctl)
- {
- int pid;
- if(p->pdbg)
- error(Einuse);
- if(procstopped(p) || p->state == Broken)
- return;
- if(ctl != 0)
- p->procctl = ctl;
- p->pdbg = up;
- pid = p->pid;
- qunlock(&p->debug);
- up->psstate = "Stopwait";
- if(waserror()) {
- p->pdbg = 0;
- qlock(&p->debug);
- nexterror();
- }
- sleep(&up->sleep, procstopped, p);
- poperror();
- qlock(&p->debug);
- if(p->pid != pid)
- error(Eprocdied);
- }
- static void
- procctlcloseone(Proc *p, Fgrp *f, int fd)
- {
- Chan *c;
- c = f->fd[fd];
- if(c == nil)
- return;
- f->fd[fd] = nil;
- unlock(f);
- qunlock(&p->debug);
- cclose(c);
- qlock(&p->debug);
- lock(f);
- }
- void
- procctlclosefiles(Proc *p, int all, int fd)
- {
- int i;
- Fgrp *f;
- f = p->fgrp;
- if(f == nil)
- error(Eprocdied);
- lock(f);
- f->ref++;
- if(all)
- for(i = 0; i < f->maxfd; i++)
- procctlcloseone(p, f, i);
- else
- procctlcloseone(p, f, fd);
- unlock(f);
- closefgrp(f);
- }
- static char *
- parsetime(vlong *rt, char *s)
- {
- uvlong ticks;
- ulong l;
- char *e, *p;
- static int p10[] = {100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1};
- if (s == nil)
- return("missing value");
- ticks=strtoul(s, &e, 10);
- if (*e == '.'){
- p = e+1;
- l = strtoul(p, &e, 10);
- if(e-p > nelem(p10))
- return "too many digits after decimal point";
- if(e-p == 0)
- return "ill-formed number";
- l *= p10[e-p-1];
- }else
- l = 0;
- if (*e == '\0' || strcmp(e, "s") == 0){
- ticks = 1000000000 * ticks + l;
- }else if (strcmp(e, "ms") == 0){
- ticks = 1000000 * ticks + l/1000;
- }else if (strcmp(e, "µs") == 0 || strcmp(e, "us") == 0){
- ticks = 1000 * ticks + l/1000000;
- }else if (strcmp(e, "ns") != 0)
- return "unrecognized unit";
- *rt = ticks;
- return nil;
- }
- void
- procctlreq(Proc *p, char *va, int n)
- {
- Segment *s;
- int npc, pri;
- Cmdbuf *cb;
- Cmdtab *ct;
- vlong time;
- char *e;
- if(p->kp) /* no ctl requests to kprocs */
- error(Eperm);
- cb = parsecmd(va, n);
- if(waserror()){
- free(cb);
- nexterror();
- }
- ct = lookupcmd(cb, proccmd, nelem(proccmd));
- switch(ct->index){
- case CMclose:
- procctlclosefiles(p, 0, atoi(cb->f[1]));
- break;
- case CMclosefiles:
- procctlclosefiles(p, 1, 0);
- break;
- case CMhang:
- p->hang = 1;
- break;
- case CMkill:
- switch(p->state) {
- case Broken:
- unbreak(p);
- break;
- case Stopped:
- postnote(p, 0, "sys: killed", NExit);
- p->procctl = Proc_exitme;
- ready(p);
- break;
- default:
- postnote(p, 0, "sys: killed", NExit);
- p->procctl = Proc_exitme;
- }
- break;
- case CMnohang:
- p->hang = 0;
- break;
- case CMnoswap:
- p->noswap = 1;
- break;
- case CMpri:
- pri = atoi(cb->f[1]);
- if(pri > PriNormal && !iseve())
- error(Eperm);
- procpriority(p, pri, 0);
- break;
- case CMfixedpri:
- pri = atoi(cb->f[1]);
- if(pri > PriNormal && !iseve())
- error(Eperm);
- procpriority(p, pri, 1);
- break;
- case CMprivate:
- p->privatemem = 1;
- break;
- case CMprofile:
- s = p->seg[TSEG];
- if(s == 0 || (s->type&SG_TYPE) != SG_TEXT)
- error(Ebadctl);
- if(s->profile != 0)
- free(s->profile);
- npc = (s->top-s->base)>>LRESPROF;
- s->profile = malloc(npc*sizeof(*s->profile));
- if(s->profile == 0)
- error(Enomem);
- break;
- case CMstart:
- if(p->state != Stopped)
- error(Ebadctl);
- ready(p);
- break;
- case CMstartstop:
- if(p->state != Stopped)
- error(Ebadctl);
- p->procctl = Proc_traceme;
- ready(p);
- procstopwait(p, Proc_traceme);
- break;
- case CMstartsyscall:
- if(p->state != Stopped)
- error(Ebadctl);
- p->procctl = Proc_tracesyscall;
- ready(p);
- procstopwait(p, Proc_tracesyscall);
- break;
- case CMstop:
- procstopwait(p, Proc_stopme);
- break;
- case CMwaitstop:
- procstopwait(p, 0);
- break;
- case CMwired:
- procwired(p, atoi(cb->f[1]));
- break;
- case CMtrace:
- switch(cb->nf){
- case 1:
- p->trace ^= 1;
- break;
- case 2:
- p->trace = atoi(cb->f[1])?1:0;
- break;
- default:
- error("args");
- }
- break;
- /* real time */
- case CMperiod:
- if(p->edf == nil)
- edfinit(p);
- if(e=parsetime(&time, cb->f[1]))
- error(e);
- edfstop(p);
- p->edf->T = time;
- break;
- case CMdeadline:
- if(p->edf == nil)
- edfinit(p);
- if(e=parsetime(&time, cb->f[1]))
- error(e);
- edfstop(p);
- p->edf->D = time;
- break;
- case CMcost:
- if(p->edf == nil)
- edfinit(p);
- if(e=parsetime(&time, cb->f[1]))
- error(e);
- edfstop(p);
- p->edf->C = time;
- break;
- case CMsporadic:
- if(p->edf == nil)
- edfinit(p);
- p->edf->flags |= Sporadic;
- break;
- case CMdeadlinenotes:
- if(p->edf == nil)
- edfinit(p);
- p->edf->flags |= Sendnotes;
- break;
- case CMadmit:
- if(p->edf == 0)
- error("edf params");
- if(e = edfadmit(p))
- error(e);
- break;
- case CMextra:
- if(p->edf == nil)
- edfinit(p);
- p->edf->flags |= Extratime;
- break;
- case CMexpel:
- if(p->edf)
- edfstop(p);
- break;
- }
- poperror();
- free(cb);
- }
- int
- procstopped(void *a)
- {
- Proc *p = a;
- return p->state == Stopped;
- }
- int
- procctlmemio(Proc *p, ulong offset, int n, void *va, int read)
- {
- KMap *k;
- Pte *pte;
- Page *pg;
- Segment *s;
- ulong soff, l;
- char *a = va, *b;
- for(;;) {
- s = seg(p, offset, 1);
- if(s == 0)
- error(Ebadarg);
- if(offset+n >= s->top)
- n = s->top-offset;
- if(!read && (s->type&SG_TYPE) == SG_TEXT)
- s = txt2data(p, s);
- s->steal++;
- soff = offset-s->base;
- if(waserror()) {
- s->steal--;
- nexterror();
- }
- if(fixfault(s, offset, read, 0) == 0)
- break;
- poperror();
- s->steal--;
- }
- poperror();
- pte = s->map[soff/PTEMAPMEM];
- if(pte == 0)
- panic("procctlmemio");
- pg = pte->pages[(soff&(PTEMAPMEM-1))/BY2PG];
- if(pagedout(pg))
- panic("procctlmemio1");
- l = BY2PG - (offset&(BY2PG-1));
- if(n > l)
- n = l;
- k = kmap(pg);
- if(waserror()) {
- s->steal--;
- kunmap(k);
- nexterror();
- }
- b = (char*)VA(k);
- b += offset&(BY2PG-1);
- if(read == 1)
- memmove(a, b, n); /* This can fault */
- else
- memmove(b, a, n);
- kunmap(k);
- poperror();
- /* Ensure the process sees text page changes */
- if(s->flushme)
- memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
- s->steal--;
- if(read == 0)
- p->newtlb = 1;
- return n;
- }
- Segment*
- txt2data(Proc *p, Segment *s)
- {
- int i;
- Segment *ps;
- ps = newseg(SG_DATA, s->base, s->size);
- ps->image = s->image;
- incref(ps->image);
- ps->fstart = s->fstart;
- ps->flen = s->flen;
- ps->flushme = 1;
- qlock(&p->seglock);
- for(i = 0; i < NSEG; i++)
- if(p->seg[i] == s)
- break;
- if(p->seg[i] != s)
- panic("segment gone");
- qunlock(&s->lk);
- putseg(s);
- qlock(&ps->lk);
- p->seg[i] = ps;
- qunlock(&p->seglock);
- return ps;
- }
- Segment*
- data2txt(Segment *s)
- {
- Segment *ps;
- ps = newseg(SG_TEXT, s->base, s->size);
- ps->image = s->image;
- incref(ps->image);
- ps->fstart = s->fstart;
- ps->flen = s->flen;
- ps->flushme = 1;
- return ps;
- }
|