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