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