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