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