12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586 |
- #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,
- CMevent,
- };
- 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,
- CMevent, "event", 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->path->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->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);
- 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)
- {
- /* 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;
- Confmem *cm;
- 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, 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)
- 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;
- }
- for(i=0; i<nelem(conf.mem); i++){
- cm = &conf.mem[i];
- /* klimit-1 because klimit might be zero! */
- if(cm->kbase <= offset && offset <= cm->klimit-1){
- if(offset+n >= cm->klimit-1)
- n = cm->klimit - 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->path->s);
- qunlock(&p->debug);
- poperror();
- return i;
- }
- int2flag(mw->cm->mflag, flag);
- if(strcmp(mw->cm->to->path->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->path->s : srv,
- mw->mh->from->path->s, mw->cm->spec? mw->cm->spec : "");
- free(srv);
- }else
- i = snprint(a, n, "bind %s %s %s\n", flag,
- mw->cm->to->path->s, mw->mh->from->path->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;
- void (*pt)(Proc*, int, vlong);
- 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:
- p->procctl = Proc_exitme;
- postnote(p, 0, "sys: killed", NExit);
- ready(p);
- break;
- default:
- p->procctl = Proc_exitme;
- postnote(p, 0, "sys: killed", NExit);
- }
- 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]) != 0);
- break;
- default:
- error("args");
- }
- break;
- /* real time */
- case CMperiod:
- if(p->edf == nil)
- edfinit(p);
- if(e=parsetime(&time, cb->f[1])) /* time in ns */
- error(e);
- edfstop(p);
- p->edf->T = time/1000; /* Edf times are in µs */
- break;
- case CMdeadline:
- if(p->edf == nil)
- edfinit(p);
- if(e=parsetime(&time, cb->f[1]))
- error(e);
- edfstop(p);
- p->edf->D = time/1000;
- break;
- case CMcost:
- if(p->edf == nil)
- edfinit(p);
- if(e=parsetime(&time, cb->f[1]))
- error(e);
- edfstop(p);
- p->edf->C = time/1000;
- 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;
- case CMevent:
- pt = proctrace;
- if(up->trace && pt)
- pt(up, SUser, 0);
- 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;
- }
|