1 /* Copyright (c) 1982 Regents of the University of California */ 2 3 static char sccsid[] = "@(#)eval.c 1.3 12/20/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; 716 if (left->op == O_RVAL or left->op == O_CALL) { 717 left = left->value.arg[0]; 718 } 719 if (left->op == O_SYM and isblock(left->value.sym)) { 720 traceproc(p->op, left->value.sym, place, cond); 721 } else { 722 tracedata(p->op, exp, place, cond); 723 } 724 } 725 } 726 727 /* 728 * Set a breakpoint that will turn on tracing. 729 */ 730 731 private traceall(op, place, cond) 732 Operator op; 733 Node place; 734 Node cond; 735 { 736 Symbol s; 737 Node event; 738 Command action; 739 740 if (place == nil) { 741 s = program; 742 } else { 743 s = place->value.sym; 744 } 745 event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s)); 746 action = build(O_PRINTSRCPOS, 747 build(O_QLINE, nil, build(O_LCON, (op == O_TRACE) ? 1 : 0))); 748 if (cond != nil) { 749 action = build(O_IF, cond, buildcmdlist(action)); 750 } 751 action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action)); 752 action->value.trace.event = addevent(event, buildcmdlist(action)); 753 } 754 755 /* 756 * Set up the appropriate breakpoint for tracing an instruction. 757 */ 758 759 private traceinst(op, exp, cond) 760 Operator op; 761 Node exp; 762 Node cond; 763 { 764 Node event; 765 Command action; 766 767 if (op == O_TRACEI) { 768 event = build(O_EQ, build(O_SYM, pcsym), exp); 769 } else { 770 event = build(O_EQ, build(O_SYM, linesym), exp); 771 } 772 action = build(O_PRINTSRCPOS, exp); 773 if (cond) { 774 action = build(O_IF, cond, buildcmdlist(action)); 775 } 776 addevent(event, buildcmdlist(action)); 777 } 778 779 /* 780 * Set a breakpoint to print an expression at a given line or address. 781 */ 782 783 private traceat(op, exp, place, cond) 784 Operator op; 785 Node exp; 786 Node place; 787 Node cond; 788 { 789 Node event; 790 Command action; 791 792 if (op == O_TRACEI) { 793 event = build(O_EQ, build(O_SYM, pcsym), place); 794 } else { 795 event = build(O_EQ, build(O_SYM, linesym), place); 796 } 797 action = build(O_PRINTSRCPOS, exp); 798 if (cond != nil) { 799 action = build(O_IF, cond, buildcmdlist(action)); 800 } 801 addevent(event, buildcmdlist(action)); 802 } 803 804 /* 805 * Construct event for tracing a procedure. 806 * 807 * What we want here is 808 * 809 * when $proc = p do 810 * if <condition> then 811 * printcall; 812 * once $pc = $retaddr do 813 * printrtn; 814 * end; 815 * end if; 816 * end; 817 * 818 * Note that "once" is like "when" except that the event 819 * deletes itself as part of its associated action. 820 */ 821 822 private traceproc(op, p, place, cond) 823 Operator op; 824 Symbol p; 825 Node place; 826 Node cond; 827 { 828 Node event; 829 Command action; 830 Cmdlist actionlist; 831 832 action = build(O_PRINTCALL, p); 833 actionlist = list_alloc(); 834 cmdlist_append(action, actionlist); 835 event = build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)); 836 action = build(O_ONCE, event, buildcmdlist(build(O_PRINTRTN, p))); 837 cmdlist_append(action, actionlist); 838 if (cond != nil) { 839 actionlist = buildcmdlist(build(O_IF, cond, actionlist)); 840 } 841 event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p)); 842 addevent(event, actionlist); 843 } 844 845 /* 846 * Set up breakpoint for tracing data. 847 */ 848 849 private tracedata(op, exp, place, cond) 850 Operator op; 851 Node exp; 852 Node place; 853 Node cond; 854 { 855 Symbol p; 856 Node event; 857 Command action; 858 859 p = (place == nil) ? tcontainer(exp) : place->value.sym; 860 if (p == nil) { 861 p = program; 862 } 863 action = build(O_PRINTIFCHANGED, exp); 864 if (cond != nil) { 865 action = build(O_IF, cond, buildcmdlist(action)); 866 } 867 action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action)); 868 event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p)); 869 action->value.trace.event = addevent(event, buildcmdlist(action)); 870 } 871 872 /* 873 * Setting and unsetting of stops. 874 */ 875 876 public stop(p) 877 Node p; 878 { 879 Node exp, place, cond; 880 Symbol s; 881 Command action; 882 883 exp = p->value.arg[0]; 884 place = p->value.arg[1]; 885 cond = p->value.arg[2]; 886 if (exp != nil) { 887 stopvar(p->op, exp, place, cond); 888 } else if (cond != nil) { 889 s = (place == nil) ? program : place->value.sym; 890 action = build(O_IF, cond, buildcmdlist(build(O_STOPX))); 891 action = build(O_TRACEON, (p->op == O_STOPI), buildcmdlist(action)); 892 cond = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s)); 893 action->value.trace.event = addevent(cond, buildcmdlist(action)); 894 } else if (place->op == O_SYM) { 895 s = place->value.sym; 896 cond = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s)); 897 addevent(cond, buildcmdlist(build(O_STOPX))); 898 } else { 899 stopinst(p->op, place, cond); 900 } 901 } 902 903 private stopinst(op, place, cond) 904 Operator op; 905 Node place; 906 Node cond; 907 { 908 Node event; 909 910 if (op == O_STOP) { 911 event = build(O_EQ, build(O_SYM, linesym), place); 912 } else { 913 event = build(O_EQ, build(O_SYM, pcsym), place); 914 } 915 addevent(event, buildcmdlist(build(O_STOPX))); 916 } 917 918 /* 919 * Implement stopping on assignment to a variable by adding it to 920 * the variable list. 921 */ 922 923 private stopvar(op, exp, place, cond) 924 Operator op; 925 Node exp; 926 Node place; 927 Node cond; 928 { 929 Symbol p; 930 Node event; 931 Command action; 932 933 p = (place == nil) ? tcontainer(exp) : place->value.sym; 934 if (p == nil) { 935 p = program; 936 } 937 action = build(O_IF, cond, buildcmdlist(build(O_STOPIFCHANGED, exp))); 938 action = build(O_TRACEON, (op == O_STOPI), buildcmdlist(action)); 939 event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p)); 940 action->value.trace.event = addevent(event, buildcmdlist(action)); 941 } 942 943 /* 944 * Assign the value of an expression to a variable (or term). 945 */ 946 947 public assign(var, exp) 948 Node var; 949 Node exp; 950 { 951 Address addr; 952 int varsize; 953 char cvalue; 954 short svalue; 955 long lvalue; 956 957 if (not compatible(var->nodetype, exp->nodetype)) { 958 error("incompatible types"); 959 } 960 addr = lval(var); 961 eval(exp); 962 varsize = size(var->nodetype); 963 if (varsize < sizeof(long)) { 964 lvalue = pop(long); 965 switch (varsize) { 966 case sizeof(char): 967 cvalue = lvalue; 968 dwrite(&cvalue, addr, varsize); 969 break; 970 971 case sizeof(short): 972 svalue = lvalue; 973 dwrite(&svalue, addr, varsize); 974 break; 975 976 default: 977 panic("bad size %d", varsize); 978 } 979 } else { 980 sp -= varsize; 981 dwrite(sp, addr, varsize); 982 } 983 } 984 985 #define DEF_EDITOR "vi" 986 987 /* 988 * Invoke an editor on the given file. Which editor to use might change 989 * installation to installation. For now, we use "vi". In any event, 990 * the environment variable "EDITOR" overrides any default. 991 */ 992 993 public edit(filename) 994 String filename; 995 { 996 extern String getenv(); 997 String ed, src; 998 File f; 999 Symbol s; 1000 Address addr; 1001 char buff[10]; 1002 1003 ed = getenv("EDITOR"); 1004 if (ed == nil) { 1005 ed = DEF_EDITOR; 1006 } 1007 if (filename == nil) { 1008 call(ed, stdin, stdout, cursource, nil); 1009 } else { 1010 f = fopen(filename, "r"); 1011 if (f == nil) { 1012 s = which(identname(filename, true)); 1013 if (not isblock(s)) { 1014 error("can't read \"%s\"", filename); 1015 } 1016 addr = firstline(s); 1017 if (addr == NOADDR) { 1018 error("no source for \"%s\"", filename); 1019 } 1020 src = srcfilename(addr); 1021 sprintf(buff, "+%d", srcline(addr)); 1022 call(ed, stdin, stdout, buff, src, nil); 1023 } else { 1024 fclose(f); 1025 call(ed, stdin, stdout, filename, nil); 1026 } 1027 } 1028 } 1029 1030 /* 1031 * Send some nasty mail to the current support person. 1032 */ 1033 1034 public gripe() 1035 { 1036 typedef Operation(); 1037 Operation *old; 1038 1039 char *maintainer = "linton@ucbarpa"; 1040 1041 puts("Type control-D to end your message. Be sure to include"); 1042 puts("your name and the name of the file you are debugging."); 1043 putchar('\n'); 1044 old = signal(SIGINT, SIG_DFL); 1045 call("Mail", stdin, stdout, maintainer, nil); 1046 signal(SIGINT, old); 1047 puts("Thank you."); 1048 } 1049 1050 /* 1051 * Give the user some help. 1052 */ 1053 1054 public help() 1055 { 1056 puts("run - begin execution of the program"); 1057 puts("cont - continue execution"); 1058 puts("step - single step one line"); 1059 puts("next - step to next line (skip over calls)"); 1060 puts("trace <line#> - trace execution of the line"); 1061 puts("trace <proc> - trace calls to the procedure"); 1062 puts("trace <var> - trace changes to the variable"); 1063 puts("trace <exp> at <line#> - print <exp> when <line> is reached"); 1064 puts("stop at <line> - suspend execution at the line"); 1065 puts("stop in <proc> - suspend execution when <proc> is called"); 1066 puts("status - print trace/stop's in effect"); 1067 puts("delete <number> - remove trace or stop of given number"); 1068 puts("call <proc> - call the procedure"); 1069 puts("where - print currently active procedures"); 1070 puts("print <exp> - print the value of the expression"); 1071 puts("whatis <name> - print the declaration of the name"); 1072 puts("list <line>, <line> - list source lines"); 1073 puts("edit <proc> - edit file containing <proc>"); 1074 puts("gripe - send mail to the person in charge of dbx"); 1075 puts("quit - exit dbx"); 1076 } 1077 1078 /* 1079 * Divert output to the given file name. 1080 * Cannot redirect to an existing file. 1081 */ 1082 1083 private int so_fd; 1084 private Boolean notstdout; 1085 1086 public setout(filename) 1087 String filename; 1088 { 1089 File f; 1090 1091 f = fopen(filename, "r"); 1092 if (f != nil) { 1093 fclose(f); 1094 error("%s: file already exists", filename); 1095 } else { 1096 so_fd = dup(1); 1097 close(1); 1098 if (creat(filename, 0666) == nil) { 1099 unsetout(); 1100 error("can't create %s", filename); 1101 } 1102 notstdout = true; 1103 } 1104 } 1105 1106 /* 1107 * Revert output to standard output. 1108 */ 1109 1110 public unsetout() 1111 { 1112 fflush(stdout); 1113 close(1); 1114 if (dup(so_fd) != 1) { 1115 panic("standard out dup failed"); 1116 } 1117 close(so_fd); 1118 notstdout = false; 1119 } 1120 1121 /* 1122 * Determine is standard output is currently being redirected 1123 * to a file (as far as we know). 1124 */ 1125 1126 public Boolean isredirected() 1127 { 1128 return notstdout; 1129 } 1130