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