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