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