|
|
1.1 ! root 1: ! 2: /* Copyright (c) 1982 Regents of the University of California */ ! 3: ! 4: static char sccsid[] = "@(#)runtime.c 1.9 8/14/83"; ! 5: ! 6: /* ! 7: * Runtime organization dependent routines, mostly dealing with ! 8: * activation records. ! 9: */ ! 10: ! 11: #include "defs.h" ! 12: #include "runtime.h" ! 13: #include "process.h" ! 14: #include "machine.h" ! 15: #include "events.h" ! 16: #include "mappings.h" ! 17: #include "symbols.h" ! 18: #include "tree.h" ! 19: #include "eval.h" ! 20: #include "operators.h" ! 21: #include "object.h" ! 22: #include <sys/param.h> ! 23: ! 24: #ifndef public ! 25: typedef struct Frame *Frame; ! 26: ! 27: #include "machine.h" ! 28: #endif ! 29: ! 30: #define NSAVEREG 12 ! 31: ! 32: struct Frame { ! 33: Integer condition_handler; ! 34: Integer mask; ! 35: Address save_ap; /* argument pointer */ ! 36: Address save_fp; /* frame pointer */ ! 37: Address save_pc; /* program counter */ ! 38: Word save_reg[NSAVEREG]; /* not necessarily there */ ! 39: }; ! 40: ! 41: private Boolean walkingstack = false; ! 42: ! 43: /* ! 44: * Set a frame to the current activation record. ! 45: */ ! 46: ! 47: private getcurframe(frp) ! 48: register Frame frp; ! 49: { ! 50: register int i; ! 51: ! 52: checkref(frp); ! 53: frp->mask = reg(NREG); ! 54: frp->save_ap = reg(ARGP); ! 55: frp->save_fp = reg(FRP); ! 56: frp->save_pc = reg(PROGCTR) + 1; ! 57: for (i = 0; i < NSAVEREG; i++) { ! 58: frp->save_reg[i] = reg(i); ! 59: } ! 60: } ! 61: ! 62: /* ! 63: * Return a pointer to the next activation record up the stack. ! 64: * Return nil if there is none. ! 65: * Writes over space pointed to by given argument. ! 66: */ ! 67: ! 68: #define bis(b, n) ((b & (1 << (n))) != 0) ! 69: ! 70: private Frame nextframe(frp) ! 71: Frame frp; ! 72: { ! 73: register Frame newfrp; ! 74: struct Frame frame; ! 75: register Integer i, j, mask; ! 76: Address prev_frame, callpc; ! 77: static Integer ntramp = 0; ! 78: ! 79: newfrp = frp; ! 80: prev_frame = frp->save_fp; ! 81: ! 82: /* ! 83: * The check for interrupt generated frames is taken from adb with only ! 84: * partial understanding. If you're in "sub" and on a sigxxx "sigsub" ! 85: * gets control, then the stack does NOT look like <main, sub, sigsub>. ! 86: * ! 87: * As best I can make out it looks like: ! 88: * ! 89: * <main, (machine check exception block + sub), sysframe, sigsub>. ! 90: * ! 91: * When the signal occurs an exception block and a frame for the routine ! 92: * in which it occured are pushed on the user stack. Then another frame ! 93: * is pushed corresponding to a call from the kernel to sigsub. ! 94: * ! 95: * The addr in sub at which the exception occured is not in sub.save_pc ! 96: * but in the machine check exception block. It is at the magic address ! 97: * fp + 84. ! 98: * ! 99: * The current approach ignores the sys_frame (what adb reports as sigtramp) ! 100: * and takes the pc for sub from the exception block. This allows the ! 101: * "where" command to report <main, sub, sigsub>, which seems reasonable. ! 102: */ ! 103: ! 104: nextf: ! 105: dread(&frame, prev_frame, sizeof(struct Frame)); ! 106: if (ntramp == 1) { ! 107: dread(&callpc, prev_frame + 84, sizeof(callpc)); ! 108: } else { ! 109: callpc = frame.save_pc; ! 110: } ! 111: if (frame.save_fp == nil) { ! 112: newfrp = nil; ! 113: } else if (callpc > 0x80000000 - 0x200 * UPAGES ) { ! 114: ntramp++; ! 115: prev_frame = frame.save_fp; ! 116: goto nextf; ! 117: } else { ! 118: frame.save_pc = callpc; ! 119: ntramp = 0; ! 120: mask = ((frame.mask >> 16) & 0x0fff); ! 121: j = 0; ! 122: for (i = 0; i < NSAVEREG; i++) { ! 123: if (bis(mask, i)) { ! 124: newfrp->save_reg[i] = frame.save_reg[j]; ! 125: ++j; ! 126: } ! 127: } ! 128: newfrp->condition_handler = frame.condition_handler; ! 129: newfrp->mask = mask; ! 130: newfrp->save_ap = frame.save_ap; ! 131: newfrp->save_fp = frame.save_fp; ! 132: newfrp->save_pc = frame.save_pc; ! 133: } ! 134: return newfrp; ! 135: } ! 136: ! 137: /* ! 138: * Return the frame associated with the given function. ! 139: * If the function is nil, return the most recently activated frame. ! 140: * ! 141: * Static allocation for the frame. ! 142: */ ! 143: ! 144: public Frame findframe(f) ! 145: Symbol f; ! 146: { ! 147: register Frame frp; ! 148: static struct Frame frame; ! 149: Symbol p; ! 150: Boolean done; ! 151: ! 152: frp = &frame; ! 153: getcurframe(frp); ! 154: if (f != nil) { ! 155: done = false; ! 156: do { ! 157: p = whatblock(frp->save_pc); ! 158: if (p == f) { ! 159: done = true; ! 160: } else if (p == program) { ! 161: done = true; ! 162: frp = nil; ! 163: } else { ! 164: frp = nextframe(frp); ! 165: if (frp == nil) { ! 166: done = true; ! 167: } ! 168: } ! 169: } while (not done); ! 170: } ! 171: return frp; ! 172: } ! 173: ! 174: /* ! 175: * Find the return address of the current procedure/function. ! 176: */ ! 177: ! 178: public Address return_addr() ! 179: { ! 180: Frame frp; ! 181: Address addr; ! 182: struct Frame frame; ! 183: ! 184: frp = &frame; ! 185: getcurframe(frp); ! 186: frp = nextframe(frp); ! 187: if (frp == nil) { ! 188: addr = 0; ! 189: } else { ! 190: addr = frp->save_pc; ! 191: } ! 192: return addr; ! 193: } ! 194: ! 195: /* ! 196: * Push the value associated with the current function. ! 197: */ ! 198: ! 199: public pushretval(len, isindirect) ! 200: Integer len; ! 201: Boolean isindirect; ! 202: { ! 203: Word r0; ! 204: ! 205: r0 = reg(0); ! 206: if (isindirect) { ! 207: rpush((Address) r0, len); ! 208: } else { ! 209: switch (len) { ! 210: case sizeof(char): ! 211: push(char, r0); ! 212: break; ! 213: ! 214: case sizeof(short): ! 215: push(short, r0); ! 216: break; ! 217: ! 218: default: ! 219: if (len == sizeof(Word)) { ! 220: push(Word, r0); ! 221: } else if (len == 2*sizeof(Word)) { ! 222: push(Word, r0); ! 223: push(Word, reg(1)); ! 224: } else { ! 225: panic("not indirect in pushretval?"); ! 226: } ! 227: break; ! 228: } ! 229: } ! 230: } ! 231: ! 232: /* ! 233: * Return the base address for locals in the given frame. ! 234: */ ! 235: ! 236: public Address locals_base(frp) ! 237: register Frame frp; ! 238: { ! 239: return (frp == nil) ? reg(FRP) : frp->save_fp; ! 240: } ! 241: ! 242: /* ! 243: * Return the base address for arguments in the given frame. ! 244: */ ! 245: ! 246: public Address args_base(frp) ! 247: register Frame frp; ! 248: { ! 249: return (frp == nil) ? reg(ARGP) : frp->save_ap; ! 250: } ! 251: ! 252: /* ! 253: * Return saved register n from the given frame. ! 254: */ ! 255: ! 256: public Word savereg(n, frp) ! 257: register Integer n; ! 258: register Frame frp; ! 259: { ! 260: register Word w; ! 261: ! 262: if (frp == nil) { ! 263: w = reg(n); ! 264: } else { ! 265: switch (n) { ! 266: case ARGP: ! 267: w = frp->save_ap; ! 268: break; ! 269: ! 270: case FRP: ! 271: w = frp->save_fp; ! 272: break; ! 273: ! 274: case STKP: ! 275: w = reg(STKP); ! 276: break; ! 277: ! 278: case PROGCTR: ! 279: w = frp->save_pc; ! 280: break; ! 281: ! 282: default: ! 283: assert(n >= 0 and n < NSAVEREG); ! 284: w = frp->save_reg[n]; ! 285: break; ! 286: } ! 287: } ! 288: return w; ! 289: } ! 290: ! 291: /* ! 292: * Return the nth argument to the current procedure. ! 293: */ ! 294: ! 295: public Word argn(n, frp) ! 296: Integer n; ! 297: Frame frp; ! 298: { ! 299: Word w; ! 300: ! 301: dread(&w, args_base(frp) + (n * sizeof(Word)), sizeof(w)); ! 302: return w; ! 303: } ! 304: ! 305: /* ! 306: * Calculate the entry address for a procedure or function parameter, ! 307: * given the address of the descriptor. ! 308: */ ! 309: ! 310: public Address fparamaddr(a) ! 311: Address a; ! 312: { ! 313: Address r; ! 314: ! 315: dread(&r, a, sizeof(r)); ! 316: return r; ! 317: } ! 318: ! 319: /* ! 320: * Print a list of currently active blocks starting with most recent. ! 321: */ ! 322: ! 323: public wherecmd() ! 324: { ! 325: walkstack(false); ! 326: } ! 327: ! 328: /* ! 329: * Dump the world to the given file. ! 330: * Like "where", but variables are dumped also. ! 331: */ ! 332: ! 333: public dump() ! 334: { ! 335: walkstack(true); ! 336: } ! 337: ! 338: /* ! 339: * Walk the stack of active procedures printing information ! 340: * about each active procedure. ! 341: */ ! 342: ! 343: private walkstack(dumpvariables) ! 344: Boolean dumpvariables; ! 345: { ! 346: register Frame frp; ! 347: register Symbol f; ! 348: register Boolean save; ! 349: register Lineno line; ! 350: struct Frame frame; ! 351: ! 352: if (notstarted(process)) { ! 353: error("program is not active"); ! 354: } else { ! 355: save = walkingstack; ! 356: walkingstack = true; ! 357: frp = &frame; ! 358: getcurframe(frp); ! 359: f = whatblock(frp->save_pc); ! 360: do { ! 361: printf("%s", symname(f)); ! 362: if (not isinline(f)) { ! 363: printparams(f, frp); ! 364: } ! 365: line = srcline(frp->save_pc - 1); ! 366: if (line != 0) { ! 367: printf(", line %d", line); ! 368: printf(" in \"%s\"\n", srcfilename(frp->save_pc - 1)); ! 369: } else { ! 370: printf(" at 0x%x\n", frp->save_pc); ! 371: } ! 372: if (dumpvariables) { ! 373: dumpvars(f, frp); ! 374: putchar('\n'); ! 375: } ! 376: if (isinline(f)) { ! 377: f = container(f); ! 378: } else { ! 379: frp = nextframe(frp); ! 380: if (frp != nil) { ! 381: f = whatblock(frp->save_pc); ! 382: } ! 383: } ! 384: } while (frp != nil and f != program); ! 385: if (dumpvariables) { ! 386: printf("in \"%s\":\n", symname(program)); ! 387: dumpvars(program, nil); ! 388: putchar('\n'); ! 389: } ! 390: walkingstack = save; ! 391: } ! 392: } ! 393: ! 394: /* ! 395: * Find the entry point of a procedure or function. ! 396: */ ! 397: ! 398: public findbeginning(f) ! 399: Symbol f; ! 400: { ! 401: f->symvalue.funcv.beginaddr += 2; ! 402: } ! 403: ! 404: /* ! 405: * Return the address corresponding to the first line in a function. ! 406: */ ! 407: ! 408: public Address firstline(f) ! 409: Symbol f; ! 410: { ! 411: Address addr; ! 412: ! 413: addr = codeloc(f); ! 414: while (linelookup(addr) == 0 and addr < objsize) { ! 415: ++addr; ! 416: } ! 417: if (addr == objsize) { ! 418: addr = -1; ! 419: } ! 420: return addr; ! 421: } ! 422: ! 423: /* ! 424: * Catcher drops strike three ... ! 425: */ ! 426: ! 427: public runtofirst() ! 428: { ! 429: Address addr; ! 430: ! 431: addr = pc; ! 432: while (linelookup(addr) == 0 and addr < objsize) { ! 433: ++addr; ! 434: } ! 435: if (addr < objsize) { ! 436: stepto(addr); ! 437: } ! 438: } ! 439: ! 440: /* ! 441: * Return the address corresponding to the end of the program. ! 442: * ! 443: * We look for the entry to "exit". ! 444: */ ! 445: ! 446: public Address lastaddr() ! 447: { ! 448: register Symbol s; ! 449: ! 450: s = lookup(identname("exit", true)); ! 451: if (s == nil) { ! 452: panic("can't find exit"); ! 453: } ! 454: return codeloc(s); ! 455: } ! 456: ! 457: /* ! 458: * Decide if the given function is currently active. ! 459: * ! 460: * We avoid calls to "findframe" during a stack trace for efficiency. ! 461: * Presumably information evaluated while walking the stack is active. ! 462: */ ! 463: ! 464: public Boolean isactive(f) ! 465: Symbol f; ! 466: { ! 467: register Boolean b; ! 468: ! 469: if (isfinished(process)) { ! 470: b = false; ! 471: } else { ! 472: if (walkingstack or f == program or ! 473: (ismodule(f) and isactive(container(f)))) { ! 474: b = true; ! 475: } else { ! 476: b = (Boolean) (findframe(f) != nil); ! 477: } ! 478: } ! 479: return b; ! 480: } ! 481: ! 482: /* ! 483: * Evaluate a call to a procedure. ! 484: */ ! 485: ! 486: public callproc(procnode, arglist) ! 487: Node procnode; ! 488: Node arglist; ! 489: { ! 490: Symbol proc; ! 491: Integer argc; ! 492: ! 493: if (procnode->op != O_SYM) { ! 494: beginerrmsg(); ! 495: fprintf(stderr, "can't call \""); ! 496: prtree(stderr, procnode); ! 497: fprintf(stderr, "\""); ! 498: enderrmsg(); ! 499: } ! 500: assert(procnode->op == O_SYM); ! 501: proc = procnode->value.sym; ! 502: if (not isblock(proc)) { ! 503: error("\"%s\" is not a procedure or function", symname(proc)); ! 504: } ! 505: pushenv(); ! 506: pc = codeloc(proc); ! 507: argc = pushargs(proc, arglist); ! 508: beginproc(proc, argc); ! 509: isstopped = true; ! 510: event_once(build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)), ! 511: buildcmdlist(build(O_PROCRTN, proc))); ! 512: cont(); ! 513: /* NOTREACHED */ ! 514: } ! 515: ! 516: /* ! 517: * Push the arguments on the process' stack. We do this by first ! 518: * evaluating them on the "eval" stack, then copying into the process' ! 519: * space. ! 520: */ ! 521: ! 522: private Integer pushargs(proc, arglist) ! 523: Symbol proc; ! 524: Node arglist; ! 525: { ! 526: Stack *savesp; ! 527: int argc, args_size; ! 528: ! 529: savesp = sp; ! 530: argc = evalargs(proc, arglist); ! 531: args_size = sp - savesp; ! 532: setreg(STKP, reg(STKP) - args_size); ! 533: dwrite(savesp, reg(STKP), args_size); ! 534: sp = savesp; ! 535: return argc; ! 536: } ! 537: ! 538: /* ! 539: * Evaluate arguments left-to-right. ! 540: */ ! 541: ! 542: private Integer evalargs(proc, arglist) ! 543: Symbol proc; ! 544: Node arglist; ! 545: { ! 546: Node p, exp; ! 547: Symbol arg; ! 548: Stack *savesp; ! 549: Address addr; ! 550: Integer count; ! 551: ! 552: savesp = sp; ! 553: count = 0; ! 554: arg = proc->chain; ! 555: for (p = arglist; p != nil; p = p->value.arg[1]) { ! 556: if (p->op != O_COMMA) { ! 557: panic("evalargs: arglist missing comma"); ! 558: } ! 559: if (arg == nil) { ! 560: sp = savesp; ! 561: error("too many parameters to %s", symname(proc)); ! 562: } ! 563: exp = p->value.arg[0]; ! 564: if (not compatible(arg->type, exp->nodetype)) { ! 565: sp = savesp; ! 566: error("expression for parameter %s is of wrong type", symname(arg)); ! 567: } ! 568: if (arg->class == REF) { ! 569: if (exp->op != O_RVAL) { ! 570: sp = savesp; ! 571: error("variable expected for parameter \"%s\"", symname(arg)); ! 572: } ! 573: addr = lval(exp->value.arg[0]); ! 574: push(Address, addr); ! 575: } else { ! 576: eval(exp); ! 577: } ! 578: arg = arg->chain; ! 579: ++count; ! 580: } ! 581: if (arg != nil) { ! 582: sp = savesp; ! 583: error("not enough parameters to %s", symname(proc)); ! 584: } ! 585: return count; ! 586: } ! 587: ! 588: public procreturn(f) ! 589: Symbol f; ! 590: { ! 591: flushoutput(); ! 592: putchar('\n'); ! 593: printname(stdout, f); ! 594: printf(" returns successfully\n", symname(f)); ! 595: popenv(); ! 596: erecover(); ! 597: } ! 598: ! 599: /* ! 600: * Push the current environment. ! 601: */ ! 602: ! 603: private pushenv() ! 604: { ! 605: push(Address, pc); ! 606: push(Lineno, curline); ! 607: push(String, cursource); ! 608: push(Boolean, isstopped); ! 609: push(Symbol, curfunc); ! 610: push(Word, reg(PROGCTR)); ! 611: push(Word, reg(STKP)); ! 612: } ! 613: ! 614: /* ! 615: * Pop back to the real world. ! 616: */ ! 617: ! 618: public popenv() ! 619: { ! 620: register String filename; ! 621: ! 622: setreg(STKP, pop(Word)); ! 623: setreg(PROGCTR, pop(Word)); ! 624: curfunc = pop(Symbol); ! 625: isstopped = pop(Boolean); ! 626: filename = pop(String); ! 627: curline = pop(Lineno); ! 628: pc = pop(Address); ! 629: setsource(filename); ! 630: } ! 631: ! 632: /* ! 633: * Flush the debuggee's standard output. ! 634: * ! 635: * This is VERY dependent on the use of stdio. ! 636: */ ! 637: ! 638: public flushoutput() ! 639: { ! 640: register Symbol p, iob; ! 641: register Stack *savesp; ! 642: ! 643: p = lookup(identname("fflush", true)); ! 644: while (p != nil and not isblock(p)) { ! 645: p = p->next_sym; ! 646: } ! 647: if (p != nil) { ! 648: iob = lookup(identname("_iob", true)); ! 649: if (iob != nil) { ! 650: pushenv(); ! 651: pc = codeloc(p); ! 652: savesp = sp; ! 653: push(long, address(iob, nil) + sizeof(struct _iobuf)); ! 654: setreg(STKP, reg(STKP) - sizeof(long)); ! 655: dwrite(savesp, reg(STKP), sizeof(long)); ! 656: sp = savesp; ! 657: beginproc(p, 1); ! 658: stepto(return_addr()); ! 659: popenv(); ! 660: } ! 661: } ! 662: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.