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