|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1985 The Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted ! 6: * provided that: (1) source distributions retain this entire copyright ! 7: * notice and comment, and (2) distributions including binaries display ! 8: * the following acknowledgement: ``This product includes software ! 9: * developed by the University of California, Berkeley and its contributors'' ! 10: * in the documentation or other materials provided with the distribution ! 11: * and in all advertising materials mentioning features or use of this ! 12: * software. Neither the name of the University nor the names of its ! 13: * contributors may be used to endorse or promote products derived ! 14: * from this software without specific prior written permission. ! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 16: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 18: */ ! 19: ! 20: #ifndef lint ! 21: static char sccsid[] = "@(#)runtime.tahoe.c 5.5 (Berkeley) 6/1/90"; ! 22: #endif /* not lint */ ! 23: ! 24: /* ! 25: * Runtime organization dependent routines, mostly dealing with ! 26: * activation records. ! 27: */ ! 28: ! 29: #include "defs.h" ! 30: #include "runtime.h" ! 31: #include "process.h" ! 32: #include "machine.h" ! 33: #include "events.h" ! 34: #include "mappings.h" ! 35: #include "symbols.h" ! 36: #include "tree.h" ! 37: #include "eval.h" ! 38: #include "operators.h" ! 39: #include "object.h" ! 40: ! 41: #ifndef public ! 42: #include "machine.h" ! 43: ! 44: typedef struct Frame { ! 45: Address save_pc; /* program counter */ ! 46: integer mask:16; /* register save mask */ ! 47: integer removed:16; /* 4*number of arguments + 4 */ ! 48: Address save_fp; /* frame pointer */ ! 49: #define NSAVEREG 13 ! 50: Word save_reg[NSAVEREG]; /* not necessarily there */ ! 51: } *Frame; ! 52: #endif ! 53: ! 54: private Frame curframe = nil; ! 55: private struct Frame curframerec; ! 56: private Boolean walkingstack = false; ! 57: ! 58: #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp) ! 59: ! 60: #define inSignalHandler(addr) \ ! 61: (((addr) < 0xc0000000) and ((addr) > 0xc0000000 - 0x400 * UPAGES)) ! 62: ! 63: typedef struct { ! 64: Node callnode; ! 65: Node cmdnode; ! 66: boolean isfunc; ! 67: } CallEnv; ! 68: ! 69: private CallEnv endproc; ! 70: ! 71: /* ! 72: * Set a frame to the current activation record. ! 73: */ ! 74: ! 75: private getcurframe(frp) ! 76: Frame frp; ! 77: { ! 78: register int i; ! 79: long x; ! 80: ! 81: checkref(frp); ! 82: frp->save_fp = reg(FRP); ! 83: dread(&x, frp->save_fp-4, 4); ! 84: frp->mask = x >> 16; ! 85: frp->removed = x & 0xffff; ! 86: frp->save_pc = reg(PROGCTR); ! 87: for (i = 0; i < NSAVEREG; i++) { ! 88: frp->save_reg[i] = reg(i); ! 89: } ! 90: } ! 91: ! 92: /* ! 93: * Get the saved registers from one frame to another ! 94: * given mask specifying which registers were actually saved. ! 95: */ ! 96: ! 97: #define bis(b, n) ((b & (1 << (n))) != 0) ! 98: ! 99: private getsaveregs (newfrp, frp, mask) ! 100: Frame newfrp, frp; ! 101: integer mask; ! 102: { ! 103: integer i, j; ! 104: ! 105: j = 0; ! 106: for (i = 0; i < NSAVEREG; i++) { ! 107: if (bis(mask, i)) { ! 108: newfrp->save_reg[i] = frp->save_reg[j]; ! 109: ++j; ! 110: } ! 111: } ! 112: } ! 113: ! 114: /* ! 115: * Return a pointer to the next activation record up the stack. ! 116: * Return nil if there is none. ! 117: * Writes over space pointed to by given argument. ! 118: */ ! 119: ! 120: private Frame nextframe(frp) ! 121: Frame frp; ! 122: { ! 123: Frame newfrp; ! 124: struct Frame frame; ! 125: long x; ! 126: Address prev_frame, callpc; ! 127: static integer ntramp = 0; ! 128: ! 129: newfrp = frp; ! 130: prev_frame = frp->save_fp; ! 131: ! 132: /* ! 133: * The check for interrupt generated frames is taken from adb with only ! 134: * partial understanding. If you're in "sub" and on a sigxxx "sigsub" ! 135: * gets control, then the stack does NOT look like <main, sub, sigsub>. ! 136: * ! 137: * As best I can make out it looks like: ! 138: * ! 139: * <main, (machine check exception block + sub), sysframe, sigsub>. ! 140: * ! 141: * When the signal occurs an exception block and a frame for the routine ! 142: * in which it occured are pushed on the user stack. Then another frame ! 143: * is pushed corresponding to a call from the kernel to sigsub. ! 144: * ! 145: * The addr in sub at which the exception occured is not in sub.save_pc ! 146: * but in the machine check exception block. It is at the magic address ! 147: * fp + 84. ! 148: * ! 149: * The current approach ignores the sys_frame (what adb reports as sigtramp) ! 150: * and takes the pc for sub from the exception block. This allows the ! 151: * "where" command to report <main, sub, sigsub>, which seems reasonable. ! 152: */ ! 153: ! 154: nextf: ! 155: dread(&frame, prev_frame-8, sizeof(struct Frame)); ! 156: if (ntramp == 1) { ! 157: dread(&callpc, prev_frame+44, sizeof(callpc)); ! 158: } else { ! 159: callpc = frame.save_pc; ! 160: } ! 161: if (frame.save_fp == nil or frame.save_pc == (Address) -1) { ! 162: newfrp = nil; ! 163: } else if (inSignalHandler(callpc)) { ! 164: ntramp++; ! 165: prev_frame = frame.save_fp; ! 166: goto nextf; ! 167: } else { ! 168: ntramp = 0; ! 169: getsaveregs(newfrp, &frame, frame.mask); ! 170: dread(&x, frame.save_fp-4, sizeof (x)); ! 171: newfrp->mask = x >> 16; ! 172: newfrp->removed = x & 0xffff; ! 173: newfrp->save_fp = frame.save_fp; ! 174: newfrp->save_pc = callpc; ! 175: } ! 176: return newfrp; ! 177: } ! 178: ! 179: /* ! 180: * Get the current frame information in the given Frame and store the ! 181: * associated function in the given value-result parameter. ! 182: */ ! 183: ! 184: private getcurfunc (frp, fp) ! 185: Frame frp; ! 186: Symbol *fp; ! 187: { ! 188: getcurframe(frp); ! 189: *fp = whatblock(frp->save_pc); ! 190: } ! 191: ! 192: /* ! 193: * Return the frame associated with the next function up the call stack, or ! 194: * nil if there is none. The function is returned in a value-result parameter. ! 195: * For "inline" functions the statically outer function and same frame ! 196: * are returned. ! 197: */ ! 198: ! 199: public Frame nextfunc (frp, fp) ! 200: Frame frp; ! 201: Symbol *fp; ! 202: { ! 203: Symbol t; ! 204: Frame nfrp; ! 205: ! 206: t = *fp; ! 207: checkref(t); ! 208: if (isinline(t)) { ! 209: t = container(t); ! 210: nfrp = frp; ! 211: } else { ! 212: nfrp = nextframe(frp); ! 213: if (nfrp == nil) { ! 214: t = nil; ! 215: } else { ! 216: t = whatblock(nfrp->save_pc); ! 217: } ! 218: } ! 219: *fp = t; ! 220: return nfrp; ! 221: } ! 222: ! 223: /* ! 224: * Return the frame associated with the given function. ! 225: * If the function is nil, return the most recently activated frame. ! 226: * ! 227: * Static allocation for the frame. ! 228: */ ! 229: ! 230: public Frame findframe(f) ! 231: Symbol f; ! 232: { ! 233: Frame frp; ! 234: static struct Frame frame; ! 235: Symbol p; ! 236: Boolean done; ! 237: ! 238: frp = &frame; ! 239: getcurframe(frp); ! 240: if (f != nil) { ! 241: if (f == curfunc and curframe != nil) { ! 242: *frp = *curframe; ! 243: } else { ! 244: done = false; ! 245: p = whatblock(frp->save_pc); ! 246: do { ! 247: if (p == f) { ! 248: done = true; ! 249: } else if (p == program) { ! 250: done = true; ! 251: frp = nil; ! 252: } else { ! 253: frp = nextfunc(frp, &p); ! 254: if (frp == nil) { ! 255: done = true; ! 256: } ! 257: } ! 258: } while (not done); ! 259: } ! 260: } ! 261: return frp; ! 262: } ! 263: ! 264: /* ! 265: * Set the registers according to the given frame pointer. ! 266: */ ! 267: ! 268: public getnewregs (addr) ! 269: Address addr; ! 270: { ! 271: struct Frame frame; ! 272: integer i, j, mask; ! 273: ! 274: dread(&frame, addr-8, sizeof(frame)); ! 275: setreg(FRP, frame.save_fp); ! 276: setreg(PROGCTR, frame.save_pc); ! 277: mask = frame.mask; ! 278: j = 0; ! 279: for (i = 0; i < NSAVEREG; i++) { ! 280: if (bis(mask, i)) { ! 281: setreg(i, frame.save_reg[j]); ! 282: ++j; ! 283: } ! 284: } ! 285: pc = frame.save_pc; ! 286: setcurfunc(whatblock(pc)); ! 287: } ! 288: ! 289: /* ! 290: * Find the return address of the current procedure/function. ! 291: */ ! 292: ! 293: public Address return_addr() ! 294: { ! 295: Frame frp; ! 296: Address addr; ! 297: struct Frame frame; ! 298: ! 299: frp = &frame; ! 300: getcurframe(frp); ! 301: frp = nextframe(frp); ! 302: if (frp == nil) { ! 303: addr = 0; ! 304: } else { ! 305: addr = frp->save_pc; ! 306: } ! 307: return addr; ! 308: } ! 309: ! 310: /* ! 311: * Push the value associated with the current function. ! 312: */ ! 313: ! 314: public pushretval(len, isindirect) ! 315: integer len; ! 316: boolean isindirect; ! 317: { ! 318: Word r0; ! 319: ! 320: r0 = reg(0); ! 321: if (isindirect) { ! 322: rpush((Address) r0, len); ! 323: } else { ! 324: switch (len) { ! 325: case sizeof(char): ! 326: push(char, r0); ! 327: break; ! 328: ! 329: case sizeof(short): ! 330: push(short, r0); ! 331: break; ! 332: ! 333: default: ! 334: if (len == sizeof(Word)) { ! 335: push(Word, r0); ! 336: } else if (len == 2*sizeof(Word)) { ! 337: push(Word, r0); ! 338: push(Word, reg(1)); ! 339: } else { ! 340: error("[internal error: bad size %d in pushretval]", len); ! 341: } ! 342: break; ! 343: } ! 344: } ! 345: } ! 346: ! 347: /* ! 348: * Return the base address for locals in the given frame. ! 349: */ ! 350: ! 351: public Address locals_base(frp) ! 352: Frame frp; ! 353: { ! 354: return (frp == nil ? reg(FRP) : frp->save_fp); ! 355: } ! 356: ! 357: /* ! 358: * Return the base address for arguments in the given frame. ! 359: */ ! 360: ! 361: public Address args_base(frp) ! 362: Frame frp; ! 363: { ! 364: return (frp == nil ? reg(FRP) : frp->save_fp); ! 365: } ! 366: ! 367: /* ! 368: * Return saved register n from the given frame. ! 369: */ ! 370: ! 371: public Word savereg(n, frp) ! 372: integer n; ! 373: Frame frp; ! 374: { ! 375: Word w; ! 376: ! 377: if (frp == nil) { ! 378: w = reg(n); ! 379: } else { ! 380: switch (n) { ! 381: ! 382: case FRP: ! 383: w = frp->save_fp; ! 384: break; ! 385: ! 386: case STKP: ! 387: w = reg(STKP); ! 388: break; ! 389: ! 390: case PROGCTR: ! 391: w = frp->save_pc; ! 392: break; ! 393: ! 394: default: ! 395: assert(n >= 0 and n < NSAVEREG); ! 396: w = frp->save_reg[n]; ! 397: break; ! 398: } ! 399: } ! 400: return w; ! 401: } ! 402: ! 403: /* ! 404: * Return the nth argument to the current procedure. ! 405: */ ! 406: ! 407: public Word argn(n, frp) ! 408: integer n; ! 409: Frame frp; ! 410: { ! 411: Address argaddr; ! 412: Word w; ! 413: ! 414: argaddr = args_base(frp) + (n * sizeof(Word)); ! 415: dread(&w, argaddr, sizeof(w)); ! 416: return w; ! 417: } ! 418: ! 419: /* ! 420: * Print a list of currently active blocks starting with most recent. ! 421: */ ! 422: ! 423: public wherecmd() ! 424: { ! 425: walkstack(false); ! 426: } ! 427: ! 428: /* ! 429: * Print the variables in the given frame or the current one if nil. ! 430: */ ! 431: ! 432: public dump (func) ! 433: Symbol func; ! 434: { ! 435: Symbol f; ! 436: Frame frp; ! 437: ! 438: if (func == nil) { ! 439: f = curfunc; ! 440: if (curframe != nil) { ! 441: frp = curframe; ! 442: } else { ! 443: frp = findframe(f); ! 444: } ! 445: } else { ! 446: f = func; ! 447: frp = findframe(f); ! 448: } ! 449: showaggrs = true; ! 450: printcallinfo(f, frp); ! 451: dumpvars(f, frp); ! 452: } ! 453: ! 454: /* ! 455: * Dump all values. ! 456: */ ! 457: ! 458: public dumpall () ! 459: { ! 460: walkstack(true); ! 461: } ! 462: ! 463: /* ! 464: * Walk the stack of active procedures printing information ! 465: * about each active procedure. ! 466: */ ! 467: ! 468: private walkstack(dumpvariables) ! 469: Boolean dumpvariables; ! 470: { ! 471: Frame frp; ! 472: boolean save; ! 473: Symbol f; ! 474: struct Frame frame; ! 475: ! 476: if (notstarted(process) or isfinished(process)) { ! 477: error("program is not active"); ! 478: } else { ! 479: save = walkingstack; ! 480: walkingstack = true; ! 481: showaggrs = dumpvariables; ! 482: frp = &frame; ! 483: getcurfunc(frp, &f); ! 484: for (;;) { ! 485: printcallinfo(f, frp); ! 486: if (dumpvariables) { ! 487: dumpvars(f, frp); ! 488: putchar('\n'); ! 489: } ! 490: frp = nextfunc(frp, &f); ! 491: if (frp == nil or f == program) { ! 492: break; ! 493: } ! 494: } ! 495: if (dumpvariables) { ! 496: printf("in \"%s\":\n", symname(program)); ! 497: dumpvars(program, nil); ! 498: putchar('\n'); ! 499: } ! 500: walkingstack = save; ! 501: } ! 502: } ! 503: ! 504: /* ! 505: * Print out the information about a call, i.e., ! 506: * routine name, parameter values, and source location. ! 507: */ ! 508: ! 509: private printcallinfo (f, frp) ! 510: Symbol f; ! 511: Frame frp; ! 512: { ! 513: Lineno line; ! 514: Address savepc; ! 515: ! 516: savepc = frp->save_pc; ! 517: if (frp->save_fp != reg(FRP)) { ! 518: savepc -= 1; ! 519: } ! 520: printname(stdout, f); ! 521: if (not isinline(f)) { ! 522: printparams(f, frp); ! 523: } ! 524: line = srcline(savepc); ! 525: if (line != 0) { ! 526: printf(", line %d", line); ! 527: printf(" in \"%s\"\n", srcfilename(savepc)); ! 528: } else { ! 529: printf(" at 0x%x\n", savepc); ! 530: } ! 531: } ! 532: ! 533: /* ! 534: * Set the current function to the given symbol. ! 535: * We must adjust "curframe" so that subsequent operations are ! 536: * not confused; for simplicity we simply clear it. ! 537: */ ! 538: ! 539: public setcurfunc (f) ! 540: Symbol f; ! 541: { ! 542: curfunc = f; ! 543: curframe = nil; ! 544: } ! 545: ! 546: /* ! 547: * Return the frame for the current function. ! 548: * The space for the frame is allocated statically. ! 549: */ ! 550: ! 551: public Frame curfuncframe () ! 552: { ! 553: static struct Frame frame; ! 554: Frame frp; ! 555: ! 556: if (curframe == nil) { ! 557: frp = findframe(curfunc); ! 558: curframe = &curframerec; ! 559: *curframe = *frp; ! 560: } else { ! 561: frp = &frame; ! 562: *frp = *curframe; ! 563: } ! 564: return frp; ! 565: } ! 566: ! 567: /* ! 568: * Set curfunc to be N up/down the stack from its current value. ! 569: */ ! 570: ! 571: public up (n) ! 572: integer n; ! 573: { ! 574: integer i; ! 575: Symbol f; ! 576: Frame frp; ! 577: boolean done; ! 578: ! 579: if (not isactive(program)) { ! 580: error("program is not active"); ! 581: } else if (curfunc == nil) { ! 582: error("no current function"); ! 583: } else { ! 584: i = 0; ! 585: f = curfunc; ! 586: frp = curfuncframe(); ! 587: done = false; ! 588: do { ! 589: if (frp == nil) { ! 590: done = true; ! 591: error("not that many levels"); ! 592: } else if (i >= n) { ! 593: done = true; ! 594: curfunc = f; ! 595: curframe = &curframerec; ! 596: *curframe = *frp; ! 597: showaggrs = false; ! 598: printcallinfo(curfunc, curframe); ! 599: } else if (f == program) { ! 600: done = true; ! 601: error("not that many levels"); ! 602: } else { ! 603: frp = nextfunc(frp, &f); ! 604: } ! 605: ++i; ! 606: } while (not done); ! 607: } ! 608: } ! 609: ! 610: public down (n) ! 611: integer n; ! 612: { ! 613: integer i, depth; ! 614: Frame frp, curfrp; ! 615: Symbol f; ! 616: struct Frame frame; ! 617: ! 618: if (not isactive(program)) { ! 619: error("program is not active"); ! 620: } else if (curfunc == nil) { ! 621: error("no current function"); ! 622: } else { ! 623: depth = 0; ! 624: frp = &frame; ! 625: getcurfunc(frp, &f); ! 626: if (curframe == nil) { ! 627: curfrp = findframe(curfunc); ! 628: curframe = &curframerec; ! 629: *curframe = *curfrp; ! 630: } ! 631: while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) { ! 632: frp = nextfunc(frp, &f); ! 633: ++depth; ! 634: } ! 635: if (f == nil or n > depth) { ! 636: error("not that many levels"); ! 637: } else { ! 638: depth -= n; ! 639: frp = &frame; ! 640: getcurfunc(frp, &f); ! 641: for (i = 0; i < depth; i++) { ! 642: frp = nextfunc(frp, &f); ! 643: assert(frp != nil); ! 644: } ! 645: curfunc = f; ! 646: *curframe = *frp; ! 647: showaggrs = false; ! 648: printcallinfo(curfunc, curframe); ! 649: } ! 650: } ! 651: } ! 652: ! 653: /* ! 654: * Find the entry point of a procedure or function. ! 655: */ ! 656: ! 657: public findbeginning (f) ! 658: Symbol f; ! 659: { ! 660: if (isinternal(f)) { ! 661: f->symvalue.funcv.beginaddr += 15; ! 662: } else { ! 663: f->symvalue.funcv.beginaddr += FUNCOFFSET; ! 664: } ! 665: } ! 666: ! 667: /* ! 668: * Return the address corresponding to the first line in a function. ! 669: */ ! 670: ! 671: public Address firstline(f) ! 672: Symbol f; ! 673: { ! 674: Address addr; ! 675: ! 676: addr = codeloc(f); ! 677: while (linelookup(addr) == 0 and addr < objsize) { ! 678: ++addr; ! 679: } ! 680: if (addr == objsize) { ! 681: addr = -1; ! 682: } ! 683: return addr; ! 684: } ! 685: ! 686: /* ! 687: * Catcher drops strike three ... ! 688: */ ! 689: ! 690: public runtofirst() ! 691: { ! 692: Address addr, endaddr; ! 693: ! 694: addr = pc; ! 695: endaddr = objsize + CODESTART; ! 696: while (linelookup(addr) == 0 and addr < endaddr) { ! 697: ++addr; ! 698: } ! 699: if (addr < endaddr) { ! 700: stepto(addr); ! 701: } ! 702: } ! 703: ! 704: /* ! 705: * Return the address corresponding to the end of the program. ! 706: * ! 707: * We look for the entry to "exit". ! 708: */ ! 709: ! 710: public Address lastaddr() ! 711: { ! 712: Symbol s; ! 713: ! 714: s = lookup(identname("exit", true)); ! 715: if (s == nil) { ! 716: panic("can't find exit"); ! 717: } ! 718: return codeloc(s); ! 719: } ! 720: ! 721: /* ! 722: * Decide if the given function is currently active. ! 723: * ! 724: * We avoid calls to "findframe" during a stack trace for efficiency. ! 725: * Presumably information evaluated while walking the stack is active. ! 726: */ ! 727: ! 728: public Boolean isactive (f) ! 729: Symbol f; ! 730: { ! 731: Boolean b; ! 732: ! 733: if (isfinished(process)) { ! 734: b = false; ! 735: } else { ! 736: if (walkingstack or f == program or f == nil or ! 737: (ismodule(f) and isactive(container(f)))) { ! 738: b = true; ! 739: } else { ! 740: b = (Boolean) (findframe(f) != nil); ! 741: } ! 742: } ! 743: return b; ! 744: } ! 745: ! 746: /* ! 747: * Evaluate a call to a procedure. ! 748: */ ! 749: ! 750: public callproc(exprnode, isfunc) ! 751: Node exprnode; ! 752: boolean isfunc; ! 753: { ! 754: Node procnode, arglist; ! 755: Symbol proc; ! 756: integer argc; ! 757: ! 758: procnode = exprnode->value.arg[0]; ! 759: arglist = exprnode->value.arg[1]; ! 760: if (procnode->op != O_SYM) { ! 761: beginerrmsg(); ! 762: fprintf(stderr, "can't call \""); ! 763: prtree(stderr, procnode); ! 764: fprintf(stderr, "\""); ! 765: enderrmsg(); ! 766: } ! 767: assert(procnode->op == O_SYM); ! 768: proc = procnode->value.sym; ! 769: if (not isblock(proc)) { ! 770: error("\"%s\" is not a procedure or function", symname(proc)); ! 771: } ! 772: endproc.isfunc = isfunc; ! 773: endproc.callnode = exprnode; ! 774: endproc.cmdnode = topnode; ! 775: pushenv(); ! 776: pc = codeloc(proc); ! 777: argc = pushargs(proc, arglist); ! 778: setreg(FRP, 1); /* have to ensure it's non-zero for return_addr() */ ! 779: beginproc(proc, argc); ! 780: event_once( ! 781: build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)), ! 782: buildcmdlist(build(O_PROCRTN, proc)) ! 783: ); ! 784: isstopped = false; ! 785: if (not bpact()) { ! 786: isstopped = true; ! 787: cont(0); ! 788: } ! 789: /* ! 790: * bpact() won't return true, it will call printstatus() and go back ! 791: * to command input if a breakpoint is found. ! 792: */ ! 793: /* NOTREACHED */ ! 794: } ! 795: ! 796: /* ! 797: * Push the arguments on the process' stack. We do this by first ! 798: * evaluating them on the "eval" stack, then copying into the process' ! 799: * space. ! 800: */ ! 801: ! 802: private integer pushargs(proc, arglist) ! 803: Symbol proc; ! 804: Node arglist; ! 805: { ! 806: Stack *savesp; ! 807: int argc, args_size; ! 808: ! 809: savesp = sp; ! 810: argc = evalargs(proc, arglist); ! 811: args_size = sp - savesp; ! 812: setreg(STKP, reg(STKP) - args_size); ! 813: dwrite(savesp, reg(STKP), args_size); ! 814: sp = savesp; ! 815: return argc; ! 816: } ! 817: ! 818: /* ! 819: * Check to see if an expression is correct for a given parameter. ! 820: * If the given parameter is false, don't worry about type inconsistencies. ! 821: * ! 822: * Return whether or not it is ok. ! 823: */ ! 824: ! 825: private boolean chkparam (actual, formal, chk) ! 826: Node actual; ! 827: Symbol formal; ! 828: boolean chk; ! 829: { ! 830: boolean b; ! 831: ! 832: b = true; ! 833: if (chk) { ! 834: if (formal == nil) { ! 835: beginerrmsg(); ! 836: fprintf(stderr, "too many parameters"); ! 837: b = false; ! 838: } else if (not compatible(formal->type, actual->nodetype)) { ! 839: beginerrmsg(); ! 840: fprintf(stderr, "type mismatch for %s", symname(formal)); ! 841: b = false; ! 842: } ! 843: } ! 844: if (b and formal != nil and ! 845: isvarparam(formal) and not isopenarray(formal->type) and ! 846: not ( ! 847: actual->op == O_RVAL or actual->nodetype == t_addr or ! 848: ( ! 849: actual->op == O_TYPERENAME and ! 850: ( ! 851: actual->value.arg[0]->op == O_RVAL or ! 852: actual->value.arg[0]->nodetype == t_addr ! 853: ) ! 854: ) ! 855: ) ! 856: ) { ! 857: beginerrmsg(); ! 858: fprintf(stderr, "expected variable, found \""); ! 859: prtree(stderr, actual); ! 860: fprintf(stderr, "\""); ! 861: b = false; ! 862: } ! 863: return b; ! 864: } ! 865: ! 866: /* ! 867: * Pass an expression to a particular parameter. ! 868: * ! 869: * Normally we pass either the address or value, but in some cases ! 870: * (such as C strings) we want to copy the value onto the stack and ! 871: * pass its address. ! 872: * ! 873: * Another special case raised by strings is the possibility that ! 874: * the actual parameter will be larger than the formal, even with ! 875: * appropriate type-checking. This occurs because we assume during ! 876: * evaluation that strings are null-terminated, whereas some languages, ! 877: * notably Pascal, do not work under that assumption. ! 878: */ ! 879: ! 880: private passparam (actual, formal) ! 881: Node actual; ! 882: Symbol formal; ! 883: { ! 884: boolean b; ! 885: Address addr; ! 886: Stack *savesp; ! 887: integer actsize, formsize; ! 888: ! 889: if (formal != nil and isvarparam(formal) and ! 890: (not isopenarray(formal->type)) ! 891: ) { ! 892: addr = lval(actual->value.arg[0]); ! 893: push(Address, addr); ! 894: } else if (passaddr(formal, actual->nodetype)) { ! 895: savesp = sp; ! 896: eval(actual); ! 897: actsize = sp - savesp; ! 898: setreg(STKP, reg(STKP) - roundup(actsize, sizeof (Word))); ! 899: dwrite(savesp, reg(STKP), actsize); ! 900: sp = savesp; ! 901: push(Address, reg(STKP)); ! 902: if (formal != nil and isopenarray(formal->type)) { ! 903: push(integer, actsize div size(formal->type->type)); ! 904: } ! 905: } else if (formal != nil) { ! 906: formsize = size(formal); ! 907: savesp = sp; ! 908: eval(actual); ! 909: actsize = sp - savesp; ! 910: if (actsize > formsize) { ! 911: sp -= (actsize - formsize); ! 912: } ! 913: } else { ! 914: eval(actual); ! 915: } ! 916: } ! 917: ! 918: /* ! 919: * Evaluate an argument list left-to-right. ! 920: */ ! 921: ! 922: private integer evalargs(proc, arglist) ! 923: Symbol proc; ! 924: Node arglist; ! 925: { ! 926: Node p, actual; ! 927: Symbol formal; ! 928: Stack *savesp; ! 929: integer count; ! 930: boolean chk; ! 931: ! 932: savesp = sp; ! 933: count = 0; ! 934: formal = proc->chain; ! 935: chk = (boolean) (not nosource(proc)); ! 936: for (p = arglist; p != nil; p = p->value.arg[1]) { ! 937: assert(p->op == O_COMMA); ! 938: actual = p->value.arg[0]; ! 939: if (not chkparam(actual, formal, chk)) { ! 940: fprintf(stderr, " in call to %s", symname(proc)); ! 941: sp = savesp; ! 942: enderrmsg(); ! 943: } ! 944: passparam(actual, formal); ! 945: if (formal != nil) { ! 946: formal = formal->chain; ! 947: } ! 948: ++count; ! 949: } ! 950: if (chk) { ! 951: if (formal != nil) { ! 952: sp = savesp; ! 953: error("not enough parameters to %s", symname(proc)); ! 954: } ! 955: } ! 956: return count; ! 957: } ! 958: ! 959: /* ! 960: * Evaluate an argument list without any type checking. ! 961: * This is only useful for procedures with a varying number of ! 962: * arguments that are compiled -g. ! 963: */ ! 964: ! 965: private integer unsafe_evalargs (proc, arglist) ! 966: Symbol proc; ! 967: Node arglist; ! 968: { ! 969: Node p; ! 970: integer count; ! 971: ! 972: count = 0; ! 973: for (p = arglist; p != nil; p = p->value.arg[1]) { ! 974: assert(p->op == O_COMMA); ! 975: eval(p->value.arg[0]); ! 976: ++count; ! 977: } ! 978: return count; ! 979: } ! 980: ! 981: public procreturn(f) ! 982: Symbol f; ! 983: { ! 984: integer retvalsize; ! 985: Node tmp; ! 986: char *copy; ! 987: ! 988: flushoutput(); ! 989: popenv(); ! 990: if (endproc.isfunc) { ! 991: retvalsize = size(f->type); ! 992: if (retvalsize > sizeof(long)) { ! 993: pushretval(retvalsize, true); ! 994: copy = newarr(char, retvalsize); ! 995: popn(retvalsize, copy); ! 996: tmp = build(O_SCON, copy); ! 997: } else { ! 998: tmp = build(O_LCON, (long) (reg(0))); ! 999: } ! 1000: tmp->nodetype = f->type; ! 1001: tfree(endproc.callnode); ! 1002: *(endproc.callnode) = *(tmp); ! 1003: dispose(tmp); ! 1004: eval(endproc.cmdnode); ! 1005: } else { ! 1006: putchar('\n'); ! 1007: printname(stdout, f); ! 1008: printf(" returns successfully\n"); ! 1009: } ! 1010: erecover(); ! 1011: } ! 1012: ! 1013: /* ! 1014: * Push the current environment. ! 1015: */ ! 1016: ! 1017: private pushenv() ! 1018: { ! 1019: push(Address, pc); ! 1020: push(Lineno, curline); ! 1021: push(String, cursource); ! 1022: push(Boolean, isstopped); ! 1023: push(Symbol, curfunc); ! 1024: push(Frame, curframe); ! 1025: push(struct Frame, curframerec); ! 1026: push(CallEnv, endproc); ! 1027: push(Word, reg(PROGCTR)); ! 1028: push(Word, reg(STKP)); ! 1029: } ! 1030: ! 1031: /* ! 1032: * Pop back to the real world. ! 1033: */ ! 1034: ! 1035: public popenv() ! 1036: { ! 1037: String filename; ! 1038: ! 1039: setreg(STKP, pop(Word)); ! 1040: setreg(PROGCTR, pop(Word)); ! 1041: endproc = pop(CallEnv); ! 1042: curframerec = pop(struct Frame); ! 1043: curframe = pop(Frame); ! 1044: curfunc = pop(Symbol); ! 1045: isstopped = pop(Boolean); ! 1046: filename = pop(String); ! 1047: curline = pop(Lineno); ! 1048: pc = pop(Address); ! 1049: setsource(filename); ! 1050: } ! 1051: ! 1052: /* ! 1053: * Flush the debuggee's standard output. ! 1054: * ! 1055: * This is VERY dependent on the use of stdio. ! 1056: */ ! 1057: ! 1058: public flushoutput() ! 1059: { ! 1060: Symbol p, iob; ! 1061: Stack *savesp; ! 1062: ! 1063: p = lookup(identname("fflush", true)); ! 1064: while (p != nil and not isblock(p)) { ! 1065: p = p->next_sym; ! 1066: } ! 1067: if (p != nil) { ! 1068: iob = lookup(identname("_iob", true)); ! 1069: if (iob != nil) { ! 1070: pushenv(); ! 1071: pc = codeloc(p); ! 1072: savesp = sp; ! 1073: push(long, address(iob, nil) + sizeof(struct _iobuf)); ! 1074: setreg(STKP, reg(STKP) - sizeof(long)); ! 1075: dwrite(savesp, reg(STKP), sizeof(long)); ! 1076: sp = savesp; ! 1077: beginproc(p, 1); ! 1078: stepto(return_addr()); ! 1079: popenv(); ! 1080: } ! 1081: } ! 1082: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.