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