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