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