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