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