The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/port/devproc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 #include        "u.h"
    2 #include        <trace.h>
    3 #include        "tos.h"
    4 #include        "../port/lib.h"
    5 #include        "mem.h"
    6 #include        "dat.h"
    7 #include        "fns.h"
    8 #include        "../port/error.h"
    9 #include        "ureg.h"
   10 #include        "edf.h"
   11 
   12 enum
   13 {
   14         Qdir,
   15         Qtrace,
   16         Qargs,
   17         Qctl,
   18         Qfd,
   19         Qfpregs,
   20         Qkregs,
   21         Qmem,
   22         Qnote,
   23         Qnoteid,
   24         Qnotepg,
   25         Qns,
   26         Qproc,
   27         Qregs,
   28         Qsegment,
   29         Qstatus,
   30         Qtext,
   31         Qwait,
   32         Qprofile,
   33 };
   34 
   35 enum
   36 {
   37         CMclose,
   38         CMclosefiles,
   39         CMfixedpri,
   40         CMhang,
   41         CMkill,
   42         CMnohang,
   43         CMnoswap,
   44         CMpri,
   45         CMprivate,
   46         CMprofile,
   47         CMstart,
   48         CMstartstop,
   49         CMstartsyscall,
   50         CMstop,
   51         CMwaitstop,
   52         CMwired,
   53         CMtrace,
   54         /* real time */
   55         CMperiod,
   56         CMdeadline,
   57         CMcost,
   58         CMsporadic,
   59         CMdeadlinenotes,
   60         CMadmit,
   61         CMextra,
   62         CMexpel,
   63         CMevent,
   64 };
   65 
   66 enum{
   67         Nevents = 0x4000,
   68         Emask = Nevents - 1,
   69 };
   70 
   71 #define STATSIZE        (2*KNAMELEN+12+9*12)
   72 /*
   73  * Status, fd, and ns are left fully readable (0444) because of their use in debugging,
   74  * particularly on shared servers.
   75  * Arguably, ns and fd shouldn't be readable; if you'd prefer, change them to 0000
   76  */
   77 Dirtab procdir[] =
   78 {
   79         "args",         {Qargs},        0,                      0660,
   80         "ctl",          {Qctl},         0,                      0000,
   81         "fd",           {Qfd},          0,                      0444,
   82         "fpregs",       {Qfpregs},      sizeof(FPsave),         0000,
   83         "kregs",        {Qkregs},       sizeof(Ureg),           0400,
   84         "mem",          {Qmem},         0,                      0000,
   85         "note",         {Qnote},        0,                      0000,
   86         "noteid",       {Qnoteid},      0,                      0664,
   87         "notepg",       {Qnotepg},      0,                      0000,
   88         "ns",           {Qns},          0,                      0444,
   89         "proc",         {Qproc},        0,                      0400,
   90         "regs",         {Qregs},        sizeof(Ureg),           0000,
   91         "segment",      {Qsegment},     0,                      0444,
   92         "status",       {Qstatus},      STATSIZE,               0444,
   93         "text",         {Qtext},        0,                      0000,
   94         "wait",         {Qwait},        0,                      0400,
   95         "profile",      {Qprofile},     0,                      0400,
   96 };
   97 
   98 static
   99 Cmdtab proccmd[] = {
  100         CMclose,                "close",                2,
  101         CMclosefiles,           "closefiles",           1,
  102         CMfixedpri,             "fixedpri",             2,
  103         CMhang,                 "hang",                 1,
  104         CMnohang,               "nohang",               1,
  105         CMnoswap,               "noswap",               1,
  106         CMkill,                 "kill",                 1,
  107         CMpri,                  "pri",                  2,
  108         CMprivate,              "private",              1,
  109         CMprofile,              "profile",              1,
  110         CMstart,                "start",                1,
  111         CMstartstop,            "startstop",            1,
  112         CMstartsyscall,         "startsyscall",         1,
  113         CMstop,                 "stop",                 1,
  114         CMwaitstop,             "waitstop",             1,
  115         CMwired,                "wired",                2,
  116         CMtrace,                "trace",                0,
  117         CMperiod,               "period",               2,
  118         CMdeadline,             "deadline",             2,
  119         CMcost,                 "cost",                 2,
  120         CMsporadic,             "sporadic",             1,
  121         CMdeadlinenotes,        "deadlinenotes",        1,
  122         CMadmit,                "admit",                1,
  123         CMextra,                "extra",                1,
  124         CMexpel,                "expel",                1,
  125         CMevent,                "event",                1,
  126 };
  127 
  128 /* Segment type from portdat.h */
  129 static char *sname[]={ "Text", "Data", "Bss", "Stack", "Shared", "Phys", };
  130 
  131 /*
  132  * Qids are, in path:
  133  *       4 bits of file type (qids above)
  134  *      23 bits of process slot number + 1
  135  *           in vers,
  136  *      32 bits of pid, for consistency checking
  137  * If notepg, c->pgrpid.path is pgrp slot, .vers is noteid.
  138  */
  139 #define QSHIFT  5       /* location in qid of proc slot # */
  140 
  141 #define QID(q)          ((((ulong)(q).path)&0x0000001F)>>0)
  142 #define SLOT(q)         (((((ulong)(q).path)&0x07FFFFFE0)>>QSHIFT)-1)
  143 #define PID(q)          ((q).vers)
  144 #define NOTEID(q)       ((q).vers)
  145 
  146 void    procctlreq(Proc*, char*, int);
  147 int     procctlmemio(Proc*, ulong, int, void*, int);
  148 Chan*   proctext(Chan*, Proc*);
  149 Segment* txt2data(Proc*, Segment*);
  150 int     procstopped(void*);
  151 void    mntscan(Mntwalk*, Proc*);
  152 
  153 static Traceevent *tevents;
  154 static Lock tlock;
  155 static int topens;
  156 static int tproduced, tconsumed;
  157 void (*proctrace)(Proc*, int, vlong);
  158 
  159 extern int unfair;
  160 
  161 static void
  162 profclock(Ureg *ur, Timer *)
  163 {
  164         Tos *tos;
  165 
  166         if(up == 0 || up->state != Running)
  167                 return;
  168 
  169         /* user profiling clock */
  170         if(userureg(ur)){
  171                 tos = (Tos*)(USTKTOP-sizeof(Tos));
  172                 tos->clock += TK2MS(1);
  173                 segclock(ur->pc);
  174         }
  175 }
  176 
  177 static int
  178 procgen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp)
  179 {
  180         Qid qid;
  181         Proc *p;
  182         char *ename;
  183         Segment *q;
  184         ulong pid, path, perm, len;
  185 
  186         if(s == DEVDOTDOT){
  187                 mkqid(&qid, Qdir, 0, QTDIR);
  188                 devdir(c, qid, "#p", 0, eve, 0555, dp);
  189                 return 1;
  190         }
  191 
  192         if(c->qid.path == Qdir){
  193                 if(s == 0){
  194                         strcpy(up->genbuf, "trace");
  195                         mkqid(&qid, Qtrace, -1, QTFILE);
  196                         devdir(c, qid, up->genbuf, 0, eve, 0444, dp);
  197                         return 1;
  198                 }
  199 
  200                 if(name != nil){
  201                         /* ignore s and use name to find pid */
  202                         pid = strtol(name, &ename, 10);
  203                         if(pid==0 || ename[0]!='\0')
  204                                 return -1;
  205                         s = procindex(pid);
  206                         if(s < 0)
  207                                 return -1;
  208                 }
  209                 else if(--s >= conf.nproc)
  210                         return -1;
  211 
  212                 p = proctab(s);
  213                 pid = p->pid;
  214                 if(pid == 0)
  215                         return 0;
  216                 sprint(up->genbuf, "%lud", pid);
  217                 /*
  218                  * String comparison is done in devwalk so name must match its formatted pid
  219                 */
  220                 if(name != nil && strcmp(name, up->genbuf) != 0)
  221                         return -1;
  222                 mkqid(&qid, (s+1)<<QSHIFT, pid, QTDIR);
  223                 devdir(c, qid, up->genbuf, 0, p->user, DMDIR|0555, dp);
  224                 return 1;
  225         }
  226         if(c->qid.path == Qtrace){
  227                 strcpy(up->genbuf, "trace");
  228                 mkqid(&qid, Qtrace, -1, QTFILE);
  229                 devdir(c, qid, up->genbuf, 0, eve, 0444, dp);
  230                 return 1;
  231         }
  232         if(s >= nelem(procdir))
  233                 return -1;
  234         if(tab)
  235                 panic("procgen");
  236 
  237         tab = &procdir[s];
  238         path = c->qid.path&~(((1<<QSHIFT)-1));  /* slot component */
  239 
  240         p = proctab(SLOT(c->qid));
  241         perm = tab->perm;
  242         if(perm == 0)
  243                 perm = p->procmode;
  244         else    /* just copy read bits */
  245                 perm |= p->procmode & 0444;
  246 
  247         len = tab->length;
  248         switch(QID(c->qid)) {
  249         case Qwait:
  250                 len = p->nwait; /* incorrect size, but >0 means there's something to read */
  251                 break;
  252         case Qprofile:
  253                 q = p->seg[TSEG];
  254                 if(q && q->profile) {
  255                         len = (q->top-q->base)>>LRESPROF;
  256                         len *= sizeof(*q->profile);
  257                 }
  258                 break;
  259         }
  260 
  261         mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE);
  262         devdir(c, qid, tab->name, len, p->user, perm, dp);
  263         return 1;
  264 }
  265 
  266 static void
  267 _proctrace(Proc* p, Tevent etype, vlong ts)
  268 {
  269         Traceevent *te;
  270 
  271         if (p->trace == 0 || topens == 0 ||
  272                 tproduced - tconsumed >= Nevents)
  273                 return;
  274 
  275         te = &tevents[tproduced&Emask];
  276         te->pid = p->pid;
  277         te->etype = etype;
  278         if (ts == 0)
  279                 te->time = todget(nil);
  280         else
  281                 te->time = ts;
  282         tproduced++;
  283 }
  284 
  285 static void
  286 procinit(void)
  287 {
  288         if(conf.nproc >= (1<<(16-QSHIFT))-1)
  289                 print("warning: too many procs for devproc\n");
  290         addclock0link((void (*)(void))profclock, 113);  /* Relative prime to HZ */
  291 }
  292 
  293 static Chan*
  294 procattach(char *spec)
  295 {
  296         return devattach('p', spec);
  297 }
  298 
  299 static Walkqid*
  300 procwalk(Chan *c, Chan *nc, char **name, int nname)
  301 {
  302         return devwalk(c, nc, name, nname, 0, 0, procgen);
  303 }
  304 
  305 static int
  306 procstat(Chan *c, uchar *db, int n)
  307 {
  308         return devstat(c, db, n, 0, 0, procgen);
  309 }
  310 
  311 /*
  312  *  none can't read or write state on other
  313  *  processes.  This is to contain access of
  314  *  servers running as none should they be
  315  *  subverted by, for example, a stack attack.
  316  */
  317 static void
  318 nonone(Proc *p)
  319 {
  320         if(p == up)
  321                 return;
  322         if(strcmp(up->user, "none") != 0)
  323                 return;
  324         if(iseve())
  325                 return;
  326         error(Eperm);
  327 }
  328 
  329 static Chan*
  330 procopen(Chan *c, int omode)
  331 {
  332         Proc *p;
  333         Pgrp *pg;
  334         Chan *tc;
  335         int pid;
  336 
  337         if(c->qid.type & QTDIR)
  338                 return devopen(c, omode, 0, 0, procgen);
  339 
  340         if(QID(c->qid) == Qtrace){
  341                 if (omode != OREAD) 
  342                         error(Eperm);
  343                 lock(&tlock);
  344                 if (waserror()){
  345                         unlock(&tlock);
  346                         nexterror();
  347                 }
  348                 if (topens > 0)
  349                         error("already open");
  350                 topens++;
  351                 if (tevents == nil){
  352                         tevents = (Traceevent*)malloc(sizeof(Traceevent) * Nevents);
  353                         if(tevents == nil)
  354                                 error(Enomem);
  355                         tproduced = tconsumed = 0;
  356                 }
  357                 proctrace = _proctrace;
  358                 unlock(&tlock);
  359                 poperror();
  360 
  361                 c->mode = openmode(omode);
  362                 c->flag |= COPEN;
  363                 c->offset = 0;
  364                 return c;
  365         }
  366                 
  367         p = proctab(SLOT(c->qid));
  368         qlock(&p->debug);
  369         if(waserror()){
  370                 qunlock(&p->debug);
  371                 nexterror();
  372         }
  373         pid = PID(c->qid);
  374         if(p->pid != pid)
  375                 error(Eprocdied);
  376 
  377         omode = openmode(omode);
  378 
  379         switch(QID(c->qid)){
  380         case Qtext:
  381                 if(omode != OREAD)
  382                         error(Eperm);
  383                 tc = proctext(c, p);
  384                 tc->offset = 0;
  385                 qunlock(&p->debug);
  386                 poperror();
  387                 return tc;
  388 
  389         case Qproc:
  390         case Qkregs:
  391         case Qsegment:
  392         case Qprofile:
  393         case Qfd:
  394                 if(omode != OREAD)
  395                         error(Eperm);
  396                 break;
  397 
  398         case Qnote:
  399                 if(p->privatemem)
  400                         error(Eperm);
  401                 break;
  402 
  403         case Qmem:
  404         case Qctl:
  405                 if(p->privatemem)
  406                         error(Eperm);
  407                 nonone(p);
  408                 break;
  409 
  410         case Qargs:
  411         case Qnoteid:
  412         case Qstatus:
  413         case Qwait:
  414         case Qregs:
  415         case Qfpregs:
  416                 nonone(p);
  417                 break;
  418 
  419         case Qns:
  420                 if(omode != OREAD)
  421                         error(Eperm);
  422                 c->aux = malloc(sizeof(Mntwalk));
  423                 break;
  424 
  425         case Qnotepg:
  426                 nonone(p);
  427                 pg = p->pgrp;
  428                 if(pg == nil)
  429                         error(Eprocdied);
  430                 if(omode!=OWRITE || pg->pgrpid == 1)
  431                         error(Eperm);
  432                 c->pgrpid.path = pg->pgrpid+1;
  433                 c->pgrpid.vers = p->noteid;
  434                 break;
  435 
  436         default:
  437                 pprint("procopen %lux\n", c->qid);
  438                 error(Egreg);
  439         }
  440 
  441         /* Affix pid to qid */
  442         if(p->state != Dead)
  443                 c->qid.vers = p->pid;
  444 
  445         /* make sure the process slot didn't get reallocated while we were playing */
  446         coherence();
  447         if(p->pid != pid)
  448                 error(Eprocdied);
  449 
  450         tc = devopen(c, omode, 0, 0, procgen);
  451         qunlock(&p->debug);
  452         poperror();
  453 
  454         return tc;
  455 }
  456 
  457 static int
  458 procwstat(Chan *c, uchar *db, int n)
  459 {
  460         Proc *p;
  461         Dir *d;
  462 
  463         if(c->qid.type&QTDIR)
  464                 error(Eperm);
  465 
  466         if(QID(c->qid) == Qtrace)
  467                 return devwstat(c, db, n);
  468                 
  469         p = proctab(SLOT(c->qid));
  470         nonone(p);
  471         d = nil;
  472         if(waserror()){
  473                 free(d);
  474                 qunlock(&p->debug);
  475                 nexterror();
  476         }
  477         qlock(&p->debug);
  478 
  479         if(p->pid != PID(c->qid))
  480                 error(Eprocdied);
  481 
  482         if(strcmp(up->user, p->user) != 0 && strcmp(up->user, eve) != 0)
  483                 error(Eperm);
  484 
  485         d = smalloc(sizeof(Dir)+n);
  486         n = convM2D(db, n, &d[0], (char*)&d[1]);
  487         if(n == 0)
  488                 error(Eshortstat);
  489         if(!emptystr(d->uid) && strcmp(d->uid, p->user) != 0){
  490                 if(strcmp(up->user, eve) != 0)
  491                         error(Eperm);
  492                 else
  493                         kstrdup(&p->user, d->uid);
  494         }
  495         if(d->mode != ~0UL)
  496                 p->procmode = d->mode&0777;
  497 
  498         poperror();
  499         free(d);
  500         qunlock(&p->debug);
  501         return n;
  502 }
  503 
  504 
  505 static long
  506 procoffset(long offset, char *va, int *np)
  507 {
  508         if(offset > 0) {
  509                 offset -= *np;
  510                 if(offset < 0) {
  511                         memmove(va, va+*np+offset, -offset);
  512                         *np = -offset;
  513                 }
  514                 else
  515                         *np = 0;
  516         }
  517         return offset;
  518 }
  519 
  520 static int
  521 procqidwidth(Chan *c)
  522 {
  523         char buf[32];
  524 
  525         return sprint(buf, "%lud", c->qid.vers);
  526 }
  527 
  528 int
  529 procfdprint(Chan *c, int fd, int w, char *s, int ns)
  530 {
  531         int n;
  532 
  533         if(w == 0)
  534                 w = procqidwidth(c);
  535         n = snprint(s, ns, "%3d %.2s %C %4ld (%.16llux %*lud %.2ux) %5ld %8lld %s\n",
  536                 fd,
  537                 &"r w rw"[(c->mode&3)<<1],
  538                 devtab[c->type]->dc, c->dev,
  539                 c->qid.path, w, c->qid.vers, c->qid.type,
  540                 c->iounit, c->offset, c->path->s);
  541         return n;
  542 }
  543 
  544 static int
  545 procfds(Proc *p, char *va, int count, long offset)
  546 {
  547         Fgrp *f;
  548         Chan *c;
  549         char buf[256];
  550         int n, i, w, ww;
  551         char *a;
  552 
  553         /* print to buf to avoid holding fgrp lock while writing to user space */
  554         if(count > sizeof buf)
  555                 count = sizeof buf;
  556         a = buf;
  557 
  558         qlock(&p->debug);
  559         f = p->fgrp;
  560         if(f == nil){
  561                 qunlock(&p->debug);
  562                 return 0;
  563         }
  564         lock(f);
  565         if(waserror()){
  566                 unlock(f);
  567                 qunlock(&p->debug);
  568                 nexterror();
  569         }
  570 
  571         n = readstr(0, a, count, p->dot->path->s);
  572         n += snprint(a+n, count-n, "\n");
  573         offset = procoffset(offset, a, &n);
  574         /* compute width of qid.path */
  575         w = 0;
  576         for(i = 0; i <= f->maxfd; i++) {
  577                 c = f->fd[i];
  578                 if(c == nil)
  579                         continue;
  580                 ww = procqidwidth(c);
  581                 if(ww > w)
  582                         w = ww;
  583         }
  584         for(i = 0; i <= f->maxfd; i++) {
  585                 c = f->fd[i];
  586                 if(c == nil)
  587                         continue;
  588                 n += procfdprint(c, i, w, a+n, count-n);
  589                 offset = procoffset(offset, a, &n);
  590         }
  591         unlock(f);
  592         qunlock(&p->debug);
  593         poperror();
  594 
  595         /* copy result to user space, now that locks are released */
  596         memmove(va, buf, n);
  597 
  598         return n;
  599 }
  600 
  601 static void
  602 procclose(Chan * c)
  603 {
  604         if(QID(c->qid) == Qtrace){
  605                 lock(&tlock);
  606                 if(topens > 0)
  607                         topens--;
  608                 if(topens == 0)
  609                         proctrace = nil;
  610                 unlock(&tlock);
  611         }
  612         if(QID(c->qid) == Qns && c->aux != 0)
  613                 free(c->aux);
  614 }
  615 
  616 static void
  617 int2flag(int flag, char *s)
  618 {
  619         if(flag == 0){
  620                 *s = '\0';
  621                 return;
  622         }
  623         *s++ = '-';
  624         if(flag & MAFTER)
  625                 *s++ = 'a';
  626         if(flag & MBEFORE)
  627                 *s++ = 'b';
  628         if(flag & MCREATE)
  629                 *s++ = 'c';
  630         if(flag & MCACHE)
  631                 *s++ = 'C';
  632         *s = '\0';
  633 }
  634 
  635 static int
  636 procargs(Proc *p, char *buf, int nbuf)
  637 {
  638         int j, k, m;
  639         char *a;
  640         int n;
  641 
  642         a = p->args;
  643         if(p->setargs){
  644                 snprint(buf, nbuf, "%s [%s]", p->text, p->args);
  645                 return strlen(buf);
  646         }
  647         n = p->nargs;
  648         for(j = 0; j < nbuf - 1; j += m){
  649                 if(n <= 0)
  650                         break;
  651                 if(j != 0)
  652                         buf[j++] = ' ';
  653                 m = snprint(buf+j, nbuf-j, "%q",  a);
  654                 k = strlen(a) + 1;
  655                 a += k;
  656                 n -= k;
  657         }
  658         return j;
  659 }
  660 
  661 static int
  662 eventsavailable(void *)
  663 {
  664         return tproduced > tconsumed;
  665 }
  666 
  667 static long
  668 procread(Chan *c, void *va, long n, vlong off)
  669 {
  670         /* NSEG*32 was too small for worst cases */
  671         char *a, flag[10], *sps, *srv, statbuf[NSEG*64];
  672         int i, j, m, navail, ne, pid, rsize;
  673         long l;
  674         uchar *rptr;
  675         ulong offset;
  676         Confmem *cm;
  677         Mntwalk *mw;
  678         Proc *p;
  679         Segment *sg, *s;
  680         Ureg kur;
  681         Waitq *wq;
  682         
  683         a = va;
  684         offset = off;
  685 
  686         if(c->qid.type & QTDIR)
  687                 return devdirread(c, a, n, 0, 0, procgen);
  688 
  689         if(QID(c->qid) == Qtrace){
  690                 if(!eventsavailable(nil))
  691                         return 0;
  692 
  693                 rptr = (uchar*)va;
  694                 navail = tproduced - tconsumed;
  695                 if(navail > n / sizeof(Traceevent))
  696                         navail = n / sizeof(Traceevent);
  697                 while(navail > 0) {
  698                         ne = ((tconsumed & Emask) + navail > Nevents)? 
  699                                         Nevents - (tconsumed & Emask): navail;
  700                         memmove(rptr, &tevents[tconsumed & Emask], 
  701                                         ne * sizeof(Traceevent));
  702 
  703                         tconsumed += ne;
  704                         rptr += ne * sizeof(Traceevent);
  705                         navail -= ne;
  706                 }
  707                 return rptr - (uchar*)va;
  708         }
  709 
  710         p = proctab(SLOT(c->qid));
  711         if(p->pid != PID(c->qid))
  712                 error(Eprocdied);
  713 
  714         switch(QID(c->qid)){
  715         case Qargs:
  716                 qlock(&p->debug);
  717                 j = procargs(p, up->genbuf, sizeof up->genbuf);
  718                 qunlock(&p->debug);
  719                 if(offset >= j)
  720                         return 0;
  721                 if(offset+n > j)
  722                         n = j-offset;
  723                 memmove(a, &up->genbuf[offset], n);
  724                 return n;
  725 
  726         case Qmem:
  727                 if(offset < KZERO)
  728                         return procctlmemio(p, offset, n, va, 1);
  729 
  730                 if(!iseve())
  731                         error(Eperm);
  732 
  733                 /* validate kernel addresses */
  734                 if(offset < (ulong)end) {
  735                         if(offset+n > (ulong)end)
  736                                 n = (ulong)end - offset;
  737                         memmove(a, (char*)offset, n);
  738                         return n;
  739                 }
  740                 for(i=0; i<nelem(conf.mem); i++){
  741                         cm = &conf.mem[i];
  742                         /* klimit-1 because klimit might be zero! */
  743                         if(cm->kbase <= offset && offset <= cm->klimit-1){
  744                                 if(offset+n >= cm->klimit-1)
  745                                         n = cm->klimit - offset;
  746                                 memmove(a, (char*)offset, n);
  747                                 return n;
  748                         }
  749                 }
  750                 error(Ebadarg);
  751 
  752         case Qprofile:
  753                 s = p->seg[TSEG];
  754                 if(s == 0 || s->profile == 0)
  755                         error("profile is off");
  756                 i = (s->top-s->base)>>LRESPROF;
  757                 i *= sizeof(*s->profile);
  758                 if(offset >= i)
  759                         return 0;
  760                 if(offset+n > i)
  761                         n = i - offset;
  762                 memmove(a, ((char*)s->profile)+offset, n);
  763                 return n;
  764 
  765         case Qnote:
  766                 qlock(&p->debug);
  767                 if(waserror()){
  768                         qunlock(&p->debug);
  769                         nexterror();
  770                 }
  771                 if(p->pid != PID(c->qid))
  772                         error(Eprocdied);
  773                 if(n < 1)       /* must accept at least the '\0' */
  774                         error(Etoosmall);
  775                 if(p->nnote == 0)
  776                         n = 0;
  777                 else {
  778                         m = strlen(p->note[0].msg) + 1;
  779                         if(m > n)
  780                                 m = n;
  781                         memmove(va, p->note[0].msg, m);
  782                         ((char*)va)[m-1] = '\0';
  783                         p->nnote--;
  784                         memmove(p->note, p->note+1, p->nnote*sizeof(Note));
  785                         n = m;
  786                 }
  787                 if(p->nnote == 0)
  788                         p->notepending = 0;
  789                 poperror();
  790                 qunlock(&p->debug);
  791                 return n;
  792 
  793         case Qproc:
  794                 if(offset >= sizeof(Proc))
  795                         return 0;
  796                 if(offset+n > sizeof(Proc))
  797                         n = sizeof(Proc) - offset;
  798                 memmove(a, ((char*)p)+offset, n);
  799                 return n;
  800 
  801         case Qregs:
  802                 rptr = (uchar*)p->dbgreg;
  803                 rsize = sizeof(Ureg);
  804                 goto regread;
  805 
  806         case Qkregs:
  807                 memset(&kur, 0, sizeof(Ureg));
  808                 setkernur(&kur, p);
  809                 rptr = (uchar*)&kur;
  810                 rsize = sizeof(Ureg);
  811                 goto regread;
  812 
  813         case Qfpregs:
  814                 rptr = (uchar*)&p->fpsave;
  815                 rsize = sizeof(FPsave);
  816         regread:
  817                 if(rptr == 0)
  818                         error(Enoreg);
  819                 if(offset >= rsize)
  820                         return 0;
  821                 if(offset+n > rsize)
  822                         n = rsize - offset;
  823                 memmove(a, rptr+offset, n);
  824                 return n;
  825 
  826         case Qstatus:
  827                 if(offset >= STATSIZE)
  828                         return 0;
  829                 if(offset+n > STATSIZE)
  830                         n = STATSIZE - offset;
  831 
  832                 sps = p->psstate;
  833                 if(sps == 0)
  834                         sps = statename[p->state];
  835                 memset(statbuf, ' ', sizeof statbuf);
  836                 memmove(statbuf+0*KNAMELEN, p->text, strlen(p->text));
  837                 memmove(statbuf+1*KNAMELEN, p->user, strlen(p->user));
  838                 memmove(statbuf+2*KNAMELEN, sps, strlen(sps));
  839                 j = 2*KNAMELEN + 12;
  840 
  841                 for(i = 0; i < 6; i++) {
  842                         l = p->time[i];
  843                         if(i == TReal)
  844                                 l = MACHP(0)->ticks - l;
  845                         l = TK2MS(l);
  846                         readnum(0, statbuf+j+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
  847                 }
  848                 /* ignore stack, which is mostly non-existent */
  849                 l = 0;
  850                 for(i=1; i<NSEG; i++){
  851                         s = p->seg[i];
  852                         if(s)
  853                                 l += s->top - s->base;
  854                 }
  855                 readnum(0, statbuf+j+NUMSIZE*6, NUMSIZE, l>>10, NUMSIZE);
  856                 readnum(0, statbuf+j+NUMSIZE*7, NUMSIZE, p->basepri, NUMSIZE);
  857                 readnum(0, statbuf+j+NUMSIZE*8, NUMSIZE, p->priority, NUMSIZE);
  858                 memmove(a, statbuf+offset, n);
  859                 return n;
  860 
  861         case Qsegment:
  862                 j = 0;
  863                 for(i = 0; i < NSEG; i++) {
  864                         sg = p->seg[i];
  865                         if(sg == 0)
  866                                 continue;
  867                         j += sprint(statbuf+j, "%-6s %c%c %.8lux %.8lux %4ld\n",
  868                                 sname[sg->type&SG_TYPE],
  869                                 sg->type&SG_RONLY ? 'R' : ' ',
  870                                 sg->profile ? 'P' : ' ',
  871                                 sg->base, sg->top, sg->ref);
  872                 }
  873                 if(offset >= j)
  874                         return 0;
  875                 if(offset+n > j)
  876                         n = j-offset;
  877                 if(n == 0 && offset == 0)
  878                         exhausted("segments");
  879                 memmove(a, &statbuf[offset], n);
  880                 return n;
  881 
  882         case Qwait:
  883                 if(!canqlock(&p->qwaitr))
  884                         error(Einuse);
  885 
  886                 if(waserror()) {
  887                         qunlock(&p->qwaitr);
  888                         nexterror();
  889                 }
  890 
  891                 lock(&p->exl);
  892                 if(up == p && p->nchild == 0 && p->waitq == 0) {
  893                         unlock(&p->exl);
  894                         error(Enochild);
  895                 }
  896                 pid = p->pid;
  897                 while(p->waitq == 0) {
  898                         unlock(&p->exl);
  899                         sleep(&p->waitr, haswaitq, p);
  900                         if(p->pid != pid)
  901                                 error(Eprocdied);
  902                         lock(&p->exl);
  903                 }
  904                 wq = p->waitq;
  905                 p->waitq = wq->next;
  906                 p->nwait--;
  907                 unlock(&p->exl);
  908 
  909                 qunlock(&p->qwaitr);
  910                 poperror();
  911                 n = snprint(a, n, "%d %lud %lud %lud %q",
  912                         wq->w.pid,
  913                         wq->w.time[TUser], wq->w.time[TSys], wq->w.time[TReal],
  914                         wq->w.msg);
  915                 free(wq);
  916                 return n;
  917 
  918         case Qns:
  919                 qlock(&p->debug);
  920                 if(waserror()){
  921                         qunlock(&p->debug);
  922                         nexterror();
  923                 }
  924                 if(p->pgrp == nil || p->pid != PID(c->qid))
  925                         error(Eprocdied);
  926                 mw = c->aux;
  927                 if(mw->cddone){
  928                         qunlock(&p->debug);
  929                         poperror();
  930                         return 0;
  931                 }
  932                 mntscan(mw, p);
  933                 if(mw->mh == 0){
  934                         mw->cddone = 1;
  935                         i = snprint(a, n, "cd %s\n", p->dot->path->s);
  936                         qunlock(&p->debug);
  937                         poperror();
  938                         return i;
  939                 }
  940                 int2flag(mw->cm->mflag, flag);
  941                 if(strcmp(mw->cm->to->path->s, "#M") == 0){
  942                         srv = srvname(mw->cm->to->mchan);
  943                         i = snprint(a, n, "mount %s %s %s %s\n", flag,
  944                                 srv==nil? mw->cm->to->mchan->path->s : srv,
  945                                 mw->mh->from->path->s, mw->cm->spec? mw->cm->spec : "");
  946                         free(srv);
  947                 }else
  948                         i = snprint(a, n, "bind %s %s %s\n", flag,
  949                                 mw->cm->to->path->s, mw->mh->from->path->s);
  950                 qunlock(&p->debug);
  951                 poperror();
  952                 return i;
  953 
  954         case Qnoteid:
  955                 return readnum(offset, va, n, p->noteid, NUMSIZE);
  956         case Qfd:
  957                 return procfds(p, va, n, offset);
  958         }
  959         error(Egreg);
  960         return 0;               /* not reached */
  961 }
  962 
  963 void
  964 mntscan(Mntwalk *mw, Proc *p)
  965 {
  966         Pgrp *pg;
  967         Mount *t;
  968         Mhead *f;
  969         int nxt, i;
  970         ulong last, bestmid;
  971 
  972         pg = p->pgrp;
  973         rlock(&pg->ns);
  974 
  975         nxt = 0;
  976         bestmid = ~0;
  977 
  978         last = 0;
  979         if(mw->mh)
  980                 last = mw->cm->mountid;
  981 
  982         for(i = 0; i < MNTHASH; i++) {
  983                 for(f = pg->mnthash[i]; f; f = f->hash) {
  984                         for(t = f->mount; t; t = t->next) {
  985                                 if(mw->mh == 0 ||
  986                                   (t->mountid > last && t->mountid < bestmid)) {
  987                                         mw->cm = t;
  988                                         mw->mh = f;
  989                                         bestmid = mw->cm->mountid;
  990                                         nxt = 1;
  991                                 }
  992                         }
  993                 }
  994         }
  995         if(nxt == 0)
  996                 mw->mh = 0;
  997 
  998         runlock(&pg->ns);
  999 }
 1000 
 1001 static long
 1002 procwrite(Chan *c, void *va, long n, vlong off)
 1003 {
 1004         int id, m;
 1005         Proc *p, *t, *et;
 1006         char *a, *arg, buf[ERRMAX];
 1007         ulong offset = off;
 1008 
 1009         a = va;
 1010         if(c->qid.type & QTDIR)
 1011                 error(Eisdir);
 1012 
 1013         p = proctab(SLOT(c->qid));
 1014 
 1015         /* Use the remembered noteid in the channel rather
 1016          * than the process pgrpid
 1017          */
 1018         if(QID(c->qid) == Qnotepg) {
 1019                 pgrpnote(NOTEID(c->pgrpid), va, n, NUser);
 1020                 return n;
 1021         }
 1022 
 1023         qlock(&p->debug);
 1024         if(waserror()){
 1025                 qunlock(&p->debug);
 1026                 nexterror();
 1027         }
 1028         if(p->pid != PID(c->qid))
 1029                 error(Eprocdied);
 1030 
 1031         switch(QID(c->qid)){
 1032         case Qargs:
 1033                 if(n == 0)
 1034                         error(Eshort);
 1035                 if(n >= ERRMAX)
 1036                         error(Etoobig);
 1037                 arg = malloc(n+1);
 1038                 if(arg == nil)
 1039                         error(Enomem);
 1040                 memmove(arg, va, n);
 1041                 m = n;
 1042                 if(arg[m-1] != 0)
 1043                         arg[m++] = 0;
 1044                 free(p->args);
 1045                 p->nargs = m;
 1046                 p->args = arg;
 1047                 p->setargs = 1;
 1048                 break;
 1049 
 1050         case Qmem:
 1051                 if(p->state != Stopped)
 1052                         error(Ebadctl);
 1053 
 1054                 n = procctlmemio(p, offset, n, va, 0);
 1055                 break;
 1056 
 1057         case Qregs:
 1058                 if(offset >= sizeof(Ureg))
 1059                         n = 0;
 1060                 else if(offset+n > sizeof(Ureg))
 1061                         n = sizeof(Ureg) - offset;
 1062                 if(p->dbgreg == 0)
 1063                         error(Enoreg);
 1064                 setregisters(p->dbgreg, (char*)(p->dbgreg)+offset, va, n);
 1065                 break;
 1066 
 1067         case Qfpregs:
 1068                 if(offset >= sizeof(FPsave))
 1069                         n = 0;
 1070                 else if(offset+n > sizeof(FPsave))
 1071                         n = sizeof(FPsave) - offset;
 1072                 memmove((uchar*)&p->fpsave+offset, va, n);
 1073                 break;
 1074 
 1075         case Qctl:
 1076                 procctlreq(p, va, n);
 1077                 break;
 1078 
 1079         case Qnote:
 1080                 if(p->kp)
 1081                         error(Eperm);
 1082                 if(n >= ERRMAX-1)
 1083                         error(Etoobig);
 1084                 memmove(buf, va, n);
 1085                 buf[n] = 0;
 1086                 if(!postnote(p, 0, buf, NUser))
 1087                         error("note not posted");
 1088                 break;
 1089         case Qnoteid:
 1090                 id = atoi(a);
 1091                 if(id == p->pid) {
 1092                         p->noteid = id;
 1093                         break;
 1094                 }
 1095                 t = proctab(0);
 1096                 for(et = t+conf.nproc; t < et; t++) {
 1097                         if(t->state == Dead)
 1098                                 continue;
 1099                         if(id == t->noteid) {
 1100                                 if(strcmp(p->user, t->user) != 0)
 1101                                         error(Eperm);
 1102                                 p->noteid = id;
 1103                                 break;
 1104                         }
 1105                 }
 1106                 if(p->noteid != id)
 1107                         error(Ebadarg);
 1108                 break;
 1109         default:
 1110                 pprint("unknown qid in procwrite\n");
 1111                 error(Egreg);
 1112         }
 1113         poperror();
 1114         qunlock(&p->debug);
 1115         return n;
 1116 }
 1117 
 1118 Dev procdevtab = {
 1119         'p',
 1120         "proc",
 1121 
 1122         devreset,
 1123         procinit,
 1124         devshutdown,
 1125         procattach,
 1126         procwalk,
 1127         procstat,
 1128         procopen,
 1129         devcreate,
 1130         procclose,
 1131         procread,
 1132         devbread,
 1133         procwrite,
 1134         devbwrite,
 1135         devremove,
 1136         procwstat,
 1137 };
 1138 
 1139 Chan*
 1140 proctext(Chan *c, Proc *p)
 1141 {
 1142         Chan *tc;
 1143         Image *i;
 1144         Segment *s;
 1145 
 1146         s = p->seg[TSEG];
 1147         if(s == 0)
 1148                 error(Enonexist);
 1149         if(p->state==Dead)
 1150                 error(Eprocdied);
 1151 
 1152         lock(s);
 1153         i = s->image;
 1154         if(i == 0) {
 1155                 unlock(s);
 1156                 error(Eprocdied);
 1157         }
 1158         unlock(s);
 1159 
 1160         lock(i);
 1161         if(waserror()) {
 1162                 unlock(i);
 1163                 nexterror();
 1164         }
 1165 
 1166         tc = i->c;
 1167         if(tc == 0)
 1168                 error(Eprocdied);
 1169 
 1170         if(incref(tc) == 1 || (tc->flag&COPEN) == 0 || tc->mode!=OREAD) {
 1171                 cclose(tc);
 1172                 error(Eprocdied);
 1173         }
 1174 
 1175         if(p->pid != PID(c->qid))
 1176                 error(Eprocdied);
 1177 
 1178         unlock(i);
 1179         poperror();
 1180 
 1181         return tc;
 1182 }
 1183 
 1184 void
 1185 procstopwait(Proc *p, int ctl)
 1186 {
 1187         int pid;
 1188 
 1189         if(p->pdbg)
 1190                 error(Einuse);
 1191         if(procstopped(p) || p->state == Broken)
 1192                 return;
 1193 
 1194         if(ctl != 0)
 1195                 p->procctl = ctl;
 1196         p->pdbg = up;
 1197         pid = p->pid;
 1198         qunlock(&p->debug);
 1199         up->psstate = "Stopwait";
 1200         if(waserror()) {
 1201                 p->pdbg = 0;
 1202                 qlock(&p->debug);
 1203                 nexterror();
 1204         }
 1205         sleep(&up->sleep, procstopped, p);
 1206         poperror();
 1207         qlock(&p->debug);
 1208         if(p->pid != pid)
 1209                 error(Eprocdied);
 1210 }
 1211 
 1212 static void
 1213 procctlcloseone(Proc *p, Fgrp *f, int fd)
 1214 {
 1215         Chan *c;
 1216 
 1217         c = f->fd[fd];
 1218         if(c == nil)
 1219                 return;
 1220         f->fd[fd] = nil;
 1221         unlock(f);
 1222         qunlock(&p->debug);
 1223         cclose(c);
 1224         qlock(&p->debug);
 1225         lock(f);
 1226 }
 1227 
 1228 void
 1229 procctlclosefiles(Proc *p, int all, int fd)
 1230 {
 1231         int i;
 1232         Fgrp *f;
 1233 
 1234         f = p->fgrp;
 1235         if(f == nil)
 1236                 error(Eprocdied);
 1237 
 1238         lock(f);
 1239         f->ref++;
 1240         if(all)
 1241                 for(i = 0; i < f->maxfd; i++)
 1242                         procctlcloseone(p, f, i);
 1243         else
 1244                 procctlcloseone(p, f, fd);
 1245         unlock(f);
 1246         closefgrp(f);
 1247 }
 1248 
 1249 static char *
 1250 parsetime(vlong *rt, char *s)
 1251 {
 1252         uvlong ticks;
 1253         ulong l;
 1254         char *e, *p;
 1255         static int p10[] = {100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1};
 1256 
 1257         if (s == nil)
 1258                 return("missing value");
 1259         ticks=strtoul(s, &e, 10);
 1260         if (*e == '.'){
 1261                 p = e+1;
 1262                 l = strtoul(p, &e, 10);
 1263                 if(e-p > nelem(p10))
 1264                         return "too many digits after decimal point";
 1265                 if(e-p == 0)
 1266                         return "ill-formed number";
 1267                 l *= p10[e-p-1];
 1268         }else
 1269                 l = 0;
 1270         if (*e == '\0' || strcmp(e, "s") == 0){
 1271                 ticks = 1000000000 * ticks + l;
 1272         }else if (strcmp(e, "ms") == 0){
 1273                 ticks = 1000000 * ticks + l/1000;
 1274         }else if (strcmp(e, "µs") == 0 || strcmp(e, "us") == 0){
 1275                 ticks = 1000 * ticks + l/1000000;
 1276         }else if (strcmp(e, "ns") != 0)
 1277                 return "unrecognized unit";
 1278         *rt = ticks;
 1279         return nil;
 1280 }
 1281 
 1282 void
 1283 procctlreq(Proc *p, char *va, int n)
 1284 {
 1285         Segment *s;
 1286         int npc, pri;
 1287         Cmdbuf *cb;
 1288         Cmdtab *ct;
 1289         vlong time;
 1290         char *e;
 1291         void (*pt)(Proc*, int, vlong);
 1292 
 1293         if(p->kp)       /* no ctl requests to kprocs */
 1294                 error(Eperm);
 1295 
 1296         cb = parsecmd(va, n);
 1297         if(waserror()){
 1298                 free(cb);
 1299                 nexterror();
 1300         }
 1301 
 1302         ct = lookupcmd(cb, proccmd, nelem(proccmd));
 1303 
 1304         switch(ct->index){
 1305         case CMclose:
 1306                 procctlclosefiles(p, 0, atoi(cb->f[1]));
 1307                 break;
 1308         case CMclosefiles:
 1309                 procctlclosefiles(p, 1, 0);
 1310                 break;
 1311         case CMhang:
 1312                 p->hang = 1;
 1313                 break;
 1314         case CMkill:
 1315                 switch(p->state) {
 1316                 case Broken:
 1317                         unbreak(p);
 1318                         break;
 1319                 case Stopped:
 1320                         p->procctl = Proc_exitme;
 1321                         postnote(p, 0, "sys: killed", NExit);
 1322                         ready(p);
 1323                         break;
 1324                 default:
 1325                         p->procctl = Proc_exitme;
 1326                         postnote(p, 0, "sys: killed", NExit);
 1327                 }
 1328                 break;
 1329         case CMnohang:
 1330                 p->hang = 0;
 1331                 break;
 1332         case CMnoswap:
 1333                 p->noswap = 1;
 1334                 break;
 1335         case CMpri:
 1336                 pri = atoi(cb->f[1]);
 1337                 if(pri > PriNormal && !iseve())
 1338                         error(Eperm);
 1339                 procpriority(p, pri, 0);
 1340                 break;
 1341         case CMfixedpri:
 1342                 pri = atoi(cb->f[1]);
 1343                 if(pri > PriNormal && !iseve())
 1344                         error(Eperm);
 1345                 procpriority(p, pri, 1);
 1346                 break;
 1347         case CMprivate:
 1348                 p->privatemem = 1;
 1349                 break;
 1350         case CMprofile:
 1351                 s = p->seg[TSEG];
 1352                 if(s == 0 || (s->type&SG_TYPE) != SG_TEXT)
 1353                         error(Ebadctl);
 1354                 if(s->profile != 0)
 1355                         free(s->profile);
 1356                 npc = (s->top-s->base)>>LRESPROF;
 1357                 s->profile = malloc(npc*sizeof(*s->profile));
 1358                 if(s->profile == 0)
 1359                         error(Enomem);
 1360                 break;
 1361         case CMstart:
 1362                 if(p->state != Stopped)
 1363                         error(Ebadctl);
 1364                 ready(p);
 1365                 break;
 1366         case CMstartstop:
 1367                 if(p->state != Stopped)
 1368                         error(Ebadctl);
 1369                 p->procctl = Proc_traceme;
 1370                 ready(p);
 1371                 procstopwait(p, Proc_traceme);
 1372                 break;
 1373         case CMstartsyscall:
 1374                 if(p->state != Stopped)
 1375                         error(Ebadctl);
 1376                 p->procctl = Proc_tracesyscall;
 1377                 ready(p);
 1378                 procstopwait(p, Proc_tracesyscall);
 1379                 break;
 1380         case CMstop:
 1381                 procstopwait(p, Proc_stopme);
 1382                 break;
 1383         case CMwaitstop:
 1384                 procstopwait(p, 0);
 1385                 break;
 1386         case CMwired:
 1387                 procwired(p, atoi(cb->f[1]));
 1388                 break;
 1389         case CMtrace:
 1390                 switch(cb->nf){
 1391                 case 1:
 1392                         p->trace ^= 1;
 1393                         break;
 1394                 case 2:
 1395                         p->trace = (atoi(cb->f[1]) != 0);
 1396                         break;
 1397                 default:
 1398                         error("args");
 1399                 }
 1400                 break;
 1401         /* real time */
 1402         case CMperiod:
 1403                 if(p->edf == nil)
 1404                         edfinit(p);
 1405                 if(e=parsetime(&time, cb->f[1]))        /* time in ns */
 1406                         error(e);
 1407                 edfstop(p);
 1408                 p->edf->T = time/1000;  /* Edf times are in µs */
 1409                 break;
 1410         case CMdeadline:
 1411                 if(p->edf == nil)
 1412                         edfinit(p);
 1413                 if(e=parsetime(&time, cb->f[1]))
 1414                         error(e);
 1415                 edfstop(p);
 1416                 p->edf->D = time/1000;
 1417                 break;
 1418         case CMcost:
 1419                 if(p->edf == nil)
 1420                         edfinit(p);
 1421                 if(e=parsetime(&time, cb->f[1]))
 1422                         error(e);
 1423                 edfstop(p);
 1424                 p->edf->C = time/1000;
 1425                 break;
 1426         case CMsporadic:
 1427                 if(p->edf == nil)
 1428                         edfinit(p);
 1429                 p->edf->flags |= Sporadic;
 1430                 break;
 1431         case CMdeadlinenotes:
 1432                 if(p->edf == nil)
 1433                         edfinit(p);
 1434                 p->edf->flags |= Sendnotes;
 1435                 break;
 1436         case CMadmit:
 1437                 if(p->edf == 0)
 1438                         error("edf params");
 1439                 if(e = edfadmit(p))
 1440                         error(e);
 1441                 break;
 1442         case CMextra:
 1443                 if(p->edf == nil)
 1444                         edfinit(p);
 1445                 p->edf->flags |= Extratime;
 1446                 break;
 1447         case CMexpel:
 1448                 if(p->edf)
 1449                         edfstop(p);
 1450                 break;
 1451         case CMevent:
 1452                 pt = proctrace;
 1453                 if(up->trace && pt)
 1454                         pt(up, SUser, 0);
 1455                 break;
 1456         }
 1457 
 1458         poperror();
 1459         free(cb);
 1460 }
 1461 
 1462 int
 1463 procstopped(void *a)
 1464 {
 1465         Proc *p = a;
 1466         return p->state == Stopped;
 1467 }
 1468 
 1469 int
 1470 procctlmemio(Proc *p, ulong offset, int n, void *va, int read)
 1471 {
 1472         KMap *k;
 1473         Pte *pte;
 1474         Page *pg;
 1475         Segment *s;
 1476         ulong soff, l;
 1477         char *a = va, *b;
 1478 
 1479         for(;;) {
 1480                 s = seg(p, offset, 1);
 1481                 if(s == 0)
 1482                         error(Ebadarg);
 1483 
 1484                 if(offset+n >= s->top)
 1485                         n = s->top-offset;
 1486 
 1487                 if(!read && (s->type&SG_TYPE) == SG_TEXT)
 1488                         s = txt2data(p, s);
 1489 
 1490                 s->steal++;
 1491                 soff = offset-s->base;
 1492                 if(waserror()) {
 1493                         s->steal--;
 1494                         nexterror();
 1495                 }
 1496                 if(fixfault(s, offset, read, 0) == 0)
 1497                         break;
 1498                 poperror();
 1499                 s->steal--;
 1500         }
 1501         poperror();
 1502         pte = s->map[soff/PTEMAPMEM];
 1503         if(pte == 0)
 1504                 panic("procctlmemio");
 1505         pg = pte->pages[(soff&(PTEMAPMEM-1))/BY2PG];
 1506         if(pagedout(pg))
 1507                 panic("procctlmemio1");
 1508 
 1509         l = BY2PG - (offset&(BY2PG-1));
 1510         if(n > l)
 1511                 n = l;
 1512 
 1513         k = kmap(pg);
 1514         if(waserror()) {
 1515                 s->steal--;
 1516                 kunmap(k);
 1517                 nexterror();
 1518         }
 1519         b = (char*)VA(k);
 1520         b += offset&(BY2PG-1);
 1521         if(read == 1)
 1522                 memmove(a, b, n);       /* This can fault */
 1523         else
 1524                 memmove(b, a, n);
 1525         kunmap(k);
 1526         poperror();
 1527 
 1528         /* Ensure the process sees text page changes */
 1529         if(s->flushme)
 1530                 memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
 1531 
 1532         s->steal--;
 1533 
 1534         if(read == 0)
 1535                 p->newtlb = 1;
 1536 
 1537         return n;
 1538 }
 1539 
 1540 Segment*
 1541 txt2data(Proc *p, Segment *s)
 1542 {
 1543         int i;
 1544         Segment *ps;
 1545 
 1546         ps = newseg(SG_DATA, s->base, s->size);
 1547         ps->image = s->image;
 1548         incref(ps->image);
 1549         ps->fstart = s->fstart;
 1550         ps->flen = s->flen;
 1551         ps->flushme = 1;
 1552 
 1553         qlock(&p->seglock);
 1554         for(i = 0; i < NSEG; i++)
 1555                 if(p->seg[i] == s)
 1556                         break;
 1557         if(i == NSEG)
 1558                 panic("segment gone");
 1559 
 1560         qunlock(&s->lk);
 1561         putseg(s);
 1562         qlock(&ps->lk);
 1563         p->seg[i] = ps;
 1564         qunlock(&p->seglock);
 1565 
 1566         return ps;
 1567 }
 1568 
 1569 Segment*
 1570 data2txt(Segment *s)
 1571 {
 1572         Segment *ps;
 1573 
 1574         ps = newseg(SG_TEXT, s->base, s->size);
 1575         ps->image = s->image;
 1576         incref(ps->image);
 1577         ps->fstart = s->fstart;
 1578         ps->flen = s->flen;
 1579         ps->flushme = 1;
 1580 
 1581         return ps;
 1582 }

Cache object: d064c5b234742f16b8368fa1daf49300


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.