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