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