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