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