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