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