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.3 (Berkeley) 6/21/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: }