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 || p->group->flags&Pprivatemem || 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 || p->group->flags&Pprivatemem || 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 1030 USED(offset); 1031 USED(va); 1032 1033 if(c->qid.type & QTDIR) 1034 error(Eisdir); 1035 1036 acquire(); 1037 if(waserror()) { 1038 release(); 1039 nexterror(); 1040 } 1041 p = progpid(PID(c->qid)); 1042 if(p == nil) 1043 error(Ethread); 1044 1045 switch(QID(c->qid)){ 1046 case Qctl: 1047 cb = parsecmd(va, n); 1048 if(waserror()){ 1049 free(cb); 1050 nexterror(); 1051 } 1052 ct = lookupcmd(cb, progcmd, nelem(progcmd)); 1053 switch(ct->index){ 1054 case CMkillgrp: 1055 killgrp(p, "killed"); 1056 break; 1057 case CMkill: 1058 killprog(p, "killed"); 1059 break; 1060 case CMrestricted: 1061 p->flags |= Prestrict; 1062 break; 1063 case CMexceptions: 1064 if(p->group->id != p->pid) 1065 error(Eperm); 1066 if(strcmp(cb->f[1], "propagate") == 0) 1067 p->flags |= Ppropagate; 1068 else if(strcmp(cb->f[1], "notifyleader") == 0) 1069 p->flags |= Pnotifyleader; 1070 else 1071 error(Ebadctl); 1072 break; 1073 case CMprivate: 1074 p->group->flags |= Pprivatemem; 1075 break; 1076 } 1077 poperror(); 1078 free(cb); 1079 break; 1080 case Qdbgctl: 1081 cb = parsecmd(va, n); 1082 if(waserror()){ 1083 free(cb); 1084 nexterror(); 1085 } 1086 if(cb->nf == 1 && strncmp(cb->f[0], "step", 4) == 0) 1087 ct = progdbgcmd; 1088 else 1089 ct = lookupcmd(cb, progdbgcmd, nelem(progdbgcmd)); 1090 switch(ct->index){ 1091 case CDstep: 1092 if(cb->nf == 1) 1093 i = strtoul(cb->f[0]+4, nil, 0); 1094 else 1095 i = strtoul(cb->f[1], nil, 0); 1096 dbgstep(c->aux, p, i); 1097 break; 1098 case CDtoret: 1099 f = currun(); 1100 i = calldepth(&p->R); 1101 while(f->kill == nil) { 1102 dbgstep(c->aux, p, 1024); 1103 if(i > calldepth(&p->R)) 1104 break; 1105 } 1106 break; 1107 case CDcont: 1108 f = currun(); 1109 while(f->kill == nil) 1110 dbgstep(c->aux, p, 1024); 1111 break; 1112 case CDstart: 1113 dbgstart(p); 1114 break; 1115 case CDstop: 1116 ctl = c->aux; 1117 ctl->stop = 1; 1118 break; 1119 case CDunstop: 1120 ctl = c->aux; 1121 ctl->stop = 0; 1122 break; 1123 case CDbpt: 1124 pc = strtoul(cb->f[3], nil, 10); 1125 ctl = c->aux; 1126 if(strcmp(cb->f[1], "set") == 0) 1127 ctl->bpts = setbpt(ctl->bpts, cb->f[2], pc); 1128 else if(strcmp(cb->f[1], "del") == 0) 1129 ctl->bpts = delbpt(ctl->bpts, cb->f[2], pc); 1130 else 1131 error(Ebadctl); 1132 break; 1133 case CDmaim: 1134 p->kill = "maim"; 1135 break; 1136 } 1137 poperror(); 1138 free(cb); 1139 break; 1140 case Qheap: 1141 /* 1142 * Heap query: 1143 * addr.Fn 1144 * pc+module.In 1145 */ 1146 i = n; 1147 if(i > sizeof(buf)-1) 1148 i = sizeof(buf)-1; 1149 memmove(buf, va, i); 1150 buf[i] = '\0'; 1151 hq = c->aux; 1152 hq->addr = strtoul(buf, &b, 0); 1153 if(*b == '+') 1154 hq->module = strtoul(b, &b, 0); 1155 if(*b++ != '.') 1156 error(Ebadctl); 1157 hq->fmt = *b++; 1158 hq->count = strtoul(b, nil, 0); 1159 break; 1160 default: 1161 print("unknown qid in procwrite\n"); 1162 error(Egreg); 1163 } 1164 poperror(); 1165 release(); 1166 return n; 1167 } 1168 1169 static Bpt* 1170 setbpt(Bpt *bpts, char *path, int pc) 1171 { 1172 int n; 1173 Bpt *b; 1174 1175 n = strlen(path); 1176 b = mallocz(sizeof *b + n, 0); 1177 if(b == nil) 1178 return bpts; 1179 b->pc = pc; 1180 memmove(b->path, path, n+1); 1181 b->file = b->path; 1182 path = strrchr(b->path, '/'); 1183 if(path != nil) 1184 b->file = path + 1; 1185 b->next = bpts; 1186 return b; 1187 } 1188 1189 static Bpt* 1190 delbpt(Bpt *bpts, char *path, int pc) 1191 { 1192 Bpt *b, **last; 1193 1194 last = &bpts; 1195 for(b = bpts; b != nil; b = b->next){ 1196 if(b->pc == pc && strcmp(b->path, path) == 0) { 1197 *last = b->next; 1198 free(b); 1199 break; 1200 } 1201 last = &b->next; 1202 } 1203 return bpts; 1204 } 1205 1206 static void 1207 freebpts(Bpt *b) 1208 { 1209 Bpt *next; 1210 1211 for(; b != nil; b = next){ 1212 next = b->next; 1213 free(b); 1214 } 1215 } 1216 1217 static void 1218 telldbg(Progctl *ctl, char *msg) 1219 { 1220 kstrcpy(ctl->msg, msg, ERRMAX); 1221 ctl->debugger = nil; 1222 Wakeup(&ctl->r); 1223 } 1224 1225 static void 1226 dbgstart(Prog *p) 1227 { 1228 Osenv *o; 1229 Progctl *ctl; 1230 1231 o = p->osenv; 1232 ctl = o->debug; 1233 if(ctl != nil && ctl->debugger != nil) 1234 error("prog debugged"); 1235 if(p->state == Pdebug) 1236 addrun(p); 1237 o->debug = nil; 1238 p->xec = xec; 1239 } 1240 1241 static int 1242 xecdone(void *vc) 1243 { 1244 Progctl *ctl = vc; 1245 1246 return ctl->debugger == nil; 1247 } 1248 1249 static void 1250 dbgstep(Progctl *vctl, Prog *p, int n) 1251 { 1252 Osenv * volatile o; 1253 Progctl * volatile ctl; 1254 char buf[ERRMAX+20], *msg; 1255 1256 if(p == currun()) 1257 error("cannot step yourself"); 1258 1259 if(p->state == Pbroken) 1260 error("prog broken"); 1261 1262 ctl = vctl; 1263 if(ctl->debugger != nil) 1264 error("prog already debugged"); 1265 1266 o = p->osenv; 1267 if(o->debug == nil) { 1268 o->debug = ctl; 1269 p->xec = dbgxec; 1270 }else if(o->debug != ctl) 1271 error("prog already debugged"); 1272 1273 ctl->step = n; 1274 if(p->state == Pdebug) 1275 addrun(p); 1276 ctl->debugger = up; 1277 strcpy(buf, "child: "); 1278 msg = buf+7; 1279 ctl->msg = msg; 1280 1281 /* 1282 * wait for reply from dbgxec; release is okay because prog is now 1283 * debugged, cannot exit. 1284 */ 1285 if(waserror()){ 1286 acquire(); 1287 ctl->debugger = nil; 1288 ctl->msg = nil; 1289 o->debug = nil; 1290 p->xec = xec; 1291 nexterror(); 1292 } 1293 release(); 1294 Sleep(&ctl->r, xecdone, ctl); 1295 poperror(); 1296 acquire(); 1297 if(msg[0] != '\0') 1298 error(buf); 1299 } 1300 1301 void 1302 dbgexit(Prog *kid, int broken, char *estr) 1303 { 1304 int n; 1305 Osenv *e; 1306 Progctl *ctl; 1307 char buf[ERRMAX+20]; 1308 1309 e = kid->osenv; 1310 ctl = e->debug; 1311 e->debug = nil; 1312 kid->xec = xec; 1313 1314 if(broken) 1315 n = snprint(buf, sizeof(buf), "broken: %s", estr); 1316 else 1317 n = snprint(buf, sizeof(buf), "exited"); 1318 if(ctl->debugger) 1319 telldbg(ctl, buf); 1320 qproduce(ctl->q, buf, n); 1321 } 1322 1323 static void 1324 dbgaddrun(Prog *p) 1325 { 1326 Osenv *o; 1327 1328 p->state = Pdebug; 1329 p->addrun = nil; 1330 o = p->osenv; 1331 if(o->rend != nil) 1332 Wakeup(o->rend); 1333 o->rend = nil; 1334 } 1335 1336 static int 1337 bdone(void *vp) 1338 { 1339 Prog *p = vp; 1340 1341 return p->addrun == nil; 1342 } 1343 1344 static void 1345 dbgblock(Prog *p) 1346 { 1347 Osenv *o; 1348 Progctl *ctl; 1349 1350 o = p->osenv; 1351 ctl = o->debug; 1352 qproduce(ctl->q, progstate[p->state], strlen(progstate[p->state])); 1353 pushrun(p); 1354 p->addrun = dbgaddrun; 1355 o->rend = &up->sleep; 1356 1357 /* 1358 * bdone(p) is safe after release because p is being debugged, 1359 * so cannot exit. 1360 */ 1361 if(waserror()){ 1362 acquire(); 1363 nexterror(); 1364 } 1365 release(); 1366 if(o->rend != nil) 1367 Sleep(o->rend, bdone, p); 1368 poperror(); 1369 acquire(); 1370 if(p->kill != nil) 1371 error(p->kill); 1372 ctl = o->debug; 1373 if(ctl != nil) 1374 qproduce(ctl->q, "run", 3); 1375 } 1376 1377 void 1378 dbgxec(Prog *p) 1379 { 1380 Bpt *b; 1381 Prog *kid; 1382 Osenv *env; 1383 Progctl *ctl; 1384 int op, pc, n; 1385 char buf[ERRMAX+10]; 1386 extern void (*dec[])(void); 1387 1388 env = p->osenv; 1389 ctl = env->debug; 1390 ctl->ref++; 1391 if(waserror()){ 1392 closedbgctl(ctl, p); 1393 nexterror(); 1394 } 1395 1396 R = p->R; 1397 R.MP = R.M->MP; 1398 1399 R.IC = p->quanta; 1400 if((ulong)R.IC > ctl->step) 1401 R.IC = ctl->step; 1402 if(ctl->stop) 1403 R.IC = 0; 1404 1405 1406 buf[0] = '\0'; 1407 1408 if(R.IC != 0 && R.M->compiled) { 1409 comvec(); 1410 if(p != currun()) 1411 dbgblock(p); 1412 goto save; 1413 } 1414 1415 while(R.IC != 0) { 1416 if(0) 1417 print("step: %lux: %s %4ld %D\n", 1418 (ulong)p, R.M->m->name, R.PC-R.M->prog, R.PC); 1419 1420 dec[R.PC->add](); 1421 op = R.PC->op; 1422 R.PC++; 1423 optab[op](); 1424 1425 /* 1426 * check notification about new progs 1427 */ 1428 if(op == ISPAWN || op == IMSPAWN) { 1429 /* pick up the kid from the end of the run queue */ 1430 kid = delruntail(Pdebug); 1431 n = snprint(buf, sizeof buf, "new %d", kid->pid); 1432 qproduce(ctl->q, buf, n); 1433 buf[0] = '\0'; 1434 } 1435 if(op == ILOAD) { 1436 n = snprint(buf, sizeof buf, "load %s", string2c(*(String**)R.s)); 1437 qproduce(ctl->q, buf, n); 1438 buf[0] = '\0'; 1439 } 1440 1441 /* 1442 * check for returns at big steps 1443 */ 1444 if(op == IRET) 1445 R.IC = 1; 1446 1447 /* 1448 * check for blocked progs 1449 */ 1450 if(R.IC == 1 && p != currun()) 1451 dbgblock(p); 1452 if(ctl->stop) 1453 R.IC = 1; 1454 R.IC--; 1455 1456 if(ctl->bpts == nil) 1457 continue; 1458 1459 pc = R.PC - R.M->prog; 1460 for(b = ctl->bpts; b != nil; b = b->next) { 1461 if(pc == b->pc && 1462 (strcmp(R.M->m->path, b->path) == 0 || 1463 strcmp(R.M->m->path, b->file) == 0)) { 1464 strcpy(buf, "breakpoint"); 1465 goto save; 1466 } 1467 } 1468 } 1469 save: 1470 if(ctl->stop) 1471 strcpy(buf, "stopped"); 1472 1473 p->R = R; 1474 1475 if(env->debug == nil) { 1476 poperror(); 1477 return; 1478 } 1479 1480 if(p == currun()) 1481 delrun(Pdebug); 1482 1483 telldbg(env->debug, buf); 1484 poperror(); 1485 closedbgctl(env->debug, p); 1486 } 1487 1488 Dev progdevtab = { 1489 'p', 1490 "prog", 1491 1492 devinit, 1493 progattach, 1494 progwalk, 1495 progstat, 1496 progopen, 1497 devcreate, 1498 progclose, 1499 progread, 1500 devbread, 1501 progwrite, 1502 devbwrite, 1503 devremove, 1504 progwstat 1505 }; 1506