|
|
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.iris.c 5.1 (Berkeley) 1/12/88"; ! 9: #endif not lint ! 10: ! 11: static char rcsid[] = "$Header: runtime.iris.c,v 1.3 88/01/11 21:26:46 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 14 ! 39: ! 40: struct Frame { ! 41: Address save_fp; /* frame pointer */ ! 42: Address save_pc; /* program counter */ ! 43: Word save_reg[NSAVEREG]; /* not necessarily there */ ! 44: integer nargwords; /* computed, not stored */ ! 45: }; ! 46: ! 47: private Frame curframe = nil; ! 48: private struct Frame curframerec; ! 49: private Boolean walkingstack = false; ! 50: ! 51: #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp) ! 52: ! 53: private boolean inSignalHandler (addr) ! 54: Address addr; ! 55: { ! 56: Symbol f; ! 57: ! 58: #ifdef IRIS ! 59: return false; ! 60: #else /* sun */ ! 61: f = whatblock(addr); ! 62: return (boolean) (f != nil and streq(symname(f), "_sigtramp")); ! 63: #endif ! 64: } ! 65: ! 66: typedef struct { ! 67: Node callnode; ! 68: Node cmdnode; ! 69: boolean isfunc; ! 70: } CallEnv; ! 71: ! 72: private CallEnv endproc; ! 73: ! 74: /* ! 75: * Set a frame to the current activation record. ! 76: */ ! 77: ! 78: private getcurframe(frp) ! 79: Frame frp; ! 80: { ! 81: register int i; ! 82: ! 83: checkref(frp); ! 84: frp->save_fp = reg(FRP); ! 85: frp->save_pc = reg(PROGCTR); ! 86: for (i = 0; i < NSAVEREG; i++) { ! 87: frp->save_reg[i] = reg(i); ! 88: } ! 89: if (frp->save_fp == nil) { ! 90: frp->nargwords = 0; ! 91: } else { ! 92: findnumargs(frp); ! 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, higher_fp, higher_pc; ! 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: # ifdef sun ! 176: Address scp; ! 177: ! 178: dread(&scp, prev_frame + 16, sizeof(scp)); ! 179: dread(&callpc, ! 180: &(((struct sigcontext *)scp)->sc_pc), sizeof(Word) ! 181: ); ! 182: # endif /* sun */ ! 183: } ! 184: frame.save_pc = callpc; ! 185: ntramp = 0; ! 186: higher_fp = frp->save_fp; ! 187: higher_pc = frp->save_pc; ! 188: newfrp->save_fp = frame.save_fp; ! 189: newfrp->save_pc = frame.save_pc; ! 190: findnumargs(newfrp); ! 191: findsavedregs(newfrp, higher_fp, higher_pc); ! 192: } ! 193: return newfrp; ! 194: } ! 195: ! 196: /* ! 197: * Finding the saved registers and number of arguments passed to ! 198: * the current procedure is painful for the 68000. ! 199: * ! 200: * This is a version of the way adb for the 68000 does this. ! 201: */ ! 202: ! 203: #define HIWORD 0xffff0000 ! 204: #define LOWORD 0x0000ffff ! 205: #define LINKA6 0x4e560000 /* link a6,#x */ ! 206: #define ADDLSP 0xdffc0000 /* addl #x,sp */ ! 207: #define ADDWSP 0xdefc0000 /* addw #x,sp */ ! 208: #define LEASP 0x4fef0000 /* lea sp@(x),sp*/ ! 209: #define TSTBSP 0x4a2f0000 /* tstb sp@(x) */ ! 210: #define INSMSK 0xfff80000 ! 211: #define MOVLSP 0x2e800000 /* movl dx,sp@ */ ! 212: #define MOVLD0 0x20000000 /* movl d0,dx */ ! 213: #define MOVLA0 0x20400000 /* movl d0,ax */ ! 214: #define MVLMSK 0xf1ff0000 ! 215: #define MOVEML 0x48d70000 /* moveml #x,sp@ */ ! 216: #define JSR 0x4eb80000 /* jsr x.[WL] */ ! 217: #define JSRPC 0x4eba0000 /* jsr PC@( ) */ ! 218: #define LONGBIT 0x00010000 ! 219: #define BSR 0x61000000 /* bsr x */ ! 220: #define BYTE3 0x0000ff00 ! 221: #define LOBYTE 0x000000ff ! 222: #define ADQMSK 0xf1ff0000 ! 223: #define ADDQSP 0x508f0000 /* addql #x,sp */ ! 224: #define ADDQWSP 0x504f0000 /* addqw #x,sp */ ! 225: ! 226: private int savedregsmask; ! 227: private int savedregp; ! 228: ! 229: /* ! 230: * Find out how many words of arguments were passed to ! 231: * the current procedure. ! 232: */ ! 233: ! 234: private findnumargs (newfrp) ! 235: Frame newfrp; ! 236: { ! 237: integer val; ! 238: integer instruc; ! 239: Address addr; ! 240: ! 241: dread(&addr, newfrp->save_fp + sizeof(Address), sizeof(addr)); ! 242: iread(&instruc, addr, sizeof(instruc)); ! 243: if ((instruc&MVLMSK) == MOVLA0 or (instruc&MVLMSK) == MOVLD0) { ! 244: addr += 2; ! 245: iread(&instruc, addr, sizeof(instruc)); ! 246: } ! 247: if ((instruc&ADQMSK) == ADDQSP or (instruc&ADQMSK) == ADDQWSP){ ! 248: val = (instruc >> (16+9)) & 07; ! 249: if (val == 0) { ! 250: val = 8; ! 251: } ! 252: } else if ((instruc&HIWORD) == ADDLSP){ ! 253: iread(&val, addr + 2, sizeof(val)); ! 254: } else if ((instruc&HIWORD) == ADDWSP || (instruc&HIWORD) == LEASP){ ! 255: val = instruc&LOWORD; ! 256: } else { ! 257: val = 0; ! 258: } ! 259: newfrp->nargwords = val / sizeof(Word); ! 260: } ! 261: ! 262: /* ! 263: * Get the saved registers for the given Frame. ! 264: */ ! 265: ! 266: private findsavedregs (newfrp, higher_fp, higher_pc) ! 267: Frame newfrp; ! 268: register Address higher_fp, higher_pc; ! 269: { ! 270: int val, regp, i; ! 271: Address addr; ! 272: Symbol func; ! 273: Address calladdr; ! 274: int instruc; ! 275: ! 276: /* ! 277: * Find the entry point of the current procedure. ! 278: * This is done by finding the procedure for the higher frame's pc ! 279: * and taking its starting address. ! 280: */ ! 281: func = whatblock(higher_pc, true); ! 282: calladdr = codeloc(func) - FUNCOFFSET; ! 283: ! 284: /* ! 285: * Look at the entry code for the current procedure ! 286: * to determine which registers were saved, and where they are. ! 287: * ! 288: * First find the size of the activation record. ! 289: */ ! 290: addr = calladdr; ! 291: iread(&instruc, addr, sizeof(instruc)); ! 292: if ((instruc&HIWORD) == LINKA6) { ! 293: if ((instruc &= LOWORD) == 0) { ! 294: /* look for addl */ ! 295: addr += 4; ! 296: iread(&instruc, addr, sizeof(instruc)); ! 297: if ((instruc&HIWORD) == ADDLSP) { ! 298: iread(&instruc, addr + 2, sizeof(instruc)); ! 299: addr += 6; ! 300: } else { ! 301: instruc = 0; ! 302: } ! 303: } else { ! 304: /* link offset was non-zero -- sign extend it */ ! 305: instruc <<= 16; ! 306: instruc >>= 16; ! 307: } ! 308: /* we now have the negative frame size */ ! 309: regp = higher_fp + instruc; ! 310: savedregp = regp; ! 311: } ! 312: ! 313: /* ! 314: * Now find which registers were saved. ! 315: * (expecting a probe instruction next) ! 316: */ ! 317: iread(&instruc, addr, sizeof(instruc)); ! 318: if ((instruc&HIWORD) == TSTBSP) { ! 319: addr += 4; ! 320: iread(&instruc, addr, sizeof(instruc)); ! 321: } ! 322: /* ! 323: * expect either a moveml or a movl next ! 324: */ ! 325: if ((instruc&INSMSK) == MOVLSP){ ! 326: /* ! 327: * Only one register saved. ! 328: */ ! 329: i = (instruc>>16) & 07; ! 330: dread(&(newfrp->save_reg[i]), regp, sizeof(Word)); ! 331: savedregsmask = 1 << i; ! 332: } else if ((instruc&HIWORD) == MOVEML) { ! 333: /* ! 334: * Saving multiple registers or unoptimized code ! 335: */ ! 336: val = instruc & LOWORD; ! 337: savedregsmask = val; ! 338: i = 0; ! 339: while (val != 0) { ! 340: if (val&1) { ! 341: dread(&(newfrp->save_reg[i]), regp, sizeof(Word)); ! 342: regp += sizeof(Word); ! 343: } ! 344: val >>= 1; ! 345: ++i; ! 346: } ! 347: } else { ! 348: savedregsmask = 0; ! 349: } ! 350: } ! 351: ! 352: /* ! 353: * Get the current frame information in the given Frame and store the ! 354: * associated function in the given value-result parameter. ! 355: */ ! 356: ! 357: private getcurfunc (frp, fp) ! 358: Frame frp; ! 359: Symbol *fp; ! 360: { ! 361: getcurframe(frp); ! 362: *fp = whatblock(frp->save_pc); ! 363: } ! 364: ! 365: /* ! 366: * Return the frame associated with the next function up the call stack, or ! 367: * nil if there is none. The function is returned in a value-result parameter. ! 368: * For "inline" functions the statically outer function and same frame ! 369: * are returned. ! 370: */ ! 371: ! 372: public Frame nextfunc (frp, fp) ! 373: Frame frp; ! 374: Symbol *fp; ! 375: { ! 376: Symbol t; ! 377: Frame nfrp; ! 378: ! 379: t = *fp; ! 380: checkref(t); ! 381: if (isinline(t)) { ! 382: t = container(t); ! 383: nfrp = frp; ! 384: } else { ! 385: nfrp = nextframe(frp); ! 386: if (nfrp == nil) { ! 387: t = nil; ! 388: } else { ! 389: t = whatblock(nfrp->save_pc); ! 390: } ! 391: } ! 392: *fp = t; ! 393: return nfrp; ! 394: } ! 395: ! 396: /* ! 397: * Return the frame associated with the given function. ! 398: * If the function is nil, return the most recently activated frame. ! 399: * ! 400: * Static allocation for the frame. ! 401: */ ! 402: ! 403: public Frame findframe(f) ! 404: Symbol f; ! 405: { ! 406: Frame frp; ! 407: static struct Frame frame; ! 408: Symbol p; ! 409: Boolean done; ! 410: ! 411: frp = &frame; ! 412: getcurframe(frp); ! 413: if (f != nil) { ! 414: if (f == curfunc and curframe != nil) { ! 415: *frp = *curframe; ! 416: } else { ! 417: done = false; ! 418: p = whatblock(frp->save_pc); ! 419: do { ! 420: if (p == f) { ! 421: done = true; ! 422: } else if (p == program) { ! 423: done = true; ! 424: frp = nil; ! 425: } else { ! 426: frp = nextfunc(frp, &p); ! 427: if (frp == nil) { ! 428: done = true; ! 429: } ! 430: } ! 431: } while (not done); ! 432: } ! 433: } ! 434: return frp; ! 435: } ! 436: ! 437: /* ! 438: * Set the registers according to the given frame pointer. ! 439: */ ! 440: ! 441: public getnewregs (addr) ! 442: Address addr; ! 443: { ! 444: struct Frame frame; ! 445: integer i, j, mask; ! 446: ! 447: dread(&frame, addr, sizeof(frame)); ! 448: setreg(FRP, frame.save_fp); ! 449: setreg(PROGCTR, frame.save_pc); ! 450: pc = frame.save_pc; ! 451: setcurfunc(whatblock(pc)); ! 452: } ! 453: ! 454: /* ! 455: * Find the return address of the current procedure/function. ! 456: */ ! 457: ! 458: public Address return_addr() ! 459: { ! 460: Frame frp; ! 461: Address addr; ! 462: struct Frame frame; ! 463: ! 464: frp = &frame; ! 465: getcurframe(frp); ! 466: frp = nextframe(frp); ! 467: if (frp == nil) { ! 468: addr = 0; ! 469: } else { ! 470: addr = frp->save_pc; ! 471: } ! 472: return addr; ! 473: } ! 474: ! 475: /* ! 476: * Push the value associated with the current function. ! 477: */ ! 478: ! 479: public pushretval(len, isindirect) ! 480: integer len; ! 481: boolean isindirect; ! 482: { ! 483: Word r0; ! 484: ! 485: r0 = reg(0); ! 486: if (isindirect) { ! 487: rpush((Address) r0, len); ! 488: } else { ! 489: switch (len) { ! 490: case sizeof(char): ! 491: push(char, r0); ! 492: break; ! 493: ! 494: case sizeof(short): ! 495: push(short, r0); ! 496: break; ! 497: ! 498: default: ! 499: if (len == sizeof(Word)) { ! 500: push(Word, r0); ! 501: } else if (len == 2*sizeof(Word)) { ! 502: push(Word, r0); ! 503: push(Word, reg(1)); ! 504: } else { ! 505: error("[internal error: bad size %d in pushretval]", len); ! 506: } ! 507: break; ! 508: } ! 509: } ! 510: } ! 511: ! 512: /* ! 513: * Return the base address for locals in the given frame. ! 514: */ ! 515: ! 516: public Address locals_base(frp) ! 517: Frame frp; ! 518: { ! 519: return (frp == nil) ? reg(FRP) : frp->save_fp; ! 520: } ! 521: ! 522: /* ! 523: * Return the base address for arguments in the given frame. ! 524: */ ! 525: ! 526: public Address args_base(frp) ! 527: Frame frp; ! 528: { ! 529: return (frp == nil) ? reg(FRP) : frp->save_fp; ! 530: } ! 531: ! 532: /* ! 533: * Return saved register n from the given frame. ! 534: */ ! 535: ! 536: public Word savereg(n, frp) ! 537: integer n; ! 538: Frame frp; ! 539: { ! 540: Word w; ! 541: ! 542: if (frp == nil) { ! 543: w = reg(n); ! 544: } else { ! 545: switch (n) { ! 546: case FRP: ! 547: w = frp->save_fp; ! 548: break; ! 549: ! 550: case STKP: ! 551: w = reg(STKP); ! 552: break; ! 553: ! 554: case PROGCTR: ! 555: w = frp->save_pc; ! 556: break; ! 557: ! 558: default: ! 559: assert(n >= 0 and n < NSAVEREG); ! 560: w = frp->save_reg[n]; ! 561: break; ! 562: } ! 563: } ! 564: return w; ! 565: } ! 566: ! 567: /* ! 568: * Return the nth argument to the current procedure. ! 569: */ ! 570: ! 571: public Word argn(n, frp) ! 572: integer n; ! 573: Frame frp; ! 574: { ! 575: Address argaddr; ! 576: Word w; ! 577: ! 578: argaddr = args_base(frp) + 4 + (n * sizeof(Word)); ! 579: dread(&w, argaddr, sizeof(w)); ! 580: return w; ! 581: } ! 582: ! 583: /* ! 584: * Return the number of words of arguments passed to the procedure ! 585: * associated with the given frame (it's a macro for the VAX). ! 586: */ ! 587: ! 588: public integer nargspassed (frp) ! 589: Frame frp; ! 590: { ! 591: integer n; ! 592: struct Frame frame; ! 593: ! 594: if (frp == nil) { ! 595: getcurframe(&frame); ! 596: n = frame.nargwords; ! 597: } else { ! 598: n = frp->nargwords; ! 599: } ! 600: return n; ! 601: } ! 602: ! 603: /* ! 604: * Print a list of currently active blocks starting with most recent. ! 605: */ ! 606: ! 607: public wherecmd() ! 608: { ! 609: walkstack(false); ! 610: } ! 611: ! 612: /* ! 613: * Print the variables in the given frame or the current one if nil. ! 614: */ ! 615: ! 616: public dump (func) ! 617: Symbol func; ! 618: { ! 619: Symbol f; ! 620: Frame frp; ! 621: ! 622: if (func == nil) { ! 623: f = curfunc; ! 624: if (curframe != nil) { ! 625: frp = curframe; ! 626: } else { ! 627: frp = findframe(f); ! 628: } ! 629: } else { ! 630: f = func; ! 631: frp = findframe(f); ! 632: } ! 633: showaggrs = true; ! 634: printcallinfo(f, frp); ! 635: dumpvars(f, frp); ! 636: } ! 637: ! 638: /* ! 639: * Dump all values. ! 640: */ ! 641: ! 642: public dumpall () ! 643: { ! 644: walkstack(true); ! 645: } ! 646: ! 647: /* ! 648: * Walk the stack of active procedures printing information ! 649: * about each active procedure. ! 650: */ ! 651: ! 652: private walkstack(dumpvariables) ! 653: Boolean dumpvariables; ! 654: { ! 655: Frame frp; ! 656: boolean save; ! 657: Symbol f; ! 658: struct Frame frame; ! 659: ! 660: if (notstarted(process) or isfinished(process)) { ! 661: error("program is not active"); ! 662: } else { ! 663: save = walkingstack; ! 664: walkingstack = true; ! 665: showaggrs = dumpvariables; ! 666: frp = &frame; ! 667: getcurfunc(frp, &f); ! 668: for (;;) { ! 669: printcallinfo(f, frp); ! 670: if (dumpvariables) { ! 671: dumpvars(f, frp); ! 672: putchar('\n'); ! 673: } ! 674: frp = nextfunc(frp, &f); ! 675: if (frp == nil or f == program) { ! 676: break; ! 677: } ! 678: } ! 679: if (dumpvariables) { ! 680: printf("in \"%s\":\n", symname(program)); ! 681: dumpvars(program, nil); ! 682: putchar('\n'); ! 683: } ! 684: walkingstack = save; ! 685: } ! 686: } ! 687: ! 688: /* ! 689: * Print out the information about a call, i.e., ! 690: * routine name, parameter values, and source location. ! 691: */ ! 692: ! 693: private printcallinfo (f, frp) ! 694: Symbol f; ! 695: Frame frp; ! 696: { ! 697: Lineno line; ! 698: Address savepc; ! 699: ! 700: savepc = frp->save_pc; ! 701: if (frp->save_fp != reg(FRP)) { ! 702: savepc -= 1; ! 703: } ! 704: printname(stdout, f); ! 705: if (not isinline(f)) { ! 706: printparams(f, frp); ! 707: } ! 708: line = srcline(savepc); ! 709: if (line != 0) { ! 710: printf(", line %d", line); ! 711: printf(" in \"%s\"\n", srcfilename(savepc)); ! 712: } else { ! 713: printf(" at 0x%x\n", savepc); ! 714: } ! 715: } ! 716: ! 717: /* ! 718: * Set the current function to the given symbol. ! 719: * We must adjust "curframe" so that subsequent operations are ! 720: * not confused; for simplicity we simply clear it. ! 721: */ ! 722: ! 723: public setcurfunc (f) ! 724: Symbol f; ! 725: { ! 726: curfunc = f; ! 727: curframe = nil; ! 728: } ! 729: ! 730: /* ! 731: * Return the frame for the current function. ! 732: * The space for the frame is allocated statically. ! 733: */ ! 734: ! 735: public Frame curfuncframe () ! 736: { ! 737: static struct Frame frame; ! 738: Frame frp; ! 739: ! 740: if (curframe == nil) { ! 741: frp = findframe(curfunc); ! 742: curframe = &curframerec; ! 743: *curframe = *frp; ! 744: } else { ! 745: frp = &frame; ! 746: *frp = *curframe; ! 747: } ! 748: return frp; ! 749: } ! 750: ! 751: /* ! 752: * Set curfunc to be N up/down the stack from its current value. ! 753: */ ! 754: ! 755: public up (n) ! 756: integer n; ! 757: { ! 758: integer i; ! 759: Symbol f; ! 760: Frame frp; ! 761: boolean done; ! 762: ! 763: if (not isactive(program)) { ! 764: error("program is not active"); ! 765: } else if (curfunc == nil) { ! 766: error("no current function"); ! 767: } else { ! 768: i = 0; ! 769: f = curfunc; ! 770: frp = curfuncframe(); ! 771: done = false; ! 772: do { ! 773: if (frp == nil) { ! 774: done = true; ! 775: error("not that many levels"); ! 776: } else if (i >= n) { ! 777: done = true; ! 778: curfunc = f; ! 779: curframe = &curframerec; ! 780: *curframe = *frp; ! 781: showaggrs = false; ! 782: printcallinfo(curfunc, curframe); ! 783: } else if (f == program) { ! 784: done = true; ! 785: error("not that many levels"); ! 786: } else { ! 787: frp = nextfunc(frp, &f); ! 788: } ! 789: ++i; ! 790: } while (not done); ! 791: } ! 792: } ! 793: ! 794: public down (n) ! 795: integer n; ! 796: { ! 797: integer i, depth; ! 798: Frame frp, curfrp; ! 799: Symbol f; ! 800: struct Frame frame; ! 801: ! 802: if (not isactive(program)) { ! 803: error("program is not active"); ! 804: } else if (curfunc == nil) { ! 805: error("no current function"); ! 806: } else { ! 807: depth = 0; ! 808: frp = &frame; ! 809: getcurfunc(frp, &f); ! 810: if (curframe == nil) { ! 811: curfrp = findframe(curfunc); ! 812: curframe = &curframerec; ! 813: *curframe = *curfrp; ! 814: } ! 815: while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) { ! 816: frp = nextfunc(frp, &f); ! 817: ++depth; ! 818: } ! 819: if (f == nil or n > depth) { ! 820: error("not that many levels"); ! 821: } else { ! 822: depth -= n; ! 823: frp = &frame; ! 824: getcurfunc(frp, &f); ! 825: for (i = 0; i < depth; i++) { ! 826: frp = nextfunc(frp, &f); ! 827: assert(frp != nil); ! 828: } ! 829: curfunc = f; ! 830: *curframe = *frp; ! 831: showaggrs = false; ! 832: printcallinfo(curfunc, curframe); ! 833: } ! 834: } ! 835: } ! 836: ! 837: /* ! 838: * Find the entry point of a procedure or function. ! 839: */ ! 840: ! 841: public findbeginning (f) ! 842: Symbol f; ! 843: { ! 844: if (isinternal(f)) { ! 845: f->symvalue.funcv.beginaddr += 18; /* VAX only */ ! 846: } else { ! 847: /* on 68000's don't add for beginning of program */ ! 848: if (f->symvalue.funcv.beginaddr != CODESTART) { ! 849: f->symvalue.funcv.beginaddr += FUNCOFFSET; ! 850: } ! 851: } ! 852: } ! 853: ! 854: /* ! 855: * Return the address corresponding to the first line in a function. ! 856: */ ! 857: ! 858: public Address firstline(f) ! 859: Symbol f; ! 860: { ! 861: Address addr; ! 862: ! 863: addr = codeloc(f); ! 864: while (linelookup(addr) == 0 and addr < objsize) { ! 865: ++addr; ! 866: } ! 867: if (addr == objsize) { ! 868: addr = -1; ! 869: } ! 870: return addr; ! 871: } ! 872: ! 873: /* ! 874: * Catcher drops strike three ... ! 875: */ ! 876: ! 877: public runtofirst() ! 878: { ! 879: Address addr, endaddr; ! 880: ! 881: addr = pc; ! 882: endaddr = objsize + CODESTART; ! 883: while (linelookup(addr) == 0 and addr < endaddr) { ! 884: ++addr; ! 885: } ! 886: if (addr < endaddr) { ! 887: stepto(addr); ! 888: } ! 889: } ! 890: ! 891: /* ! 892: * Return the address corresponding to the end of the program. ! 893: * ! 894: * We look for the entry to "exit". ! 895: */ ! 896: ! 897: public Address lastaddr() ! 898: { ! 899: Symbol s; ! 900: ! 901: s = lookup(identname("exit", true)); ! 902: if (s == nil) { ! 903: panic("can't find exit"); ! 904: } ! 905: return codeloc(s); ! 906: } ! 907: ! 908: /* ! 909: * Decide if the given function is currently active. ! 910: * ! 911: * We avoid calls to "findframe" during a stack trace for efficiency. ! 912: * Presumably information evaluated while walking the stack is active. ! 913: */ ! 914: ! 915: public Boolean isactive (f) ! 916: Symbol f; ! 917: { ! 918: Boolean b; ! 919: ! 920: if (isfinished(process)) { ! 921: b = false; ! 922: } else { ! 923: if (walkingstack or f == program or f == nil or ! 924: (ismodule(f) and isactive(container(f)))) { ! 925: b = true; ! 926: } else { ! 927: b = (Boolean) (findframe(f) != nil); ! 928: } ! 929: } ! 930: return b; ! 931: } ! 932: ! 933: /* ! 934: * Evaluate a call to a procedure. ! 935: */ ! 936: ! 937: public callproc(exprnode, isfunc) ! 938: Node exprnode; ! 939: boolean isfunc; ! 940: { ! 941: Node procnode, arglist; ! 942: Symbol proc; ! 943: integer argc; ! 944: ! 945: procnode = exprnode->value.arg[0]; ! 946: arglist = exprnode->value.arg[1]; ! 947: if (procnode->op != O_SYM) { ! 948: beginerrmsg(); ! 949: fprintf(stderr, "can't call \""); ! 950: prtree(stderr, procnode); ! 951: fprintf(stderr, "\""); ! 952: enderrmsg(); ! 953: } ! 954: assert(procnode->op == O_SYM); ! 955: proc = procnode->value.sym; ! 956: if (not isblock(proc)) { ! 957: error("\"%s\" is not a procedure or function", symname(proc)); ! 958: } ! 959: endproc.isfunc = isfunc; ! 960: endproc.callnode = exprnode; ! 961: endproc.cmdnode = topnode; ! 962: pushenv(); ! 963: pc = codeloc(proc); ! 964: argc = pushargs(proc, arglist); ! 965: setreg(FRP, 1); /* have to ensure it's non-zero for return_addr() */ ! 966: beginproc(proc, argc); ! 967: event_once( ! 968: build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)), ! 969: buildcmdlist(build(O_PROCRTN, proc)) ! 970: ); ! 971: isstopped = false; ! 972: if (not bpact()) { ! 973: isstopped = true; ! 974: cont(0); ! 975: } ! 976: /* ! 977: * bpact() won't return true, it will call printstatus() and go back ! 978: * to command input if a breakpoint is found. ! 979: */ ! 980: /* NOTREACHED */ ! 981: } ! 982: ! 983: /* ! 984: * Push the arguments on the process' stack. We do this by first ! 985: * evaluating them on the "eval" stack, then copying into the process' ! 986: * space. ! 987: */ ! 988: ! 989: private integer pushargs(proc, arglist) ! 990: Symbol proc; ! 991: Node arglist; ! 992: { ! 993: Stack *savesp; ! 994: int argc, args_size; ! 995: ! 996: savesp = sp; ! 997: if (varIsSet("$unsafecall")) { ! 998: argc = unsafe_evalargs(proc, arglist); ! 999: } else { ! 1000: argc = evalargs(proc, arglist); ! 1001: } ! 1002: args_size = sp - savesp; ! 1003: setreg(STKP, reg(STKP) - args_size); ! 1004: dwrite(savesp, reg(STKP), args_size); ! 1005: sp = savesp; ! 1006: return argc; ! 1007: } ! 1008: ! 1009: /* ! 1010: * Check to see if an expression is correct for a given parameter. ! 1011: * If the given parameter is false, don't worry about type inconsistencies. ! 1012: * ! 1013: * Return whether or not it is ok. ! 1014: */ ! 1015: ! 1016: private boolean chkparam (actual, formal, chk) ! 1017: Node actual; ! 1018: Symbol formal; ! 1019: boolean chk; ! 1020: { ! 1021: boolean b; ! 1022: ! 1023: b = true; ! 1024: if (chk) { ! 1025: if (formal == nil) { ! 1026: beginerrmsg(); ! 1027: fprintf(stderr, "too many parameters"); ! 1028: b = false; ! 1029: } else if (not compatible(formal->type, actual->nodetype)) { ! 1030: beginerrmsg(); ! 1031: fprintf(stderr, "type mismatch for %s", symname(formal)); ! 1032: b = false; ! 1033: } ! 1034: } ! 1035: if (b and formal != nil and ! 1036: isvarparam(formal) and not isopenarray(formal->type) and ! 1037: not ( ! 1038: actual->op == O_RVAL or actual->nodetype == t_addr or ! 1039: ( ! 1040: actual->op == O_TYPERENAME and ! 1041: ( ! 1042: actual->value.arg[0]->op == O_RVAL or ! 1043: actual->value.arg[0]->nodetype == t_addr ! 1044: ) ! 1045: ) ! 1046: ) ! 1047: ) { ! 1048: beginerrmsg(); ! 1049: fprintf(stderr, "expected variable, found \""); ! 1050: prtree(stderr, actual); ! 1051: fprintf(stderr, "\""); ! 1052: b = false; ! 1053: } ! 1054: return b; ! 1055: } ! 1056: ! 1057: /* ! 1058: * Pass an expression to a particular parameter. ! 1059: * ! 1060: * Normally we pass either the address or value, but in some cases ! 1061: * (such as C strings) we want to copy the value onto the stack and ! 1062: * pass its address. ! 1063: * ! 1064: * Another special case raised by strings is the possibility that ! 1065: * the actual parameter will be larger than the formal, even with ! 1066: * appropriate type-checking. This occurs because we assume during ! 1067: * evaluation that strings are null-terminated, whereas some languages, ! 1068: * notably Pascal, do not work under that assumption. ! 1069: */ ! 1070: ! 1071: private passparam (actual, formal) ! 1072: Node actual; ! 1073: Symbol formal; ! 1074: { ! 1075: boolean b; ! 1076: Address addr; ! 1077: Stack *savesp; ! 1078: integer actsize, formsize; ! 1079: ! 1080: if (formal != nil and isvarparam(formal) and ! 1081: (not isopenarray(formal->type)) ! 1082: ) { ! 1083: addr = lval(actual->value.arg[0]); ! 1084: push(Address, addr); ! 1085: } else if (passaddr(formal, actual->nodetype)) { ! 1086: savesp = sp; ! 1087: eval(actual); ! 1088: actsize = sp - savesp; ! 1089: setreg(STKP, ! 1090: reg(STKP) - ((actsize + sizeof(Word) - 1) & ~(sizeof(Word) - 1)) ! 1091: ); ! 1092: dwrite(savesp, reg(STKP), actsize); ! 1093: sp = savesp; ! 1094: push(Address, reg(STKP)); ! 1095: if (formal != nil and isopenarray(formal->type)) { ! 1096: push(integer, actsize div size(formal->type->type)); ! 1097: } ! 1098: } else if (formal != nil) { ! 1099: formsize = size(formal); ! 1100: savesp = sp; ! 1101: eval(actual); ! 1102: actsize = sp - savesp; ! 1103: if (actsize > formsize) { ! 1104: sp -= (actsize - formsize); ! 1105: } ! 1106: } else { ! 1107: eval(actual); ! 1108: } ! 1109: } ! 1110: ! 1111: /* ! 1112: * Evaluate an argument list left-to-right. ! 1113: */ ! 1114: ! 1115: private integer evalargs(proc, arglist) ! 1116: Symbol proc; ! 1117: Node arglist; ! 1118: { ! 1119: Node p, actual; ! 1120: Symbol formal; ! 1121: Stack *savesp; ! 1122: integer count; ! 1123: boolean chk; ! 1124: ! 1125: savesp = sp; ! 1126: count = 0; ! 1127: formal = proc->chain; ! 1128: chk = (boolean) (not nosource(proc)); ! 1129: for (p = arglist; p != nil; p = p->value.arg[1]) { ! 1130: assert(p->op == O_COMMA); ! 1131: actual = p->value.arg[0]; ! 1132: if (not chkparam(actual, formal, chk)) { ! 1133: fprintf(stderr, " in call to %s", symname(proc)); ! 1134: sp = savesp; ! 1135: enderrmsg(); ! 1136: } ! 1137: passparam(actual, formal); ! 1138: if (formal != nil) { ! 1139: formal = formal->chain; ! 1140: } ! 1141: ++count; ! 1142: } ! 1143: if (chk) { ! 1144: if (formal != nil) { ! 1145: sp = savesp; ! 1146: error("not enough parameters to %s", symname(proc)); ! 1147: } ! 1148: } ! 1149: return count; ! 1150: } ! 1151: ! 1152: /* ! 1153: * Evaluate an argument list without any type checking. ! 1154: * This is only useful for procedures with a varying number of ! 1155: * arguments that are compiled -g. ! 1156: */ ! 1157: ! 1158: private integer unsafe_evalargs (proc, arglist) ! 1159: Symbol proc; ! 1160: Node arglist; ! 1161: { ! 1162: Node p; ! 1163: integer count; ! 1164: ! 1165: count = 0; ! 1166: for (p = arglist; p != nil; p = p->value.arg[1]) { ! 1167: assert(p->op == O_COMMA); ! 1168: eval(p->value.arg[0]); ! 1169: ++count; ! 1170: } ! 1171: return count; ! 1172: } ! 1173: ! 1174: public procreturn(f) ! 1175: Symbol f; ! 1176: { ! 1177: integer retvalsize; ! 1178: Node tmp; ! 1179: char *copy; ! 1180: ! 1181: flushoutput(); ! 1182: popenv(); ! 1183: if (endproc.isfunc) { ! 1184: retvalsize = size(f->type); ! 1185: if (retvalsize > sizeof(long)) { ! 1186: pushretval(retvalsize, true); ! 1187: copy = newarr(char, retvalsize); ! 1188: popn(retvalsize, copy); ! 1189: tmp = build(O_SCON, copy); ! 1190: } else { ! 1191: tmp = build(O_LCON, (long) (reg(0))); ! 1192: } ! 1193: tmp->nodetype = f->type; ! 1194: tfree(endproc.callnode); ! 1195: *(endproc.callnode) = *(tmp); ! 1196: dispose(tmp); ! 1197: eval(endproc.cmdnode); ! 1198: } else { ! 1199: putchar('\n'); ! 1200: printname(stdout, f); ! 1201: printf(" returns successfully\n"); ! 1202: } ! 1203: erecover(); ! 1204: } ! 1205: ! 1206: /* ! 1207: * Push the current environment. ! 1208: */ ! 1209: ! 1210: private pushenv() ! 1211: { ! 1212: push(Address, pc); ! 1213: push(Lineno, curline); ! 1214: push(String, cursource); ! 1215: push(Boolean, isstopped); ! 1216: push(Symbol, curfunc); ! 1217: push(Frame, curframe); ! 1218: push(struct Frame, curframerec); ! 1219: push(CallEnv, endproc); ! 1220: push(Word, reg(PROGCTR)); ! 1221: push(Word, reg(STKP)); ! 1222: push(Word, reg(FRP)); ! 1223: } ! 1224: ! 1225: /* ! 1226: * Pop back to the real world. ! 1227: */ ! 1228: ! 1229: public popenv() ! 1230: { ! 1231: String filename; ! 1232: ! 1233: setreg(FRP, pop(Word)); ! 1234: setreg(STKP, pop(Word)); ! 1235: setreg(PROGCTR, pop(Word)); ! 1236: endproc = pop(CallEnv); ! 1237: curframerec = pop(struct Frame); ! 1238: curframe = pop(Frame); ! 1239: curfunc = pop(Symbol); ! 1240: isstopped = pop(Boolean); ! 1241: filename = pop(String); ! 1242: curline = pop(Lineno); ! 1243: pc = pop(Address); ! 1244: setsource(filename); ! 1245: } ! 1246: ! 1247: /* ! 1248: * Flush the debuggee's standard output. ! 1249: * ! 1250: * This is VERY dependent on the use of stdio. ! 1251: */ ! 1252: ! 1253: public flushoutput() ! 1254: { ! 1255: Symbol p, iob; ! 1256: Stack *savesp; ! 1257: ! 1258: p = lookup(identname("fflush", true)); ! 1259: while (p != nil and not isblock(p)) { ! 1260: p = p->next_sym; ! 1261: } ! 1262: if (p != nil) { ! 1263: iob = lookup(identname("_iob", true)); ! 1264: if (iob != nil) { ! 1265: pushenv(); ! 1266: pc = codeloc(p) - FUNCOFFSET; ! 1267: savesp = sp; ! 1268: push(long, address(iob, nil) + sizeof(*stdout)); ! 1269: setreg(STKP, reg(STKP) - sizeof(long)); ! 1270: dwrite(savesp, reg(STKP), sizeof(long)); ! 1271: sp = savesp; ! 1272: beginproc(p, 1); ! 1273: stepto(return_addr()); ! 1274: popenv(); ! 1275: } ! 1276: } ! 1277: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.