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