1 #include "dat.h" 2 #include "fns.h" 3 #include "error.h" 4 #include <interp.h> 5 #include <isa.h> 6 #include "runt.h" 7 8 /* 9 * Enable the heap device for environments that allow debugging => 10 * Must be 1 for a production environment. 11 */ 12 int SECURE = 0; 13 14 enum 15 { 16 Qdir, 17 Qctl, 18 Qdbgctl, 19 Qheap, 20 Qns, 21 Qnsgrp, 22 Qpgrp, 23 Qstack, 24 Qstatus, 25 Qtext, 26 Qwait, 27 Qfd, 28 Qexception, 29 }; 30 31 /* 32 * must be in same order as enum 33 */ 34 Dirtab progdir[] = 35 { 36 "ctl", {Qctl}, 0, 0200, 37 "dbgctl", {Qdbgctl}, 0, 0600, 38 "heap", {Qheap}, 0, 0600, 39 "ns", {Qns}, 0, 0400, 40 "nsgrp", {Qnsgrp}, 0, 0444, 41 "pgrp", {Qpgrp}, 0, 0444, 42 "stack", {Qstack}, 0, 0400, 43 "status", {Qstatus}, 0, 0444, 44 "text", {Qtext}, 0, 0000, 45 "wait", {Qwait}, 0, 0400, 46 "fd", {Qfd}, 0, 0400, 47 "exception", {Qexception}, 0, 0400, 48 }; 49 50 enum 51 { 52 CMkill, 53 CMkillgrp, 54 CMrestricted, 55 CMexceptions, 56 CMprivate 57 }; 58 59 static 60 Cmdtab progcmd[] = { 61 CMkill, "kill", 1, 62 CMkillgrp, "killgrp", 1, 63 CMrestricted, "restricted", 1, 64 CMexceptions, "exceptions", 2, 65 CMprivate, "private", 1, 66 }; 67 68 enum 69 { 70 CDstep, 71 CDtoret, 72 CDcont, 73 CDstart, 74 CDstop, 75 CDunstop, 76 CDmaim, 77 CDbpt 78 }; 79 80 static 81 Cmdtab progdbgcmd[] = { 82 CDstep, "step", 0, /* known below to be first, to cope with stepN */ 83 CDtoret, "toret", 1, 84 CDcont, "cont", 1, 85 CDstart, "start", 1, 86 CDstop, "stop", 1, 87 CDunstop, "unstop", 1, 88 CDmaim, "maim", 1, 89 CDbpt, "bpt", 4, 90 }; 91 92 typedef struct Heapqry Heapqry; 93 struct Heapqry 94 { 95 char fmt; 96 ulong addr; 97 ulong module; 98 int count; 99 }; 100 101 typedef struct Bpt Bpt; 102 103 struct Bpt 104 { 105 Bpt *next; 106 int pc; 107 char *file; 108 char path[1]; 109 }; 110 111 typedef struct Progctl Progctl; 112 struct Progctl 113 { 114 Rendez r; 115 int ref; 116 Proc *debugger; /* waiting for dbgxec */ 117 char *msg; /* reply from dbgxec */ 118 int step; /* instructions to try */ 119 int stop; /* stop running the program */ 120 Bpt* bpts; /* active breakpoints */ 121 Queue* q; /* status queue */ 122 }; 123 124 #define QSHIFT 4 /* location in qid of pid */ 125 #define QID(q) (((ulong)(q).path&0x0000000F)>>0) 126 #define QPID(pid) (((pid)<<QSHIFT)) 127 #define PID(q) ((q).vers) 128 #define PATH(q) ((ulong)(q).path&~((1<<QSHIFT)-1)) 129 130 static char *progstate[] = /* must correspond to include/interp.h */ 131 { 132 "alt", /* blocked in alt instruction */ 133 "send", /* waiting to send */ 134 "recv", /* waiting to recv */ 135 "debug", /* debugged */ 136 "ready", /* ready to be scheduled */ 137 "release", /* interpreter released */ 138 "exiting", /* exit because of kill or error */ 139 "broken", /* thread crashed */ 140 }; 141 142 static void dbgstep(Progctl*, Prog*, int); 143 static void dbgstart(Prog*); 144 static void freebpts(Bpt*); 145 static Bpt* delbpt(Bpt*, char*, int); 146 static Bpt* setbpt(Bpt*, char*, int); 147 static void mntscan(Mntwalk*, Pgrp*); 148 extern Type *Trdchan; 149 extern Type *Twrchan; 150 extern Module* modules; 151 static char Emisalign[] = "misaligned address"; 152 153 static int 154 proggen(Chan *c, char *name, Dirtab *tab, int ntab, int s, Dir *dp) 155 { 156 Qid qid; 157 Prog *p; 158 char *e; 159 Osenv *o; 160 ulong pid, path, perm, len; 161 162 USED(ntab); 163 164 if(s == DEVDOTDOT){ 165 mkqid(&qid, Qdir, 0, QTDIR); 166 devdir(c, qid, "#p", 0, eve, DMDIR|0555, dp); 167 return 1; 168 } 169 170 if((ulong)c->qid.path == Qdir) { 171 if(name != nil){ 172 /* ignore s and use name to find pid */ 173 pid = strtoul(name, &e, 0); 174 if(pid == 0 || *e != '\0') 175 return -1; 176 acquire(); 177 p = progpid(pid); 178 if(p == nil){ 179 release(); 180 return -1; 181 } 182 }else{ 183 acquire(); 184 p = progn(s); 185 if(p == nil) { 186 release(); 187 return -1; 188 } 189 pid = p->pid; 190 } 191 o = p->osenv; 192 sprint(up->genbuf, "%lud", pid); 193 if(name != nil && strcmp(name, up->genbuf) != 0){ 194 release(); 195 return -1; 196 } 197 mkqid(&qid, pid<<QSHIFT, pid, QTDIR); 198 devdir(c, qid, up->genbuf, 0, o->user, DMDIR|0555, dp); 199 release(); 200 return 1; 201 } 202 203 if(s >= nelem(progdir)) 204 return -1; 205 tab = &progdir[s]; 206 path = PATH(c->qid); 207 208 acquire(); 209 p = progpid(PID(c->qid)); 210 if(p == nil) { 211 release(); 212 return -1; 213 } 214 215 o = p->osenv; 216 217 perm = tab->perm; 218 if((perm & 7) == 0) 219 perm = (perm|(perm>>3)|(perm>>6)) & o->pgrp->progmode; 220 221 len = tab->length; 222 mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE); 223 devdir(c, qid, tab->name, len, o->user, perm, dp); 224 release(); 225 return 1; 226 } 227 228 static Chan* 229 progattach(char *spec) 230 { 231 return devattach('p', spec); 232 } 233 234 static Walkqid* 235 progwalk(Chan *c, Chan *nc, char **name, int nname) 236 { 237 return devwalk(c, nc, name, nname, 0, 0, proggen); 238 } 239 240 static int 241 progstat(Chan *c, uchar *db, int n) 242 { 243 return devstat(c, db, n, 0, 0, proggen); 244 } 245 246 static Chan* 247 progopen(Chan *c, int omode) 248 { 249 Prog *p; 250 Osenv *o; 251 Progctl *ctl; 252 int perm; 253 254 if(c->qid.type & QTDIR) 255 return devopen(c, omode, 0, 0, proggen); 256 257 acquire(); 258 if (waserror()) { 259 release(); 260 nexterror(); 261 } 262 p = progpid(PID(c->qid)); 263 if(p == nil) 264 error(Ethread); 265 o = p->osenv; 266 perm = progdir[QID(c->qid)-1].perm; 267 if((perm & 7) == 0) 268 perm = (perm|(perm>>3)|(perm>>6)) & o->pgrp->progmode; 269 devpermcheck(o->user, perm, omode); 270 omode = openmode(omode); 271 272 switch(QID(c->qid)){ 273 default: 274 error(Egreg); 275 case Qnsgrp: 276 case Qpgrp: 277 case Qtext: 278 case Qstatus: 279 case Qstack: 280 case Qctl: 281 case Qfd: 282 case Qexception: 283 break; 284 case Qwait: 285 c->aux = qopen(1024, Qmsg, nil, nil); 286 if(c->aux == nil) 287 error(Enomem); 288 o->childq = c->aux; 289 break; 290 case Qns: 291 c->aux = malloc(sizeof(Mntwalk)); 292 if(c->aux == nil) 293 error(Enomem); 294 break; 295 case Qheap: 296 if(SECURE || o->pgrp->privatemem || omode != ORDWR) 297 error(Eperm); 298 c->aux = malloc(sizeof(Heapqry)); 299 if(c->aux == nil) 300 error(Enomem); 301 break; 302 case Qdbgctl: 303 if(SECURE || o->pgrp->privatemem || omode != ORDWR) 304 error(Eperm); 305 ctl = malloc(sizeof(Progctl)); 306 if(ctl == nil) 307 error(Enomem); 308 ctl->q = qopen(1024, Qmsg, nil, nil); 309 if(ctl->q == nil) { 310 free(ctl); 311 error(Enomem); 312 } 313 ctl->bpts = nil; 314 ctl->ref = 1; 315 c->aux = ctl; 316 break; 317 } 318 if(p->state != Pexiting) 319 c->qid.vers = p->pid; 320 321 poperror(); 322 release(); 323 c->offset = 0; 324 c->mode = omode; 325 c->flag |= COPEN; 326 return c; 327 } 328 329 static int 330 progwstat(Chan *c, uchar *db, int n) 331 { 332 Dir d; 333 Prog *p; 334 char *u; 335 Osenv *o; 336 337 if(c->qid.type&QTDIR) 338 error(Eperm); 339 acquire(); 340 p = progpid(PID(c->qid)); 341 if(p == nil) { 342 release(); 343 error(Ethread); 344 } 345 346 u = up->env->user; 347 o = p->osenv; 348 if(strcmp(u, o->user) != 0 && strcmp(u, eve) != 0) { 349 release(); 350 error(Eperm); 351 } 352 353 n = convM2D(db, n, &d, nil); 354 if(n == 0){ 355 release(); 356 error(Eshortstat); 357 } 358 if(d.mode != ~0UL) 359 o->pgrp->progmode = d.mode&0777; 360 release(); 361 return n; 362 } 363 364 static void 365 closedbgctl(Progctl *ctl, Prog *p) 366 { 367 Osenv *o; 368 369 if(ctl->ref-- > 1) 370 return; 371 freebpts(ctl->bpts); 372 if(p != nil){ 373 o = p->osenv; 374 if(o->debug == ctl){ 375 o->debug = nil; 376 p->xec = xec; 377 } 378 } 379 qfree(ctl->q); 380 free(ctl); 381 } 382 383 static void 384 progclose(Chan *c) 385 { 386 int i; 387 Prog *f; 388 Osenv *o; 389 Progctl *ctl; 390 391 switch(QID(c->qid)) { 392 case Qns: 393 case Qheap: 394 free(c->aux); 395 break; 396 case Qdbgctl: 397 if((c->flag & COPEN) == 0) 398 return; 399 ctl = c->aux; 400 acquire(); 401 closedbgctl(ctl, progpid(PID(c->qid))); 402 release(); 403 break; 404 case Qwait: 405 acquire(); 406 i = 0; 407 for(;;) { 408 f = progn(i++); 409 if(f == nil) 410 break; 411 o = f->osenv; 412 if(o->waitq == c->aux) 413 o->waitq = nil; 414 if(o->childq == c->aux) 415 o->childq = nil; 416 } 417 release(); 418 qfree(c->aux); 419 } 420 } 421 422 static int 423 progsize(Prog *p) 424 { 425 int size; 426 Frame *f; 427 uchar *fp; 428 Modlink *m; 429 430 m = p->R.M; 431 size = 0; 432 if(m->MP != H) 433 size += hmsize(D2H(m->MP)); 434 if(m->prog != nil) 435 size += msize(m->prog); 436 437 fp = p->R.FP; 438 while(fp != nil) { 439 f = (Frame*)fp; 440 fp = f->fp; 441 if(f->mr != nil) { 442 if(f->mr->MP != H) 443 size += hmsize(D2H(f->mr->MP)); 444 if(f->mr->prog != nil) 445 size += msize(f->mr->prog); 446 } 447 if(f->t == nil) 448 size += msize(SEXTYPE(f)); 449 } 450 return size/1024; 451 } 452 453 static long 454 progoffset(long offset, char *va, int *np) 455 { 456 if(offset > 0) { 457 offset -= *np; 458 if(offset < 0) { 459 memmove(va, va+*np+offset, -offset); 460 *np = -offset; 461 } 462 else 463 *np = 0; 464 } 465 return offset; 466 } 467 468 static int 469 progqidwidth(Chan *c) 470 { 471 char buf[32]; 472 473 return sprint(buf, "%lud", c->qid.vers); 474 } 475 476 int 477 progfdprint(Chan *c, int fd, int w, char *s, int ns) 478 { 479 int n; 480 481 if(w == 0) 482 w = progqidwidth(c); 483 n = snprint(s, ns, "%3d %.2s %C %4ld (%.16llux %*lud %.2ux) %5ld %8lld %s\n", 484 fd, 485 &"r w rw"[(c->mode&3)<<1], 486 devtab[c->type]->dc, c->dev, 487 c->qid.path, w, c->qid.vers, c->qid.type, 488 c->iounit, c->offset, c->name->s); 489 return n; 490 } 491 492 static int 493 progfds(Osenv *o, char *va, int count, long offset) 494 { 495 Fgrp *f; 496 Chan *c; 497 int n, i, w, ww; 498 499 f = o->fgrp; /* f is not locked because we've acquired */ 500 n = readstr(0, va, count, o->pgrp->dot->name->s); 501 n += snprint(va+n, count-n, "\n"); 502 offset = progoffset(offset, va, &n); 503 /* compute width of qid.path */ 504 w = 0; 505 for(i = 0; i <= f->maxfd; i++) { 506 c = f->fd[i]; 507 if(c == nil) 508 continue; 509 ww = progqidwidth(c); 510 if(ww > w) 511 w = ww; 512 } 513 for(i = 0; i <= f->maxfd; i++) { 514 c = f->fd[i]; 515 if(c == nil) 516 continue; 517 n += progfdprint(c, i, w, va+n, count-n); 518 offset = progoffset(offset, va, &n); 519 } 520 return n; 521 } 522 523 Inst * 524 pc2dispc(Inst *pc, Module *mod) 525 { 526 ulong l, u, m, v; 527 ulong *tab = mod->pctab; 528 529 v = (ulong)pc - (ulong)mod->prog; 530 l = 0; 531 u = mod->nprog-1; 532 while(l < u){ 533 m = (l+u+1)/2; 534 if(tab[m] < v) 535 l = m; 536 else if(tab[m] > v) 537 u = m-1; 538 else 539 l = u = m; 540 } 541 if(l == u && tab[u] <= v && u != mod->nprog-1 && tab[u+1] > v) 542 return &mod->prog[u]; 543 return 0; 544 } 545 546 static int 547 progstack(REG *reg, int state, char *va, int count, long offset) 548 { 549 int n; 550 Frame *f; 551 Inst *pc; 552 uchar *fp; 553 Modlink *m; 554 555 n = 0; 556 m = reg->M; 557 fp = reg->FP; 558 pc = reg->PC; 559 560 /* 561 * all states other than debug and ready block, 562 * but interp has already advanced the PC 563 */ 564 if(!m->compiled && state != Pready && state != Pdebug && pc > m->prog) 565 pc--; 566 if(m->compiled && m->m->pctab != nil) 567 pc = pc2dispc(pc, m->m); 568 569 while(fp != nil) { 570 f = (Frame*)fp; 571 n += snprint(va+n, count-n, "%.8lux %.8lux %.8lux %.8lux %d %s\n", 572 (ulong)f, /* FP */ 573 (ulong)(pc - m->prog), /* PC in dis instructions */ 574 (ulong)m->MP, /* MP */ 575 (ulong)m->prog, /* Code for module */ 576 m->compiled && m->m->pctab == nil, /* True if native assembler: fool stack utility for now */ 577 m->m->path); /* File system path */ 578 579 if(offset > 0) { 580 offset -= n; 581 if(offset < 0) { 582 memmove(va, va+n+offset, -offset); 583 n = -offset; 584 } 585 else 586 n = 0; 587 } 588 589 pc = f->lr; 590 fp = f->fp; 591 if(f->mr != nil) 592 m = f->mr; 593 if(!m->compiled) 594 pc--; 595 else if(m->m->pctab != nil) 596 pc = pc2dispc(pc, m->m)-1; 597 } 598 return n; 599 } 600 601 static int 602 calldepth(REG *reg) 603 { 604 int n; 605 uchar *fp; 606 607 n = 0; 608 for(fp = reg->FP; fp != nil; fp = ((Frame*)fp)->fp) 609 n++; 610 return n; 611 } 612 613 static int 614 progheap(Heapqry *hq, char *va, int count, ulong offset) 615 { 616 WORD *w; 617 void *p; 618 List *hd; 619 Array *a; 620 char *fmt, *str; 621 Module *m; 622 Modlink *ml; 623 Channel *c; 624 ulong addr; 625 String *ss; 626 union { REAL r; LONG l; WORD w[2]; } rock; 627 int i, s, n, len, signed_off; 628 Type *t; 629 630 n = 0; 631 s = 0; 632 signed_off = offset; 633 addr = hq->addr; 634 for(i = 0; i < hq->count; i++) { 635 switch(hq->fmt) { 636 case 'W': 637 if(addr & 3) 638 return -1; 639 n += snprint(va+n, count-n, "%d\n", *(WORD*)addr); 640 s = sizeof(WORD); 641 break; 642 case 'B': 643 n += snprint(va+n, count-n, "%d\n", *(BYTE*)addr); 644 s = sizeof(BYTE); 645 break; 646 case 'V': 647 if(addr & 3) 648 return -1; 649 w = (WORD*)addr; 650 rock.w[0] = w[0]; 651 rock.w[1] = w[1]; 652 n += snprint(va+n, count-n, "%lld\n", rock.l); 653 s = sizeof(LONG); 654 break; 655 case 'R': 656 if(addr & 3) 657 return -1; 658 w = (WORD*)addr; 659 rock.w[0] = w[0]; 660 rock.w[1] = w[1]; 661 n += snprint(va+n, count-n, "%g\n", rock.r); 662 s = sizeof(REAL); 663 break; 664 case 'I': 665 if(addr & 3) 666 return -1; 667 for(m = modules; m != nil; m = m->link) 668 if(m == (Module*)hq->module) 669 break; 670 if(m == nil) 671 error(Ebadctl); 672 addr = (ulong)(m->prog+addr); 673 n += snprint(va+n, count-n, "%D\n", (Inst*)addr); 674 s = sizeof(Inst); 675 break; 676 case 'P': 677 if(addr & 3) 678 return -1; 679 p = *(void**)addr; 680 fmt = "nil\n"; 681 if(p != H) 682 fmt = "%lux\n"; 683 n += snprint(va+n, count-n, fmt, p); 684 s = sizeof(WORD); 685 break; 686 case 'L': 687 if(addr & 3) 688 return -1; 689 hd = *(List**)addr; 690 if(hd == H || D2H(hd)->t != &Tlist) 691 return -1; 692 n += snprint(va+n, count-n, "%lux.%lux\n", (ulong)&hd->tail, (ulong)hd->data); 693 s = sizeof(WORD); 694 break; 695 case 'A': 696 if(addr & 3) 697 return -1; 698 a = *(Array**)addr; 699 if(a == H) 700 n += snprint(va+n, count-n, "nil\n"); 701 else { 702 if(D2H(a)->t != &Tarray) 703 return -1; 704 n += snprint(va+n, count-n, "%d.%lux\n", a->len, (ulong)a->data); 705 } 706 s = sizeof(WORD); 707 break; 708 case 'C': 709 if(addr & 3) 710 return -1; 711 ss = *(String**)addr; 712 if(ss == H) 713 ss = &snil; 714 else 715 if(D2H(ss)->t != &Tstring) 716 return -1; 717 n += snprint(va+n, count-n, "%d.", abs(ss->len)); 718 str = string2c(ss); 719 len = strlen(str); 720 if(count-n < len) 721 len = count-n; 722 if(len > 0) { 723 memmove(va+n, str, len); 724 n += len; 725 } 726 break; 727 case 'M': 728 if(addr & 3) 729 return -1; 730 ml = *(Modlink**)addr; 731 fmt = ml == H ? "nil\n" : "%lux\n"; 732 n += snprint(va+n, count-n, fmt, ml->MP); 733 s = sizeof(WORD); 734 break; 735 case 'c': 736 if(addr & 3) 737 return -1; 738 c = *(Channel**)addr; 739 if(c == H) 740 n += snprint(va+n, count-n, "nil\n"); 741 else{ 742 t = D2H(c)->t; 743 if(t != &Tchannel && t != Trdchan && t != Twrchan) 744 return -1; 745 if(c->buf == H) 746 n += snprint(va+n, count-n, "0.%lux\n", (ulong)c); 747 else 748 n += snprint(va+n, count-n, "%d.%lux.%d.%d\n", c->buf->len, (ulong)c->buf->data, c->front, c->size); 749 } 750 break; 751 752 } 753 addr += s; 754 if(signed_off > 0) { 755 signed_off -= n; 756 if(signed_off < 0) { 757 memmove(va, va+n+signed_off, -signed_off); 758 n = -signed_off; 759 } 760 else 761 n = 0; 762 } 763 } 764 return n; 765 } 766 767 WORD 768 modstatus(REG *r, char *ptr, int len) 769 { 770 Inst *PC; 771 Frame *f; 772 773 if(r->M->m->name[0] == '$') { 774 f = (Frame*)r->FP; 775 snprint(ptr, len, "%s[%s]", f->mr->m->name, r->M->m->name); 776 if(f->mr->compiled) 777 return (WORD)f->lr; 778 return f->lr - f->mr->prog; 779 } 780 memmove(ptr, r->M->m->name, len); 781 if(r->M->compiled) 782 return (WORD)r->PC; 783 PC = r->PC; 784 /* should really check for blocked states */ 785 if(PC > r->M->prog) 786 PC--; 787 return PC - r->M->prog; 788 } 789 790 static void 791 int2flag(int flag, char *s) 792 { 793 if(flag == 0){ 794 *s = '\0'; 795 return; 796 } 797 *s++ = '-'; 798 if(flag & MAFTER) 799 *s++ = 'a'; 800 if(flag & MBEFORE) 801 *s++ = 'b'; 802 if(flag & MCREATE) 803 *s++ = 'c'; 804 if(flag & MCACHE) 805 *s++ = 'C'; 806 *s = '\0'; 807 } 808 809 static char* 810 progtime(ulong msec, char *buf, char *ebuf) 811 { 812 int tenths, sec; 813 814 tenths = msec/100; 815 sec = tenths/10; 816 seprint(buf, ebuf, "%4d:%2.2d.%d", sec/60, sec%60, tenths%10); 817 return buf; 818 } 819 820 static long 821 progread(Chan *c, void *va, long n, vlong offset) 822 { 823 int i; 824 Prog *p; 825 Osenv *o; 826 Mntwalk *mw; 827 ulong grpid; 828 char *a = va; 829 Progctl *ctl; 830 char mbuf[64], timebuf[12]; 831 char flag[10]; 832 833 if(c->qid.type & QTDIR) 834 return devdirread(c, a, n, 0, 0, proggen); 835 836 switch(QID(c->qid)){ 837 case Qdbgctl: 838 ctl = c->aux; 839 return qread(ctl->q, va, n); 840 case Qstatus: 841 acquire(); 842 p = progpid(PID(c->qid)); 843 if(p == nil || p->state == Pexiting || p->R.M == H) { 844 release(); 845 snprint(up->genbuf, sizeof(up->genbuf), "%8lud %8d %10s %s %10s %5dK %s", 846 PID(c->qid), 847 0, 848 eve, 849 progtime(0, timebuf, timebuf+sizeof(timebuf)), 850 progstate[Pexiting], 851 0, 852 "[$Sys]"); 853 return readstr(offset, va, n, up->genbuf); 854 } 855 modstatus(&p->R, mbuf, sizeof(mbuf)); 856 o = p->osenv; 857 snprint(up->genbuf, sizeof(up->genbuf), "%8d %8d %10s %s %10s %5dK %s", 858 p->pid, 859 p->group!=nil? p->group->id: 0, 860 o->user, 861 progtime(p->ticks, timebuf, timebuf+sizeof(timebuf)), 862 progstate[p->state], 863 progsize(p), 864 mbuf); 865 release(); 866 return readstr(offset, va, n, up->genbuf); 867 case Qwait: 868 return qread(c->aux, va, n); 869 case Qns: 870 acquire(); 871 if(waserror()){ 872 release(); 873 nexterror(); 874 } 875 p = progpid(PID(c->qid)); 876 if(p == nil) 877 error(Ethread); 878 mw = c->aux; 879 if(mw->cddone){ 880 poperror(); 881 release(); 882 return 0; 883 } 884 o = p->osenv; 885 mntscan(mw, o->pgrp); 886 if(mw->mh == 0) { 887 mw->cddone = 1; 888 i = snprint(a, n, "cd %s\n", o->pgrp->dot->name->s); 889 poperror(); 890 release(); 891 return i; 892 } 893 int2flag(mw->cm->mflag, flag); 894 if(strcmp(mw->cm->to->name->s, "#M") == 0){ 895 i = snprint(a, n, "mount %s %s %s %s\n", flag, 896 mw->cm->to->mchan->name->s, 897 mw->mh->from->name->s, mw->cm->spec? mw->cm->spec : ""); 898 }else 899 i = snprint(a, n, "bind %s %s %s\n", flag, 900 mw->cm->to->name->s, mw->mh->from->name->s); 901 poperror(); 902 release(); 903 return i; 904 case Qnsgrp: 905 acquire(); 906 p = progpid(PID(c->qid)); 907 if(p == nil) { 908 release(); 909 error(Ethread); 910 } 911 grpid = ((Osenv *)p->osenv)->pgrp->pgrpid; 912 release(); 913 return readnum(offset, va, n, grpid, NUMSIZE); 914 case Qpgrp: 915 acquire(); 916 p = progpid(PID(c->qid)); 917 if(p == nil) { 918 release(); 919 error(Ethread); 920 } 921 grpid = p->group!=nil? p->group->id: 0; 922 release(); 923 return readnum(offset, va, n, grpid, NUMSIZE); 924 case Qstack: 925 acquire(); 926 p = progpid(PID(c->qid)); 927 if(p == nil || p->state == Pexiting) { 928 release(); 929 error(Ethread); 930 } 931 if(p->state == Pready) { 932 release(); 933 error(Estopped); 934 } 935 n = progstack(&p->R, p->state, va, n, offset); 936 release(); 937 return n; 938 case Qheap: 939 acquire(); 940 if(waserror()){ 941 release(); 942 nexterror(); 943 } 944 n = progheap(c->aux, va, n, offset); 945 if(n == -1) 946 error(Emisalign); 947 poperror(); 948 release(); 949 return n; 950 case Qfd: 951 acquire(); 952 if(waserror()) { 953 release(); 954 nexterror(); 955 } 956 p = progpid(PID(c->qid)); 957 if(p == nil) 958 error(Ethread); 959 o = p->osenv; 960 n = progfds(o, va, n, offset); 961 poperror(); 962 release(); 963 return n; 964 case Qexception: 965 acquire(); 966 p = progpid(PID(c->qid)); 967 if(p == nil) { 968 release(); 969 error(Ethread); 970 } 971 if(p->exstr == nil) 972 up->genbuf[0] = 0; 973 else 974 snprint(up->genbuf, sizeof(up->genbuf), p->exstr); 975 release(); 976 return readstr(offset, va, n, up->genbuf); 977 } 978 error(Egreg); 979 return 0; 980 } 981 982 static void 983 mntscan(Mntwalk *mw, Pgrp *pg) 984 { 985 Mount *t; 986 Mhead *f; 987 int nxt, i; 988 ulong last, bestmid; 989 990 rlock(&pg->ns); 991 992 nxt = 0; 993 bestmid = ~0; 994 995 last = 0; 996 if(mw->mh) 997 last = mw->cm->mountid; 998 999 for(i = 0; i < MNTHASH; i++) { 1000 for(f = pg->mnthash[i]; f; f = f->hash) { 1001 for(t = f->mount; t; t = t->next) { 1002 if(mw->mh == 0 || 1003 (t->mountid > last && t->mountid < bestmid)) { 1004 mw->cm = t; 1005 mw->mh = f; 1006 bestmid = mw->cm->mountid; 1007 nxt = 1; 1008 } 1009 } 1010 } 1011 } 1012 if(nxt == 0) 1013 mw->mh = 0; 1014 1015 runlock(&pg->ns); 1016 } 1017 1018 static long 1019 progwrite(Chan *c, void *va, long n, vlong offset) 1020 { 1021 Prog *p, *f; 1022 Heapqry *hq; 1023 char buf[512]; 1024 Progctl *ctl; 1025 char *b; 1026 int i, pc; 1027 Cmdbuf *cb; 1028 Cmdtab *ct; 1029 Osenv *o; 1030 1031 USED(offset); 1032 USED(va); 1033 1034 if(c->qid.type & QTDIR) 1035 error(Eisdir); 1036 1037 acquire(); 1038 if(waserror()) { 1039 release(); 1040 nexterror(); 1041 } 1042 p = progpid(PID(c->qid)); 1043 if(p == nil) 1044 error(Ethread); 1045 1046 switch(QID(c->qid)){ 1047 case Qctl: 1048 cb = parsecmd(va, n); 1049 if(waserror()){ 1050 free(cb); 1051 nexterror(); 1052 } 1053 ct = lookupcmd(cb, progcmd, nelem(progcmd)); 1054 switch(ct->index){ 1055 case CMkillgrp: 1056 killgrp(p, "killed"); 1057 break; 1058 case CMkill: 1059 killprog(p, "killed"); 1060 break; 1061 case CMrestricted: 1062 p->flags |= Prestrict; 1063 break; 1064 case CMexceptions: 1065 if(p->group->id != p->pid) 1066 error(Eperm); 1067 if(strcmp(cb->f[1], "propagate") == 0) 1068 p->flags |= Ppropagate; 1069 else if(strcmp(cb->f[1], "notifyleader") == 0) 1070 p->flags |= Pnotifyleader; 1071 else 1072 error(Ebadctl); 1073 break; 1074 case CMprivate: 1075 o = p->osenv; 1076 o->pgrp->privatemem = 1; 1077 break; 1078 } 1079 poperror(); 1080 free(cb); 1081 break; 1082 case Qdbgctl: 1083 cb = parsecmd(va, n); 1084 if(waserror()){ 1085 free(cb); 1086 nexterror(); 1087 } 1088 if(cb->nf == 1 && strncmp(cb->f[0], "step", 4) == 0) 1089 ct = progdbgcmd; 1090 else 1091 ct = lookupcmd(cb, progdbgcmd, nelem(progdbgcmd)); 1092 switch(ct->index){ 1093 case CDstep: 1094 if(cb->nf == 1) 1095 i = strtoul(cb->f[0]+4, nil, 0); 1096 else 1097 i = strtoul(cb->f[1], nil, 0); 1098 dbgstep(c->aux, p, i); 1099 break; 1100 case CDtoret: 1101 f = currun(); 1102 i = calldepth(&p->R); 1103 while(f->kill == nil) { 1104 dbgstep(c->aux, p, 1024); 1105 if(i > calldepth(&p->R)) 1106 break; 1107 } 1108 break; 1109 case CDcont: 1110 f = currun(); 1111 while(f->kill == nil) 1112 dbgstep(c->aux, p, 1024); 1113 break; 1114 case CDstart: 1115 dbgstart(p); 1116 break; 1117 case CDstop: 1118 ctl = c->aux; 1119 ctl->stop = 1; 1120 break; 1121 case CDunstop: 1122 ctl = c->aux; 1123 ctl->stop = 0; 1124 break; 1125 case CDbpt: 1126 pc = strtoul(cb->f[3], nil, 10); 1127 ctl = c->aux; 1128 if(strcmp(cb->f[1], "set") == 0) 1129 ctl->bpts = setbpt(ctl->bpts, cb->f[2], pc); 1130 else if(strcmp(cb->f[1], "del") == 0) 1131 ctl->bpts = delbpt(ctl->bpts, cb->f[2], pc); 1132 else 1133 error(Ebadctl); 1134 break; 1135 case CDmaim: 1136 p->kill = "maim"; 1137 break; 1138 } 1139 poperror(); 1140 free(cb); 1141 break; 1142 case Qheap: 1143 /* 1144 * Heap query: 1145 * addr.Fn 1146 * pc+module.In 1147 */ 1148 i = n; 1149 if(i > sizeof(buf)-1) 1150 i = sizeof(buf)-1; 1151 memmove(buf, va, i); 1152 buf[i] = '\0'; 1153 hq = c->aux; 1154 hq->addr = strtoul(buf, &b, 0); 1155 if(*b == '+') 1156 hq->module = strtoul(b, &b, 0); 1157 if(*b++ != '.') 1158 error(Ebadctl); 1159 hq->fmt = *b++; 1160 hq->count = strtoul(b, nil, 0); 1161 break; 1162 default: 1163 print("unknown qid in procwrite\n"); 1164 error(Egreg); 1165 } 1166 poperror(); 1167 release(); 1168 return n; 1169 } 1170 1171 static Bpt* 1172 setbpt(Bpt *bpts, char *path, int pc) 1173 { 1174 int n; 1175 Bpt *b; 1176 1177 n = strlen(path); 1178 b = mallocz(sizeof *b + n, 0); 1179 if(b == nil) 1180 return bpts; 1181 b->pc = pc; 1182 memmove(b->path, path, n+1); 1183 b->file = b->path; 1184 path = strrchr(b->path, '/'); 1185 if(path != nil) 1186 b->file = path + 1; 1187 b->next = bpts; 1188 return b; 1189 } 1190 1191 static Bpt* 1192 delbpt(Bpt *bpts, char *path, int pc) 1193 { 1194 Bpt *b, **last; 1195 1196 last = &bpts; 1197 for(b = bpts; b != nil; b = b->next){ 1198 if(b->pc == pc && strcmp(b->path, path) == 0) { 1199 *last = b->next; 1200 free(b); 1201 break; 1202 } 1203 last = &b->next; 1204 } 1205 return bpts; 1206 } 1207 1208 static void 1209 freebpts(Bpt *b) 1210 { 1211 Bpt *next; 1212 1213 for(; b != nil; b = next){ 1214 next = b->next; 1215 free(b); 1216 } 1217 } 1218 1219 static void 1220 telldbg(Progctl *ctl, char *msg) 1221 { 1222 kstrcpy(ctl->msg, msg, ERRMAX); 1223 ctl->debugger = nil; 1224 Wakeup(&ctl->r); 1225 } 1226 1227 static void 1228 dbgstart(Prog *p) 1229 { 1230 Osenv *o; 1231 Progctl *ctl; 1232 1233 o = p->osenv; 1234 ctl = o->debug; 1235 if(ctl != nil && ctl->debugger != nil) 1236 error("prog debugged"); 1237 if(p->state == Pdebug) 1238 addrun(p); 1239 o->debug = nil; 1240 p->xec = xec; 1241 } 1242 1243 static int 1244 xecdone(void *vc) 1245 { 1246 Progctl *ctl = vc; 1247 1248 return ctl->debugger == nil; 1249 } 1250 1251 static void 1252 dbgstep(Progctl *vctl, Prog *p, int n) 1253 { 1254 Osenv * volatile o; 1255 Progctl * volatile ctl; 1256 char buf[ERRMAX+20], *msg; 1257 1258 if(p == currun()) 1259 error("cannot step yourself"); 1260 1261 if(p->state == Pbroken) 1262 error("prog broken"); 1263 1264 ctl = vctl; 1265 if(ctl->debugger != nil) 1266 error("prog already debugged"); 1267 1268 o = p->osenv; 1269 if(o->debug == nil) { 1270 o->debug = ctl; 1271 p->xec = dbgxec; 1272 }else if(o->debug != ctl) 1273 error("prog already debugged"); 1274 1275 ctl->step = n; 1276 if(p->state == Pdebug) 1277 addrun(p); 1278 ctl->debugger = up; 1279 strcpy(buf, "child: "); 1280 msg = buf+7; 1281 ctl->msg = msg; 1282 1283 /* 1284 * wait for reply from dbgxec; release is okay because prog is now 1285 * debugged, cannot exit. 1286 */ 1287 if(waserror()){ 1288 acquire(); 1289 ctl->debugger = nil; 1290 ctl->msg = nil; 1291 o->debug = nil; 1292 p->xec = xec; 1293 nexterror(); 1294 } 1295 release(); 1296 Sleep(&ctl->r, xecdone, ctl); 1297 poperror(); 1298 acquire(); 1299 if(msg[0] != '\0') 1300 error(buf); 1301 } 1302 1303 void 1304 dbgexit(Prog *kid, int broken, char *estr) 1305 { 1306 int n; 1307 Osenv *e; 1308 Progctl *ctl; 1309 char buf[ERRMAX+20]; 1310 1311 e = kid->osenv; 1312 ctl = e->debug; 1313 e->debug = nil; 1314 kid->xec = xec; 1315 1316 if(broken) 1317 n = snprint(buf, sizeof(buf), "broken: %s", estr); 1318 else 1319 n = snprint(buf, sizeof(buf), "exited"); 1320 if(ctl->debugger) 1321 telldbg(ctl, buf); 1322 qproduce(ctl->q, buf, n); 1323 } 1324 1325 static void 1326 dbgaddrun(Prog *p) 1327 { 1328 Osenv *o; 1329 1330 p->state = Pdebug; 1331 p->addrun = nil; 1332 o = p->osenv; 1333 if(o->rend != nil) 1334 Wakeup(o->rend); 1335 o->rend = nil; 1336 } 1337 1338 static int 1339 bdone(void *vp) 1340 { 1341 Prog *p = vp; 1342 1343 return p->addrun == nil; 1344 } 1345 1346 static void 1347 dbgblock(Prog *p) 1348 { 1349 Osenv *o; 1350 Progctl *ctl; 1351 1352 o = p->osenv; 1353 ctl = o->debug; 1354 qproduce(ctl->q, progstate[p->state], strlen(progstate[p->state])); 1355 pushrun(p); 1356 p->addrun = dbgaddrun; 1357 o->rend = &up->sleep; 1358 1359 /* 1360 * bdone(p) is safe after release because p is being debugged, 1361 * so cannot exit. 1362 */ 1363 if(waserror()){ 1364 acquire(); 1365 nexterror(); 1366 } 1367 release(); 1368 if(o->rend != nil) 1369 Sleep(o->rend, bdone, p); 1370 poperror(); 1371 acquire(); 1372 if(p->kill != nil) 1373 error(p->kill); 1374 ctl = o->debug; 1375 if(ctl != nil) 1376 qproduce(ctl->q, "run", 3); 1377 } 1378 1379 void 1380 dbgxec(Prog *p) 1381 { 1382 Bpt *b; 1383 Prog *kid; 1384 Osenv *env; 1385 Progctl *ctl; 1386 int op, pc, n; 1387 char buf[ERRMAX+10]; 1388 extern void (*dec[])(void); 1389 1390 env = p->osenv; 1391 ctl = env->debug; 1392 ctl->ref++; 1393 if(waserror()){ 1394 closedbgctl(ctl, p); 1395 nexterror(); 1396 } 1397 1398 R = p->R; 1399 R.MP = R.M->MP; 1400 1401 R.IC = p->quanta; 1402 if((ulong)R.IC > ctl->step) 1403 R.IC = ctl->step; 1404 if(ctl->stop) 1405 R.IC = 0; 1406 1407 1408 buf[0] = '\0'; 1409 1410 if(R.IC != 0 && R.M->compiled) { 1411 comvec(); 1412 if(p != currun()) 1413 dbgblock(p); 1414 goto save; 1415 } 1416 1417 while(R.IC != 0) { 1418 if(0) 1419 print("step: %lux: %s %4ld %D\n", 1420 (ulong)p, R.M->m->name, R.PC-R.M->prog, R.PC); 1421 1422 dec[R.PC->add](); 1423 op = R.PC->op; 1424 R.PC++; 1425 optab[op](); 1426 1427 /* 1428 * check notification about new progs 1429 */ 1430 if(op == ISPAWN || op == IMSPAWN) { 1431 /* pick up the kid from the end of the run queue */ 1432 kid = delruntail(Pdebug); 1433 n = snprint(buf, sizeof buf, "new %d", kid->pid); 1434 qproduce(ctl->q, buf, n); 1435 buf[0] = '\0'; 1436 } 1437 if(op == ILOAD) { 1438 n = snprint(buf, sizeof buf, "load %s", string2c(*(String**)R.s)); 1439 qproduce(ctl->q, buf, n); 1440 buf[0] = '\0'; 1441 } 1442 1443 /* 1444 * check for returns at big steps 1445 */ 1446 if(op == IRET) 1447 R.IC = 1; 1448 1449 /* 1450 * check for blocked progs 1451 */ 1452 if(R.IC == 1 && p != currun()) 1453 dbgblock(p); 1454 if(ctl->stop) 1455 R.IC = 1; 1456 R.IC--; 1457 1458 if(ctl->bpts == nil) 1459 continue; 1460 1461 pc = R.PC - R.M->prog; 1462 for(b = ctl->bpts; b != nil; b = b->next) { 1463 if(pc == b->pc && 1464 (strcmp(R.M->m->path, b->path) == 0 || 1465 strcmp(R.M->m->path, b->file) == 0)) { 1466 strcpy(buf, "breakpoint"); 1467 goto save; 1468 } 1469 } 1470 } 1471 save: 1472 if(ctl->stop) 1473 strcpy(buf, "stopped"); 1474 1475 p->R = R; 1476 1477 if(env->debug == nil) { 1478 poperror(); 1479 return; 1480 } 1481 1482 if(p == currun()) 1483 delrun(Pdebug); 1484 1485 telldbg(env->debug, buf); 1486 poperror(); 1487 closedbgctl(env->debug, p); 1488 } 1489 1490 Dev progdevtab = { 1491 'p', 1492 "prog", 1493 1494 devinit, 1495 progattach, 1496 progwalk, 1497 progstat, 1498 progopen, 1499 devcreate, 1500 progclose, 1501 progread, 1502 devbread, 1503 progwrite, 1504 devbwrite, 1505 devremove, 1506 progwstat 1507 }; 1508