1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "error.h" 7 #include <interp.h> 8 #include <isa.h> 9 #include "runt.h" 10 11 /* 12 * Enable the heap device for environments that allow debugging => 13 * Must be 1 for a production environment. 14 */ 15 int SECURE = 0; 16 17 enum 18 { 19 Qdir, 20 Qctl, 21 Qdbgctl, 22 Qheap, 23 Qns, 24 Qnsgrp, 25 Qpgrp, 26 Qstack, 27 Qstatus, 28 Qtext, 29 Qwait, 30 Qfd, 31 Qexception, 32 }; 33 34 /* 35 * must be in same order as enum 36 */ 37 Dirtab progdir[] = 38 { 39 "ctl", {Qctl}, 0, 0200, 40 "dbgctl", {Qdbgctl}, 0, 0600, 41 "heap", {Qheap}, 0, 0600, 42 "ns", {Qns}, 0, 0400, 43 "nsgrp", {Qnsgrp}, 0, 0444, 44 "pgrp", {Qpgrp}, 0, 0444, 45 "stack", {Qstack}, 0, 0400, 46 "status", {Qstatus}, 0, 0444, 47 "text", {Qtext}, 0, 0000, 48 "wait", {Qwait}, 0, 0400, 49 "fd", {Qfd}, 0, 0400, 50 "exception", {Qexception}, 0, 0400, 51 }; 52 53 enum 54 { 55 CMkill, 56 CMkillgrp, 57 CMrestricted, 58 CMexceptions, 59 CMprivate 60 }; 61 62 static 63 Cmdtab progcmd[] = { 64 CMkill, "kill", 1, 65 CMkillgrp, "killgrp", 1, 66 CMrestricted, "restricted", 1, 67 CMexceptions, "exceptions", 2, 68 CMprivate, "private", 1, 69 }; 70 71 enum 72 { 73 CDstep, 74 CDtoret, 75 CDcont, 76 CDstart, 77 CDstop, 78 CDunstop, 79 CDmaim, 80 CDbpt 81 }; 82 83 static 84 Cmdtab progdbgcmd[] = { 85 CDstep, "step", 0, /* known below to be first, to cope with stepN */ 86 CDtoret, "toret", 1, 87 CDcont, "cont", 1, 88 CDstart, "start", 1, 89 CDstop, "stop", 1, 90 CDunstop, "unstop", 1, 91 CDmaim, "maim", 1, 92 CDbpt, "bpt", 4, 93 }; 94 95 typedef struct Heapqry Heapqry; 96 struct Heapqry 97 { 98 char fmt; 99 ulong addr; 100 ulong module; 101 int count; 102 }; 103 104 typedef struct Bpt Bpt; 105 106 struct Bpt 107 { 108 Bpt *next; 109 int pc; 110 char *file; 111 char path[1]; 112 }; 113 114 typedef struct Progctl Progctl; 115 struct Progctl 116 { 117 Rendez r; 118 int ref; 119 Proc *debugger; /* waiting for dbgxec */ 120 char *msg; /* reply from dbgxec */ 121 int step; /* instructions to try */ 122 int stop; /* stop running the program */ 123 Bpt* bpts; /* active breakpoints */ 124 Queue* q; /* status queue */ 125 }; 126 127 #define QSHIFT 4 /* location in qid of pid */ 128 #define QID(q) (((ulong)(q).path&0x0000000F)>>0) 129 #define QPID(pid) (((pid)<<QSHIFT)) 130 #define PID(q) ((q).vers) 131 #define PATH(q) ((ulong)(q).path&~((1<<QSHIFT)-1)) 132 133 static char *progstate[] = /* must correspond to include/interp.h */ 134 { 135 "alt", /* blocked in alt instruction */ 136 "send", /* waiting to send */ 137 "recv", /* waiting to recv */ 138 "debug", /* debugged */ 139 "ready", /* ready to be scheduled */ 140 "release", /* interpreter released */ 141 "exiting", /* exit because of kill or error */ 142 "broken", /* thread crashed */ 143 }; 144 145 static void dbgstep(Progctl*, Prog*, int); 146 static void dbgstart(Prog*); 147 static void freebpts(Bpt*); 148 static Bpt* delbpt(Bpt*, char*, int); 149 static Bpt* setbpt(Bpt*, char*, int); 150 static void mntscan(Mntwalk*, Pgrp*); 151 extern Type *Trdchan; 152 extern Type *Twrchan; 153 extern Module* modules; 154 static char Emisalign[] = "misaligned address"; 155 156 static int 157 proggen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp) 158 { 159 Qid qid; 160 Prog *p; 161 char *e; 162 Osenv *o; 163 ulong pid, path, perm, len; 164 165 if(s == DEVDOTDOT){ 166 mkqid(&qid, Qdir, 0, QTDIR); 167 devdir(c, qid, "#p", 0, eve, DMDIR|0555, dp); 168 return 1; 169 } 170 171 if((ulong)c->qid.path == Qdir) { 172 if(name != nil){ 173 /* ignore s and use name to find pid */ 174 pid = strtoul(name, &e, 0); 175 if(pid == 0 || *e != '\0') 176 return -1; 177 acquire(); 178 p = progpid(pid); 179 if(p == nil){ 180 release(); 181 return -1; 182 } 183 }else{ 184 acquire(); 185 p = progn(s); 186 if(p == nil) { 187 release(); 188 return -1; 189 } 190 pid = p->pid; 191 } 192 o = p->osenv; 193 sprint(up->genbuf, "%lud", pid); 194 if(name != nil && strcmp(name, up->genbuf) != 0){ 195 release(); 196 return -1; 197 } 198 mkqid(&qid, pid<<QSHIFT, pid, QTDIR); 199 devdir(c, qid, up->genbuf, 0, o->user, DMDIR|0555, dp); 200 release(); 201 return 1; 202 } 203 204 if(s >= nelem(progdir)) 205 return -1; 206 tab = &progdir[s]; 207 path = PATH(c->qid); 208 209 acquire(); 210 p = progpid(PID(c->qid)); 211 if(p == nil) { 212 release(); 213 return -1; 214 } 215 216 o = p->osenv; 217 218 perm = tab->perm; 219 if((perm & 7) == 0) 220 perm = (perm|(perm>>3)|(perm>>6)) & o->pgrp->progmode; 221 222 len = tab->length; 223 mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE); 224 devdir(c, qid, tab->name, len, o->user, perm, dp); 225 release(); 226 return 1; 227 } 228 229 static Chan* 230 progattach(char *spec) 231 { 232 return devattach('p', spec); 233 } 234 235 static Walkqid* 236 progwalk(Chan *c, Chan *nc, char **name, int nname) 237 { 238 return devwalk(c, nc, name, nname, 0, 0, proggen); 239 } 240 241 static int 242 progstat(Chan *c, uchar *db, int n) 243 { 244 return devstat(c, db, n, 0, 0, proggen); 245 } 246 247 static Chan* 248 progopen(Chan *c, int omode) 249 { 250 Prog *p; 251 Osenv *o; 252 Progctl *ctl; 253 int perm; 254 255 if(c->qid.type & QTDIR) 256 return devopen(c, omode, 0, 0, proggen); 257 258 acquire(); 259 if (waserror()) { 260 release(); 261 nexterror(); 262 } 263 p = progpid(PID(c->qid)); 264 if(p == nil) 265 error(Ethread); 266 267 o = p->osenv; 268 perm = progdir[QID(c->qid)-1].perm; 269 if((perm & 7) == 0) 270 perm = (perm|(perm>>3)|(perm>>6)) & o->pgrp->progmode; 271 devpermcheck(o->user, perm, omode); 272 omode = openmode(omode); 273 274 switch(QID(c->qid)){ 275 default: 276 error(Egreg); 277 case Qnsgrp: 278 case Qpgrp: 279 case Qtext: 280 case Qstatus: 281 case Qstack: 282 case Qctl: 283 case Qfd: 284 case Qexception: 285 break; 286 case Qwait: 287 c->aux = qopen(1024, Qmsg, nil, nil); 288 if(c->aux == nil) 289 error(Enomem); 290 o->childq = c->aux; 291 break; 292 case Qns: 293 c->aux = malloc(sizeof(Mntwalk)); 294 if(c->aux == nil) 295 error(Enomem); 296 break; 297 case Qheap: 298 if(SECURE || p->group->flags&Pprivatemem || omode != ORDWR) 299 error(Eperm); 300 c->aux = malloc(sizeof(Heapqry)); 301 if(c->aux == nil) 302 error(Enomem); 303 break; 304 case Qdbgctl: 305 if(SECURE || p->group->flags&Pprivatemem || omode != ORDWR) 306 error(Eperm); 307 ctl = malloc(sizeof(Progctl)); 308 if(ctl == nil) 309 error(Enomem); 310 ctl->q = qopen(1024, Qmsg, nil, nil); 311 if(ctl->q == nil) { 312 free(ctl); 313 error(Enomem); 314 } 315 ctl->bpts = nil; 316 ctl->ref = 1; 317 c->aux = ctl; 318 break; 319 } 320 if(p->state != Pexiting) 321 c->qid.vers = p->pid; 322 323 poperror(); 324 release(); 325 c->offset = 0; 326 c->mode = omode; 327 c->flag |= COPEN; 328 return c; 329 } 330 331 static int 332 progwstat(Chan *c, uchar *db, int n) 333 { 334 Dir d; 335 Prog *p; 336 char *u; 337 Osenv *o; 338 339 if(c->qid.type&QTDIR) 340 error(Eperm); 341 acquire(); 342 p = progpid(PID(c->qid)); 343 if(p == nil) { 344 release(); 345 error(Ethread); 346 } 347 348 u = up->env->user; 349 o = p->osenv; 350 if(strcmp(u, o->user) != 0 && strcmp(u, eve) != 0) { 351 release(); 352 error(Eperm); 353 } 354 355 n = convM2D(db, n, &d, nil); 356 if(n == 0){ 357 release(); 358 error(Eshortstat); 359 } 360 if(d.mode != ~0UL) 361 o->pgrp->progmode = d.mode&0777; 362 release(); 363 return n; 364 } 365 366 static void 367 closedbgctl(Progctl *ctl, Prog *p) 368 { 369 Osenv *o; 370 371 if(ctl->ref-- > 1) 372 return; 373 freebpts(ctl->bpts); 374 if(p != nil){ 375 o = p->osenv; 376 if(o->debug == ctl){ 377 o->debug = nil; 378 p->xec = xec; 379 } 380 } 381 qfree(ctl->q); 382 free(ctl); 383 } 384 385 static void 386 progclose(Chan *c) 387 { 388 int i; 389 Prog *f; 390 Osenv *o; 391 Progctl *ctl; 392 393 switch(QID(c->qid)) { 394 case Qns: 395 case Qheap: 396 free(c->aux); 397 break; 398 case Qdbgctl: 399 if((c->flag & COPEN) == 0) 400 return; 401 ctl = c->aux; 402 acquire(); 403 closedbgctl(ctl, progpid(PID(c->qid))); 404 release(); 405 break; 406 case Qwait: 407 acquire(); 408 i = 0; 409 for(;;) { 410 f = progn(i++); 411 if(f == nil) 412 break; 413 o = f->osenv; 414 if(o->waitq == c->aux) 415 o->waitq = nil; 416 if(o->childq == c->aux) 417 o->childq = nil; 418 } 419 release(); 420 qfree(c->aux); 421 } 422 } 423 424 static int 425 progsize(Prog *p) 426 { 427 int size; 428 Frame *f; 429 uchar *fp; 430 Modlink *m; 431 432 m = p->R.M; 433 size = 0; 434 if(m->MP != H) 435 size += hmsize(D2H(m->MP)); 436 if(m->prog != nil) 437 size += msize(m->prog); 438 439 fp = p->R.FP; 440 while(fp != nil) { 441 f = (Frame*)fp; 442 fp = f->fp; 443 if(f->mr != nil) { 444 if(f->mr->MP != H) 445 size += hmsize(D2H(f->mr->MP)); 446 if(f->mr->prog != nil) 447 size += msize(f->mr->prog); 448 } 449 if(f->t == nil) 450 size += msize(SEXTYPE(f)); 451 } 452 return size/1024; 453 } 454 455 static long 456 progoffset(long offset, char *va, int *np) 457 { 458 if(offset > 0) { 459 offset -= *np; 460 if(offset < 0) { 461 memmove(va, va+*np+offset, -offset); 462 *np = -offset; 463 } 464 else 465 *np = 0; 466 } 467 return offset; 468 } 469 470 static int 471 progqidwidth(Chan *c) 472 { 473 char buf[32]; 474 475 return sprint(buf, "%lud", c->qid.vers); 476 } 477 478 int 479 progfdprint(Chan *c, int fd, int w, char *s, int ns) 480 { 481 int n; 482 483 if(w == 0) 484 w = progqidwidth(c); 485 n = snprint(s, ns, "%3d %.2s %C %4ld (%.16llux %*lud %.2ux) %5ld %8lld %s\n", 486 fd, 487 &"r w rw"[(c->mode&3)<<1], 488 devtab[c->type]->dc, c->dev, 489 c->qid.path, w, c->qid.vers, c->qid.type, 490 c->iounit, c->offset, c->name->s); 491 return n; 492 } 493 494 static int 495 progfds(Osenv *o, char *va, int count, long offset) 496 { 497 Fgrp *f; 498 Chan *c; 499 int n, i, w, ww; 500 501 f = o->fgrp; /* f is not locked because we've acquired */ 502 n = readstr(0, va, count, o->pgrp->dot->name->s); 503 n += snprint(va+n, count-n, "\n"); 504 offset = progoffset(offset, va, &n); 505 /* compute width of qid.path */ 506 w = 0; 507 for(i = 0; i <= f->maxfd; i++) { 508 c = f->fd[i]; 509 if(c == nil) 510 continue; 511 ww = progqidwidth(c); 512 if(ww > w) 513 w = ww; 514 } 515 for(i = 0; i <= f->maxfd; i++) { 516 c = f->fd[i]; 517 if(c == nil) 518 continue; 519 n += progfdprint(c, i, w, va+n, count-n); 520 offset = progoffset(offset, va, &n); 521 } 522 return n; 523 } 524 525 Inst * 526 pc2dispc(Inst *pc, Module *mod) 527 { 528 ulong l, u, m, v; 529 ulong *tab = mod->pctab; 530 531 v = (ulong)pc - (ulong)mod->prog; 532 l = 0; 533 u = mod->nprog-1; 534 while(l < u){ 535 m = (l+u+1)/2; 536 if(tab[m] < v) 537 l = m; 538 else if(tab[m] > v) 539 u = m-1; 540 else 541 l = u = m; 542 } 543 if(l == u && tab[u] <= v && u != mod->nprog-1 && tab[u+1] > v) 544 return &mod->prog[u]; 545 return 0; 546 } 547 548 static int 549 progstack(REG *reg, int state, char *va, int count, long offset) 550 { 551 int n; 552 Frame *f; 553 Inst *pc; 554 uchar *fp; 555 Modlink *m; 556 557 n = 0; 558 m = reg->M; 559 fp = reg->FP; 560 pc = reg->PC; 561 562 /* 563 * all states other than debug and ready block, 564 * but interp has already advanced the PC 565 */ 566 if(!m->compiled && state != Pready && state != Pdebug && pc > m->prog) 567 pc--; 568 if(m->compiled && m->m->pctab != nil) 569 pc = pc2dispc(pc, m->m); 570 571 while(fp != nil) { 572 f = (Frame*)fp; 573 n += snprint(va+n, count-n, "%.8lux %.8lux %.8lux %.8lux %d %s\n", 574 (ulong)f, /* FP */ 575 (ulong)(pc - m->prog), /* PC in dis instructions */ 576 (ulong)m->MP, /* MP */ 577 (ulong)m->prog, /* Code for module */ 578 m->compiled && m->m->pctab == nil, /* True if native assembler: fool stack utility for now */ 579 m->m->path); /* File system path */ 580 581 if(offset > 0) { 582 offset -= n; 583 if(offset < 0) { 584 memmove(va, va+n+offset, -offset); 585 n = -offset; 586 } 587 else 588 n = 0; 589 } 590 591 pc = f->lr; 592 fp = f->fp; 593 if(f->mr != nil) 594 m = f->mr; 595 if(!m->compiled) 596 pc--; 597 else if(m->m->pctab != nil) 598 pc = pc2dispc(pc, m->m)-1; 599 } 600 return n; 601 } 602 603 static int 604 calldepth(REG *reg) 605 { 606 int n; 607 uchar *fp; 608 609 n = 0; 610 for(fp = reg->FP; fp != nil; fp = ((Frame*)fp)->fp) 611 n++; 612 return n; 613 } 614 615 static int 616 progheap(Heapqry *hq, char *va, int count, ulong offset) 617 { 618 WORD *w; 619 void *p; 620 List *hd; 621 Array *a; 622 char *fmt, *str; 623 Module *m; 624 Modlink *ml; 625 Channel *c; 626 ulong addr; 627 String *ss; 628 union { REAL r; LONG l; WORD w[2]; } rock; 629 int i, s, n, len, signed_off; 630 Type *t; 631 632 n = 0; 633 s = 0; 634 signed_off = offset; 635 addr = hq->addr; 636 for(i = 0; i < hq->count; i++) { 637 switch(hq->fmt) { 638 case 'W': 639 if(addr & 3) 640 return -1; 641 n += snprint(va+n, count-n, "%d\n", *(WORD*)addr); 642 s = sizeof(WORD); 643 break; 644 case 'B': 645 n += snprint(va+n, count-n, "%d\n", *(BYTE*)addr); 646 s = sizeof(BYTE); 647 break; 648 case 'V': 649 if(addr & 3) 650 return -1; 651 w = (WORD*)addr; 652 rock.w[0] = w[0]; 653 rock.w[1] = w[1]; 654 n += snprint(va+n, count-n, "%lld\n", rock.l); 655 s = sizeof(LONG); 656 break; 657 case 'R': 658 if(addr & 3) 659 return -1; 660 w = (WORD*)addr; 661 rock.w[0] = w[0]; 662 rock.w[1] = w[1]; 663 n += snprint(va+n, count-n, "%g\n", rock.r); 664 s = sizeof(REAL); 665 break; 666 case 'I': 667 if(addr & 3) 668 return -1; 669 for(m = modules; m != nil; m = m->link) 670 if(m == (Module*)hq->module) 671 break; 672 if(m == nil) 673 error(Ebadctl); 674 addr = (ulong)(m->prog+addr); 675 n += snprint(va+n, count-n, "%D\n", (Inst*)addr); 676 s = sizeof(Inst); 677 break; 678 case 'P': 679 if(addr & 3) 680 return -1; 681 p = *(void**)addr; 682 fmt = "nil\n"; 683 if(p != H) 684 fmt = "%lux\n"; 685 n += snprint(va+n, count-n, fmt, p); 686 s = sizeof(WORD); 687 break; 688 case 'L': 689 if(addr & 3) 690 return -1; 691 hd = *(List**)addr; 692 if(hd == H || D2H(hd)->t != &Tlist) 693 return -1; 694 n += snprint(va+n, count-n, "%lux.%lux\n", (ulong)&hd->tail, (ulong)hd->data); 695 s = sizeof(WORD); 696 break; 697 case 'A': 698 if(addr & 3) 699 return -1; 700 a = *(Array**)addr; 701 if(a == H) 702 n += snprint(va+n, count-n, "nil\n"); 703 else { 704 if(D2H(a)->t != &Tarray) 705 return -1; 706 n += snprint(va+n, count-n, "%d.%lux\n", a->len, (ulong)a->data); 707 } 708 s = sizeof(WORD); 709 break; 710 case 'C': 711 if(addr & 3) 712 return -1; 713 ss = *(String**)addr; 714 if(ss == H) 715 ss = &snil; 716 else 717 if(D2H(ss)->t != &Tstring) 718 return -1; 719 n += snprint(va+n, count-n, "%d.", abs(ss->len)); 720 str = string2c(ss); 721 len = strlen(str); 722 if(count-n < len) 723 len = count-n; 724 if(len > 0) { 725 memmove(va+n, str, len); 726 n += len; 727 } 728 break; 729 case 'M': 730 if(addr & 3) 731 return -1; 732 ml = *(Modlink**)addr; 733 fmt = ml == H ? "nil\n" : "%lux\n"; 734 n += snprint(va+n, count-n, fmt, ml->MP); 735 s = sizeof(WORD); 736 break; 737 case 'c': 738 if(addr & 3) 739 return -1; 740 c = *(Channel**)addr; 741 if(c == H) 742 n += snprint(va+n, count-n, "nil\n"); 743 else{ 744 t = D2H(c)->t; 745 if(t != &Tchannel && t != Trdchan && t != Twrchan) 746 return -1; 747 if(c->buf == H) 748 n += snprint(va+n, count-n, "0.%lux\n", (ulong)c); 749 else 750 n += snprint(va+n, count-n, "%d.%lux.%d.%d\n", c->buf->len, (ulong)c->buf->data, c->front, c->size); 751 } 752 break; 753 754 } 755 addr += s; 756 if(signed_off > 0) { 757 signed_off -= n; 758 if(signed_off < 0) { 759 memmove(va, va+n+signed_off, -signed_off); 760 n = -signed_off; 761 } 762 else 763 n = 0; 764 } 765 } 766 return n; 767 } 768 769 WORD 770 modstatus(REG *r, char *ptr, int len) 771 { 772 Inst *PC; 773 Frame *f; 774 775 if(r->M->m->name[0] == '$') { 776 f = (Frame*)r->FP; 777 snprint(ptr, len, "%s[%s]", f->mr->m->name, r->M->m->name); 778 if(f->mr->compiled) 779 return (WORD)f->lr; 780 return f->lr - f->mr->prog; 781 } 782 memmove(ptr, r->M->m->name, len); 783 if(r->M->compiled) 784 return (WORD)r->PC; 785 PC = r->PC; 786 /* should really check for blocked states */ 787 if(PC > r->M->prog) 788 PC--; 789 return PC - r->M->prog; 790 } 791 792 static void 793 int2flag(int flag, char *s) 794 { 795 if(flag == 0){ 796 *s = '\0'; 797 return; 798 } 799 *s++ = '-'; 800 if(flag & MAFTER) 801 *s++ = 'a'; 802 if(flag & MBEFORE) 803 *s++ = 'b'; 804 if(flag & MCREATE) 805 *s++ = 'c'; 806 if(flag & MCACHE) 807 *s++ = 'C'; 808 *s = '\0'; 809 } 810 811 static char* 812 progtime(ulong msec, char *buf, char *ebuf) 813 { 814 int tenths, sec; 815 816 tenths = msec/100; 817 sec = tenths/10; 818 seprint(buf, ebuf, "%4d:%2.2d.%d", sec/60, sec%60, tenths%10); 819 return buf; 820 } 821 822 static long 823 progread(Chan *c, void *va, long n, vlong offset) 824 { 825 int i; 826 Prog *p; 827 Osenv *o; 828 Mntwalk *mw; 829 ulong grpid; 830 char *a = va; 831 Progctl *ctl; 832 char mbuf[64], timebuf[12]; 833 char flag[10]; 834 835 if(c->qid.type & QTDIR) 836 return devdirread(c, a, n, 0, 0, proggen); 837 838 switch(QID(c->qid)){ 839 case Qdbgctl: 840 ctl = c->aux; 841 return qread(ctl->q, va, n); 842 case Qstatus: 843 acquire(); 844 p = progpid(PID(c->qid)); 845 if(p == nil || p->state == Pexiting || p->R.M == H) { 846 release(); 847 snprint(up->genbuf, sizeof(up->genbuf), "%8lud %8d %10s %s %10s %5dK %s", 848 PID(c->qid), 849 0, 850 eve, 851 progtime(0, timebuf, timebuf+sizeof(timebuf)), 852 progstate[Pexiting], 853 0, 854 "[$Sys]"); 855 return readstr(offset, va, n, up->genbuf); 856 } 857 modstatus(&p->R, mbuf, sizeof(mbuf)); 858 o = p->osenv; 859 snprint(up->genbuf, sizeof(up->genbuf), "%8d %8d %10s %s %10s %5dK %s", 860 p->pid, 861 p->group!=nil? p->group->id: 0, 862 o->user, 863 progtime(TK2MS(p->ticks), timebuf, timebuf+sizeof(timebuf)), 864 progstate[p->state], 865 progsize(p), 866 mbuf); 867 release(); 868 return readstr(offset, va, n, up->genbuf); 869 case Qwait: 870 return qread(c->aux, va, n); 871 case Qns: 872 acquire(); 873 if(waserror()){ 874 release(); 875 nexterror(); 876 } 877 p = progpid(PID(c->qid)); 878 if(p == nil) 879 error(Ethread); 880 mw = c->aux; 881 if(mw->cddone){ 882 poperror(); 883 release(); 884 return 0; 885 } 886 o = p->osenv; 887 mntscan(mw, o->pgrp); 888 if(mw->mh == 0) { 889 mw->cddone = 1; 890 i = snprint(a, n, "cd %s\n", o->pgrp->dot->name->s); 891 poperror(); 892 release(); 893 return i; 894 } 895 int2flag(mw->cm->mflag, flag); 896 if(strcmp(mw->cm->to->name->s, "#M") == 0){ 897 i = snprint(a, n, "mount %s %s %s %s\n", flag, 898 mw->cm->to->mchan->name->s, 899 mw->mh->from->name->s, mw->cm->spec? mw->cm->spec : ""); 900 }else 901 i = snprint(a, n, "bind %s %s %s\n", flag, 902 mw->cm->to->name->s, mw->mh->from->name->s); 903 poperror(); 904 release(); 905 return i; 906 case Qnsgrp: 907 acquire(); 908 p = progpid(PID(c->qid)); 909 if(p == nil) { 910 release(); 911 error(Ethread); 912 } 913 grpid = ((Osenv *)p->osenv)->pgrp->pgrpid; 914 release(); 915 return readnum(offset, va, n, grpid, NUMSIZE); 916 case Qpgrp: 917 acquire(); 918 p = progpid(PID(c->qid)); 919 if(p == nil) { 920 release(); 921 error(Ethread); 922 } 923 grpid = p->group!=nil? p->group->id: 0; 924 release(); 925 return readnum(offset, va, n, grpid, NUMSIZE); 926 case Qstack: 927 acquire(); 928 p = progpid(PID(c->qid)); 929 if(p == nil || p->state == Pexiting) { 930 release(); 931 error(Ethread); 932 } 933 if(p->state == Pready) { 934 release(); 935 error(Estopped); 936 } 937 n = progstack(&p->R, p->state, va, n, offset); 938 release(); 939 return n; 940 case Qheap: 941 acquire(); 942 if(waserror()){ 943 release(); 944 nexterror(); 945 } 946 n = progheap(c->aux, va, n, offset); 947 if(n == -1) 948 error(Emisalign); 949 poperror(); 950 release(); 951 return n; 952 case Qfd: 953 acquire(); 954 if(waserror()) { 955 release(); 956 nexterror(); 957 } 958 p = progpid(PID(c->qid)); 959 if(p == nil) 960 error(Ethread); 961 o = p->osenv; 962 n = progfds(o, va, n, offset); 963 poperror(); 964 release(); 965 return n; 966 case Qexception: 967 acquire(); 968 p = progpid(PID(c->qid)); 969 if(p == nil) { 970 release(); 971 error(Ethread); 972 } 973 if(p->exstr == nil) 974 up->genbuf[0] = 0; 975 else 976 snprint(up->genbuf, sizeof(up->genbuf), p->exstr); 977 release(); 978 return readstr(offset, va, n, up->genbuf); 979 } 980 error(Egreg); 981 return 0; 982 } 983 984 static void 985 mntscan(Mntwalk *mw, Pgrp *pg) 986 { 987 Mount *t; 988 Mhead *f; 989 int nxt, i; 990 ulong last, bestmid; 991 992 rlock(&pg->ns); 993 994 nxt = 0; 995 bestmid = ~0; 996 997 last = 0; 998 if(mw->mh) 999 last = mw->cm->mountid; 1000 1001 for(i = 0; i < MNTHASH; i++) { 1002 for(f = pg->mnthash[i]; f; f = f->hash) { 1003 for(t = f->mount; t; t = t->next) { 1004 if(mw->mh == 0 || 1005 (t->mountid > last && t->mountid < bestmid)) { 1006 mw->cm = t; 1007 mw->mh = f; 1008 bestmid = mw->cm->mountid; 1009 nxt = 1; 1010 } 1011 } 1012 } 1013 } 1014 if(nxt == 0) 1015 mw->mh = 0; 1016 1017 runlock(&pg->ns); 1018 } 1019 1020 static long 1021 progwrite(Chan *c, void *va, long n, vlong offset) 1022 { 1023 Prog *p, *f; 1024 Heapqry *hq; 1025 char buf[128]; 1026 Progctl *ctl; 1027 char *b; 1028 int i, pc; 1029 Cmdbuf *cb; 1030 Cmdtab *ct; 1031 1032 USED(offset); 1033 USED(va); 1034 1035 if(c->qid.type & QTDIR) 1036 error(Eisdir); 1037 1038 acquire(); 1039 if(waserror()) { 1040 release(); 1041 nexterror(); 1042 } 1043 p = progpid(PID(c->qid)); 1044 if(p == nil) 1045 error(Ethread); 1046 1047 switch(QID(c->qid)){ 1048 case Qctl: 1049 cb = parsecmd(va, n); 1050 if(waserror()){ 1051 free(cb); 1052 nexterror(); 1053 } 1054 ct = lookupcmd(cb, progcmd, nelem(progcmd)); 1055 switch(ct->index){ 1056 case CMkillgrp: 1057 killgrp(p, "killed"); 1058 break; 1059 case CMkill: 1060 killprog(p, "killed"); 1061 break; 1062 case CMrestricted: 1063 p->flags |= Prestrict; 1064 break; 1065 case CMexceptions: 1066 if(p->group->id != p->pid) 1067 error(Eperm); 1068 if(strcmp(cb->f[1], "propagate") == 0) 1069 p->flags |= Ppropagate; 1070 else if(strcmp(cb->f[1], "notifyleader") == 0) 1071 p->flags |= Pnotifyleader; 1072 else 1073 error(Ebadctl); 1074 break; 1075 case CMprivate: 1076 p->group->flags |= Pprivatemem; 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 *o; 1255 Progctl *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 if(ctl->bpts == nil) 1458 continue; 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 1470 save: 1471 if(ctl->stop) 1472 strcpy(buf, "stopped"); 1473 1474 p->R = R; 1475 1476 if(env->debug == nil) { 1477 poperror(); 1478 return; 1479 } 1480 1481 if(p == currun()) 1482 delrun(Pdebug); 1483 1484 telldbg(env->debug, buf); 1485 poperror(); 1486 closedbgctl(env->debug, p); 1487 } 1488 1489 Dev progdevtab = { 1490 'p', 1491 "prog", 1492 1493 devreset, 1494 devinit, 1495 devshutdown, 1496 progattach, 1497 progwalk, 1498 progstat, 1499 progopen, 1500 devcreate, 1501 progclose, 1502 progread, 1503 devbread, 1504 progwrite, 1505 devbwrite, 1506 devremove, 1507 progwstat, 1508 }; 1509