1 /* Copyright (c) 1982 Regents of the University of California */ 2 3 static char sccsid[] = "@(#)@(#)eval.c 1.1 12/15/82"; 4 5 /* 6 * Tree evaluation. 7 */ 8 9 #include "defs.h" 10 #include "tree.h" 11 #include "operators.h" 12 #include "eval.h" 13 #include "events.h" 14 #include "symbols.h" 15 #include "scanner.h" 16 #include "source.h" 17 #include "object.h" 18 #include "mappings.h" 19 #include "process.h" 20 #include "machine.h" 21 #include <signal.h> 22 23 #ifndef public 24 25 #include "machine.h" 26 27 #define STACKSIZE 2000 28 29 typedef Char Stack; 30 31 #define push(type, value) { \ 32 ((type *) (sp += sizeof(type)))[-1] = (value); \ 33 } 34 35 #define pop(type) ( \ 36 (*((type *) (sp -= sizeof(type)))) \ 37 ) 38 39 #define alignstack() { \ 40 sp = (Stack *) (( ((int) sp) + sizeof(int) - 1)&~(sizeof(int) - 1)); \ 41 } 42 43 #endif 44 45 public Stack stack[STACKSIZE]; 46 public Stack *sp = &stack[0]; 47 48 #define chksp() \ 49 { \ 50 if (sp < &stack[0]) { \ 51 panic("stack underflow"); \ 52 } \ 53 } 54 55 #define poparg(n, r, fr) { \ 56 eval(p->value.arg[n]); \ 57 if (isreal(p->op)) { \ 58 fr = pop(double); \ 59 } else if (isint(p->op)) { \ 60 r = popsmall(p->value.arg[n]->nodetype); \ 61 } \ 62 } 63 64 #define Boolrep char /* underlying representation type for booleans */ 65 66 /* 67 * Evaluate a parse tree leaving the value on the top of the stack. 68 */ 69 70 public eval(p) 71 register Node p; 72 { 73 long r0, r1; 74 double fr0, fr1; 75 Address addr; 76 long i, n; 77 int len; 78 Symbol s, f; 79 Node n1, n2; 80 Boolean b; 81 File file; 82 83 checkref(p); 84 switch (degree(p->op)) { 85 case BINARY: 86 poparg(1, r1, fr1); 87 poparg(0, r0, fr0); 88 break; 89 90 case UNARY: 91 poparg(0, r0, fr0); 92 break; 93 94 default: 95 /* do nothing */; 96 } 97 switch (p->op) { 98 case O_SYM: 99 s = p->value.sym; 100 if (s == retaddrsym) { 101 push(long, return_addr()); 102 } else { 103 if (isvariable(s)) { 104 if (s != program and not isactive(container(s))) { 105 error("\"%s\" is not active", symname(s)); 106 } 107 push(long, address(s, nil)); 108 } else if (isblock(s)) { 109 push(Symbol, s); 110 } else { 111 error("can't evaluate a %s", classname(s)); 112 } 113 } 114 break; 115 116 case O_LCON: 117 r0 = p->value.lcon; 118 pushsmall(p->nodetype, r0); 119 break; 120 121 case O_FCON: 122 push(double, p->value.fcon); 123 break; 124 125 case O_SCON: 126 len = size(p->nodetype); 127 mov(p->value.scon, sp, len); 128 sp += len; 129 break; 130 131 case O_INDEX: 132 n = pop(long); 133 i = evalindex(p->value.arg[0]->nodetype, 134 popsmall(p->value.arg[1]->nodetype)); 135 push(long, n + i*size(p->nodetype)); 136 break; 137 138 case O_DOT: 139 s = p->value.arg[1]->value.sym; 140 n = lval(p->value.arg[0]); 141 push(long, n + (s->symvalue.field.offset div 8)); 142 break; 143 144 /* 145 * Get the value of the expression addressed by the top of the stack. 146 * Push the result back on the stack. 147 */ 148 149 case O_INDIR: 150 case O_RVAL: 151 addr = pop(long); 152 if (addr == 0) { 153 error("reference through nil pointer"); 154 } 155 if (p->op == O_INDIR) { 156 len = sizeof(long); 157 } else { 158 len = size(p->nodetype); 159 } 160 rpush(addr, len); 161 break; 162 163 case O_COMMA: 164 break; 165 166 case O_ITOF: 167 push(double, (double) r0); 168 break; 169 170 case O_ADD: 171 push(long, r0+r1); 172 break; 173 174 case O_ADDF: 175 push(double, fr0+fr1); 176 break; 177 178 case O_SUB: 179 push(long, r0-r1); 180 break; 181 182 case O_SUBF: 183 push(double, fr0-fr1); 184 break; 185 186 case O_NEG: 187 push(long, -r0); 188 break; 189 190 case O_NEGF: 191 push(double, -fr0); 192 break; 193 194 case O_MUL: 195 push(long, r0*r1); 196 break; 197 198 case O_MULF: 199 push(double, fr0*fr1); 200 break; 201 202 case O_DIVF: 203 if (fr1 == 0) { 204 error("error: division by 0"); 205 } 206 push(double, fr0 / fr1); 207 break; 208 209 case O_DIV: 210 if (r1 == 0) { 211 error("error: div by 0"); 212 } 213 push(long, r0 div r1); 214 break; 215 216 case O_MOD: 217 if (r1 == 0) { 218 error("error: mod by 0"); 219 } 220 push(long, r0 mod r1); 221 break; 222 223 case O_LT: 224 push(Boolrep, r0 < r1); 225 break; 226 227 case O_LTF: 228 push(Boolrep, fr0 < fr1); 229 break; 230 231 case O_LE: 232 push(Boolrep, r0 <= r1); 233 break; 234 235 case O_LEF: 236 push(Boolrep, fr0 <= fr1); 237 break; 238 239 case O_GT: 240 push(Boolrep, r0 > r1); 241 break; 242 243 case O_GTF: 244 push(Boolrep, fr0 > fr1); 245 break; 246 247 case O_EQ: 248 push(Boolrep, r0 == r1); 249 break; 250 251 case O_EQF: 252 push(Boolrep, fr0 == fr1); 253 break; 254 255 case O_NE: 256 push(Boolrep, r0 != r1); 257 break; 258 259 case O_NEF: 260 push(Boolrep, fr0 != fr1); 261 break; 262 263 case O_AND: 264 push(Boolrep, r0 and r1); 265 break; 266 267 case O_OR: 268 push(Boolrep, r0 or r1); 269 break; 270 271 case O_ASSIGN: 272 assign(p->value.arg[0], p->value.arg[1]); 273 break; 274 275 case O_CHFILE: 276 if (p->value.scon == nil) { 277 printf("%s\n", cursource); 278 } else { 279 file = opensource(p->value.scon); 280 if (file == nil) { 281 error("can't read \"%s\"", p->value.scon); 282 } else { 283 fclose(file); 284 setsource(p->value.scon); 285 } 286 } 287 break; 288 289 case O_CONT: 290 cont(); 291 printnews(); 292 break; 293 294 case O_LIST: 295 if (p->value.arg[0]->op == O_SYM) { 296 f = p->value.arg[0]->value.sym; 297 addr = firstline(f); 298 if (addr == NOADDR) { 299 error("no source lines for \"%s\"", symname(f)); 300 } 301 setsource(srcfilename(addr)); 302 r0 = srcline(addr) - 5; 303 r1 = r0 + 10; 304 if (r0 < 1) { 305 r0 = 1; 306 } 307 } else { 308 eval(p->value.arg[0]); 309 r0 = pop(long); 310 eval(p->value.arg[1]); 311 r1 = pop(long); 312 } 313 printlines((Lineno) r0, (Lineno) r1); 314 break; 315 316 case O_FUNC: 317 if (p->value.arg[0] == nil) { 318 printname(stdout, curfunc); 319 putchar('\n'); 320 } else { 321 curfunc = p->value.arg[0]->value.sym; 322 addr = codeloc(curfunc); 323 if (addr != NOADDR) { 324 setsource(srcfilename(addr)); 325 cursrcline = srcline(addr) - 5; 326 if (cursrcline < 1) { 327 cursrcline = 1; 328 } 329 } 330 } 331 break; 332 333 case O_EXAMINE: 334 eval(p->value.examine.beginaddr); 335 r0 = pop(long); 336 if (p->value.examine.endaddr == nil) { 337 n = p->value.examine.count; 338 if (streq(p->value.examine.mode, "i")) { 339 printninst(n, (Address) r0); 340 } else { 341 printndata(n, (Address) r0, p->value.examine.mode); 342 } 343 } else { 344 eval(p->value.examine.endaddr); 345 r1 = pop(long); 346 if (streq(p->value.examine.mode, "i")) { 347 printinst((Address)r0, (Address)r1); 348 } else { 349 printdata((Address)r0, (Address)r1, p->value.examine.mode); 350 } 351 } 352 break; 353 354 case O_PRINT: 355 for (n1 = p->value.arg[0]; n1 != nil; n1 = n1->value.arg[1]) { 356 eval(n1->value.arg[0]); 357 printval(n1->value.arg[0]->nodetype); 358 putchar(' '); 359 } 360 putchar('\n'); 361 break; 362 363 case O_PSYM: 364 if (p->value.arg[0]->op == O_SYM) { 365 psym(p->value.arg[0]->value.sym); 366 } else { 367 psym(p->value.arg[0]->nodetype); 368 } 369 break; 370 371 case O_QLINE: 372 eval(p->value.arg[1]); 373 break; 374 375 case O_STEP: 376 b = inst_tracing; 377 inst_tracing = (Boolean) (not p->value.step.source); 378 if (p->value.step.skipcalls) { 379 next(); 380 } else { 381 stepc(); 382 } 383 inst_tracing = b; 384 printnews(); 385 break; 386 387 case O_WHATIS: 388 if (p->value.arg[0]->op == O_SYM) { 389 printdecl(p->value.arg[0]->value.sym); 390 } else { 391 printdecl(p->value.arg[0]->nodetype); 392 } 393 break; 394 395 case O_WHERE: 396 wherecmd(); 397 break; 398 399 case O_WHEREIS: 400 printwhereis(stdout, p->value.arg[0]->value.sym); 401 break; 402 403 case O_WHICH: 404 printwhich(stdout, p->value.arg[0]->value.sym); 405 putchar('\n'); 406 break; 407 408 case O_ALIAS: 409 n1 = p->value.arg[0]; 410 n2 = p->value.arg[1]; 411 if (n1 == nil) { 412 print_alias(nil); 413 } else if (n2 == nil) { 414 print_alias(n1->value.name); 415 } else { 416 enter_alias(n1->value.name, n2->value.name); 417 } 418 break; 419 420 case O_CALL: 421 callproc(p->value.arg[0], p->value.arg[1]); 422 break; 423 424 case O_CATCH: 425 psigtrace(process, p->value.lcon, true); 426 break; 427 428 case O_EDIT: 429 edit(p->value.scon); 430 break; 431 432 case O_DUMP: 433 dump(); 434 break; 435 436 case O_GRIPE: 437 gripe(); 438 break; 439 440 case O_HELP: 441 help(); 442 break; 443 444 case O_IGNORE: 445 psigtrace(process, p->value.lcon, false); 446 break; 447 448 case O_RUN: 449 run(); 450 break; 451 452 case O_SOURCE: 453 setinput(p->value.scon); 454 break; 455 456 case O_STATUS: 457 status(); 458 break; 459 460 case O_TRACE: 461 case O_TRACEI: 462 trace(p); 463 if (isstdin()) { 464 status(); 465 } 466 break; 467 468 case O_STOP: 469 case O_STOPI: 470 stop(p); 471 if (isstdin()) { 472 status(); 473 } 474 break; 475 476 case O_ADDEVENT: 477 addevent(p->value.event.cond, p->value.event.actions); 478 break; 479 480 case O_DELETE: 481 delevent((unsigned int) p->value.lcon); 482 break; 483 484 case O_ENDX: 485 endprogram(); 486 break; 487 488 case O_IF: 489 if (cond(p->value.event.cond)) { 490 evalcmdlist(p->value.event.actions); 491 } 492 break; 493 494 case O_ONCE: 495 event_once(p->value.event.cond, p->value.event.actions); 496 break; 497 498 case O_PRINTCALL: 499 printcall(p->value.sym, whatblock(return_addr())); 500 break; 501 502 case O_PRINTIFCHANGED: 503 printifchanged(p->value.arg[0]); 504 break; 505 506 case O_PRINTRTN: 507 printrtn(p->value.sym); 508 break; 509 510 case O_PRINTSRCPOS: 511 getsrcpos(); 512 if (p->value.arg[0] == nil) { 513 printsrcpos(); 514 putchar('\n'); 515 printlines(curline, curline); 516 } else if (p->value.arg[0]->op == O_QLINE) { 517 if (p->value.arg[0]->value.arg[1]->value.lcon == 0) { 518 printf("tracei: "); 519 printinst(pc, pc); 520 } else { 521 printf("trace: "); 522 printlines(curline, curline); 523 } 524 } else { 525 printsrcpos(); 526 printf(": "); 527 eval(p->value.arg[0]); 528 prtree(stdout, p->value.arg[0]); 529 printf(" = "); 530 printval(p->value.arg[0]->nodetype); 531 putchar('\n'); 532 } 533 break; 534 535 case O_PROCRTN: 536 procreturn(p->value.sym); 537 break; 538 539 case O_STOPIFCHANGED: 540 stopifchanged(p->value.arg[0]); 541 break; 542 543 case O_STOPX: 544 isstopped = true; 545 break; 546 547 case O_TRACEON: 548 traceon(p->value.trace.inst, p->value.trace.event, 549 p->value.trace.actions); 550 break; 551 552 case O_TRACEOFF: 553 traceoff(p->value.lcon); 554 break; 555 556 default: 557 panic("eval: bad op %d", p->op); 558 } 559 } 560 561 /* 562 * Evaluate a list of commands. 563 */ 564 565 public evalcmdlist(cl) 566 Cmdlist cl; 567 { 568 Command c; 569 570 foreach (Command, c, cl) 571 evalcmd(c); 572 endfor 573 } 574 575 /* 576 * Push "len" bytes onto the expression stack from address "addr" 577 * in the process. If there isn't room on the stack, print an error message. 578 */ 579 580 public rpush(addr, len) 581 Address addr; 582 int len; 583 { 584 if (not canpush(len)) { 585 error("expression too large to evaluate"); 586 } else { 587 chksp(); 588 dread(sp, addr, len); 589 sp += len; 590 } 591 } 592 593 /* 594 * Check if the stack has n bytes available. 595 */ 596 597 public Boolean canpush(n) 598 Integer n; 599 { 600 return (Boolean) (sp + n < &stack[STACKSIZE]); 601 } 602 603 /* 604 * Push a small scalar of the given type onto the stack. 605 */ 606 607 public pushsmall(t, v) 608 Symbol t; 609 long v; 610 { 611 register Integer s; 612 613 s = size(t); 614 switch (s) { 615 case sizeof(char): 616 push(char, v); 617 break; 618 619 case sizeof(short): 620 push(short, v); 621 break; 622 623 case sizeof(long): 624 push(long, v); 625 break; 626 627 default: 628 panic("bad size %d in popsmall", s); 629 } 630 } 631 632 /* 633 * Pop an item of the given type which is assumed to be no larger 634 * than a long and return it expanded into a long. 635 */ 636 637 public long popsmall(t) 638 Symbol t; 639 { 640 long r; 641 642 switch (size(t)) { 643 case sizeof(char): 644 r = (long) pop(char); 645 break; 646 647 case sizeof(short): 648 r = (long) pop(short); 649 break; 650 651 case sizeof(long): 652 r = pop(long); 653 break; 654 655 default: 656 panic("popsmall: size is %d", size(t)); 657 } 658 return r; 659 } 660 661 /* 662 * Evaluate a conditional expression. 663 */ 664 665 public Boolean cond(p) 666 Node p; 667 { 668 register Boolean b; 669 670 if (p == nil) { 671 b = true; 672 } else { 673 eval(p); 674 b = pop(Boolean); 675 } 676 return b; 677 } 678 679 /* 680 * Return the address corresponding to a given tree. 681 */ 682 683 public Address lval(p) 684 Node p; 685 { 686 if (p->op == O_RVAL) { 687 eval(p->value.arg[0]); 688 } else { 689 eval(p); 690 } 691 return (Address) (pop(long)); 692 } 693 694 /* 695 * Process a trace command, translating into the appropriate events 696 * and associated actions. 697 */ 698 699 public trace(p) 700 Node p; 701 { 702 Node exp, place, cond; 703 Node left; 704 705 exp = p->value.arg[0]; 706 place = p->value.arg[1]; 707 cond = p->value.arg[2]; 708 if (exp == nil) { 709 traceall(p->op, place, cond); 710 } else if (exp->op == O_QLINE) { 711 traceinst(p->op, exp, cond); 712 } else if (place != nil and place->op == O_QLINE) { 713 traceat(p->op, exp, place, cond); 714 } else { 715 left = (exp->op == O_RVAL) ? exp->value.arg[0] : exp; 716 if (left->op == O_SYM and isblock(left->value.sym)) { 717 traceproc(p->op, left->value.sym, place, cond); 718 } else { 719 tracedata(p->op, exp, place, cond); 720 } 721 } 722 } 723 724 /* 725 * Set a breakpoint that will turn on tracing. 726 */ 727 728 private traceall(op, place, cond) 729 Operator op; 730 Node place; 731 Node cond; 732 { 733 Symbol s; 734 Node event; 735 Command action; 736 737 if (place == nil) { 738 s = program; 739 } else { 740 s = place->value.sym; 741 } 742 event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s)); 743 action = build(O_PRINTSRCPOS, 744 build(O_QLINE, nil, build(O_LCON, (op == O_TRACE) ? 1 : 0))); 745 if (cond != nil) { 746 action = build(O_IF, cond, buildcmdlist(action)); 747 } 748 action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action)); 749 action->value.trace.event = addevent(event, buildcmdlist(action)); 750 } 751 752 /* 753 * Set up the appropriate breakpoint for tracing an instruction. 754 */ 755 756 private traceinst(op, exp, cond) 757 Operator op; 758 Node exp; 759 Node cond; 760 { 761 Node event; 762 Command action; 763 764 if (op == O_TRACEI) { 765 event = build(O_EQ, build(O_SYM, pcsym), exp); 766 } else { 767 event = build(O_EQ, build(O_SYM, linesym), exp); 768 } 769 action = build(O_PRINTSRCPOS, exp); 770 if (cond) { 771 action = build(O_IF, cond, buildcmdlist(action)); 772 } 773 addevent(event, buildcmdlist(action)); 774 } 775 776 /* 777 * Set a breakpoint to print an expression at a given line or address. 778 */ 779 780 private traceat(op, exp, place, cond) 781 Operator op; 782 Node exp; 783 Node place; 784 Node cond; 785 { 786 Node event; 787 Command action; 788 789 if (op == O_TRACEI) { 790 event = build(O_EQ, build(O_SYM, pcsym), place); 791 } else { 792 event = build(O_EQ, build(O_SYM, linesym), place); 793 } 794 action = build(O_PRINTSRCPOS, exp); 795 if (cond != nil) { 796 action = build(O_IF, cond, buildcmdlist(action)); 797 } 798 addevent(event, buildcmdlist(action)); 799 } 800 801 /* 802 * Construct event for tracing a procedure. 803 * 804 * What we want here is 805 * 806 * when $proc = p do 807 * if <condition> then 808 * printcall; 809 * once $pc = $retaddr do 810 * printrtn; 811 * end; 812 * end if; 813 * end; 814 * 815 * Note that "once" is like "when" except that the event 816 * deletes itself as part of its associated action. 817 */ 818 819 private traceproc(op, p, place, cond) 820 Operator op; 821 Symbol p; 822 Node place; 823 Node cond; 824 { 825 Node event; 826 Command action; 827 Cmdlist actionlist; 828 829 action = build(O_PRINTCALL, p); 830 actionlist = list_alloc(); 831 cmdlist_append(action, actionlist); 832 event = build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)); 833 action = build(O_ONCE, event, buildcmdlist(build(O_PRINTRTN, p))); 834 cmdlist_append(action, actionlist); 835 if (cond != nil) { 836 actionlist = buildcmdlist(build(O_IF, cond, actionlist)); 837 } 838 event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p)); 839 addevent(event, actionlist); 840 } 841 842 /* 843 * Set up breakpoint for tracing data. 844 */ 845 846 private tracedata(op, exp, place, cond) 847 Operator op; 848 Node exp; 849 Node place; 850 Node cond; 851 { 852 Symbol p; 853 Node event; 854 Command action; 855 856 p = (place == nil) ? tcontainer(exp) : place->value.sym; 857 if (p == nil) { 858 p = program; 859 } 860 action = build(O_PRINTIFCHANGED, exp); 861 if (cond != nil) { 862 action = build(O_IF, cond, buildcmdlist(action)); 863 } 864 action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action)); 865 event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p)); 866 action->value.trace.event = addevent(event, buildcmdlist(action)); 867 } 868 869 /* 870 * Setting and unsetting of stops. 871 */ 872 873 public stop(p) 874 Node p; 875 { 876 Node exp, place, cond; 877 Symbol s; 878 Command action; 879 880 exp = p->value.arg[0]; 881 place = p->value.arg[1]; 882 cond = p->value.arg[2]; 883 if (exp != nil) { 884 stopvar(p->op, exp, place, cond); 885 } else if (cond != nil) { 886 s = (place == nil) ? program : place->value.sym; 887 action = build(O_IF, cond, buildcmdlist(build(O_STOPX))); 888 action = build(O_TRACEON, (p->op == O_STOPI), buildcmdlist(action)); 889 cond = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s)); 890 action->value.trace.event = addevent(cond, buildcmdlist(action)); 891 } else if (place->op == O_SYM) { 892 s = place->value.sym; 893 cond = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s)); 894 addevent(cond, buildcmdlist(build(O_STOPX))); 895 } else { 896 stopinst(p->op, place, cond); 897 } 898 } 899 900 private stopinst(op, place, cond) 901 Operator op; 902 Node place; 903 Node cond; 904 { 905 Node event; 906 907 if (op == O_STOP) { 908 event = build(O_EQ, build(O_SYM, linesym), place); 909 } else { 910 event = build(O_EQ, build(O_SYM, pcsym), place); 911 } 912 addevent(event, buildcmdlist(build(O_STOPX))); 913 } 914 915 /* 916 * Implement stopping on assignment to a variable by adding it to 917 * the variable list. 918 */ 919 920 private stopvar(op, exp, place, cond) 921 Operator op; 922 Node exp; 923 Node place; 924 Node cond; 925 { 926 Symbol p; 927 Node event; 928 Command action; 929 930 p = (place == nil) ? tcontainer(exp) : place->value.sym; 931 if (p == nil) { 932 p = program; 933 } 934 action = build(O_IF, cond, buildcmdlist(build(O_STOPIFCHANGED, exp))); 935 action = build(O_TRACEON, (op == O_STOPI), buildcmdlist(action)); 936 event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p)); 937 action->value.trace.event = addevent(event, buildcmdlist(action)); 938 } 939 940 /* 941 * Assign the value of an expression to a variable (or term). 942 */ 943 944 public assign(var, exp) 945 Node var; 946 Node exp; 947 { 948 Address addr; 949 int varsize; 950 char cvalue; 951 short svalue; 952 long lvalue; 953 954 if (not compatible(var->nodetype, exp->nodetype)) { 955 error("incompatible types"); 956 } 957 addr = lval(var); 958 eval(exp); 959 varsize = size(var->nodetype); 960 if (varsize < sizeof(long)) { 961 lvalue = pop(long); 962 switch (varsize) { 963 case sizeof(char): 964 cvalue = lvalue; 965 dwrite(&cvalue, addr, varsize); 966 break; 967 968 case sizeof(short): 969 svalue = lvalue; 970 dwrite(&svalue, addr, varsize); 971 break; 972 973 default: 974 panic("bad size %d", varsize); 975 } 976 } else { 977 sp -= varsize; 978 dwrite(sp, addr, varsize); 979 } 980 } 981 982 #define DEF_EDITOR "vi" 983 984 /* 985 * Invoke an editor on the given file. Which editor to use might change 986 * installation to installation. For now, we use "vi". In any event, 987 * the environment variable "EDITOR" overrides any default. 988 */ 989 990 public edit(filename) 991 String filename; 992 { 993 extern String getenv(); 994 String ed, src; 995 File f; 996 Symbol s; 997 Address addr; 998 char buff[10]; 999 1000 ed = getenv("EDITOR"); 1001 if (ed == nil) { 1002 ed = DEF_EDITOR; 1003 } 1004 if (filename == nil) { 1005 call(ed, stdin, stdout, cursource, nil); 1006 } else { 1007 f = fopen(filename, "r"); 1008 if (f == nil) { 1009 s = which(identname(filename, true)); 1010 if (not isblock(s)) { 1011 error("can't read \"%s\"", filename); 1012 } 1013 addr = firstline(s); 1014 if (addr == NOADDR) { 1015 error("no source for \"%s\"", filename); 1016 } 1017 src = srcfilename(addr); 1018 sprintf(buff, "+%d", srcline(addr)); 1019 call(ed, stdin, stdout, buff, src, nil); 1020 } else { 1021 fclose(f); 1022 call(ed, stdin, stdout, filename, nil); 1023 } 1024 } 1025 } 1026 1027 /* 1028 * Send some nasty mail to the current support person. 1029 */ 1030 1031 public gripe() 1032 { 1033 typedef Operation(); 1034 Operation *old; 1035 1036 char *maintainer = "linton@ucbarpa"; 1037 1038 puts("Type control-D to end your message. Be sure to include"); 1039 puts("your name and the name of the file you are debugging."); 1040 putchar('\n'); 1041 old = signal(SIGINT, SIG_DFL); 1042 call("Mail", stdin, stdout, maintainer, nil); 1043 signal(SIGINT, old); 1044 puts("Thank you."); 1045 } 1046 1047 /* 1048 * Give the user some help. 1049 */ 1050 1051 public help() 1052 { 1053 puts("run - begin execution of the program"); 1054 puts("cont - continue execution"); 1055 puts("step - single step one line"); 1056 puts("next - step to next line (skip over calls)"); 1057 puts("trace <line#> - trace execution of the line"); 1058 puts("trace <proc> - trace calls to the procedure"); 1059 puts("trace <var> - trace changes to the variable"); 1060 puts("trace <exp> at <line#> - print <exp> when <line> is reached"); 1061 puts("stop at <line> - suspend execution at the line"); 1062 puts("stop in <proc> - suspend execution when <proc> is called"); 1063 puts("status - print trace/stop's in effect"); 1064 puts("delete <number> - remove trace or stop of given number"); 1065 puts("call <proc> - call the procedure"); 1066 puts("where - print currently active procedures"); 1067 puts("print <exp> - print the value of the expression"); 1068 puts("whatis <name> - print the declaration of the name"); 1069 puts("list <line>, <line> - list source lines"); 1070 puts("edit <proc> - edit file containing <proc>"); 1071 puts("gripe - send mail to the person in charge of dbx"); 1072 puts("quit - exit dbx"); 1073 } 1074 1075 /* 1076 * Divert output to the given file name. 1077 * Cannot redirect to an existing file. 1078 */ 1079 1080 private int so_fd; 1081 private Boolean notstdout; 1082 1083 public setout(filename) 1084 String filename; 1085 { 1086 File f; 1087 1088 f = fopen(filename, "r"); 1089 if (f != nil) { 1090 fclose(f); 1091 error("%s: file already exists", filename); 1092 } else { 1093 so_fd = dup(1); 1094 close(1); 1095 if (creat(filename, 0666) == nil) { 1096 unsetout(); 1097 error("can't create %s", filename); 1098 } 1099 notstdout = true; 1100 } 1101 } 1102 1103 /* 1104 * Revert output to standard output. 1105 */ 1106 1107 public unsetout() 1108 { 1109 fflush(stdout); 1110 close(1); 1111 if (dup(so_fd) != 1) { 1112 panic("standard out dup failed"); 1113 } 1114 close(so_fd); 1115 notstdout = false; 1116 } 1117 1118 /* 1119 * Determine is standard output is currently being redirected 1120 * to a file (as far as we know). 1121 */ 1122 1123 public Boolean isredirected() 1124 { 1125 return notstdout; 1126 } 1127