123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663 |
- /* Copyright (c) 1982 Regents of the University of California */
- static char sccsid[] = "@(#)runtime.c 1.9 8/14/83";
- /*
- * Runtime organization dependent routines, mostly dealing with
- * activation records.
- */
- #include "defs.h"
- #include "runtime.h"
- #include "process.h"
- #include "machine.h"
- #include "events.h"
- #include "mappings.h"
- #include "symbols.h"
- #include "tree.h"
- #include "eval.h"
- #include "operators.h"
- #include "object.h"
- #include <sys/param.h>
- #ifndef public
- typedef struct Frame *Frame;
- #include "machine.h"
- #endif
- #define NSAVEREG 12
- struct Frame {
- Integer condition_handler;
- Integer mask;
- Address save_ap; /* argument pointer */
- Address save_fp; /* frame pointer */
- Address save_pc; /* program counter */
- Word save_reg[NSAVEREG]; /* not necessarily there */
- };
- private Boolean walkingstack = false;
- /*
- * Set a frame to the current activation record.
- */
- private getcurframe(frp)
- register Frame frp;
- {
- register int i;
- checkref(frp);
- frp->mask = reg(NREG);
- frp->save_ap = reg(ARGP);
- frp->save_fp = reg(FRP);
- frp->save_pc = reg(PROGCTR) + 1;
- for (i = 0; i < NSAVEREG; i++) {
- frp->save_reg[i] = reg(i);
- }
- }
- /*
- * Return a pointer to the next activation record up the stack.
- * Return nil if there is none.
- * Writes over space pointed to by given argument.
- */
- #define bis(b, n) ((b & (1 << (n))) != 0)
- private Frame nextframe(frp)
- Frame frp;
- {
- register Frame newfrp;
- struct Frame frame;
- register Integer i, j, mask;
- Address prev_frame, callpc;
- static Integer ntramp = 0;
- newfrp = frp;
- prev_frame = frp->save_fp;
- /*
- * The check for interrupt generated frames is taken from adb with only
- * partial understanding. If you're in "sub" and on a sigxxx "sigsub"
- * gets control, then the stack does NOT look like <main, sub, sigsub>.
- *
- * As best I can make out it looks like:
- *
- * <main, (machine check exception block + sub), sysframe, sigsub>.
- *
- * When the signal occurs an exception block and a frame for the routine
- * in which it occured are pushed on the user stack. Then another frame
- * is pushed corresponding to a call from the kernel to sigsub.
- *
- * The addr in sub at which the exception occured is not in sub.save_pc
- * but in the machine check exception block. It is at the magic address
- * fp + 84.
- *
- * The current approach ignores the sys_frame (what adb reports as sigtramp)
- * and takes the pc for sub from the exception block. This allows the
- * "where" command to report <main, sub, sigsub>, which seems reasonable.
- */
- nextf:
- dread(&frame, prev_frame, sizeof(struct Frame));
- if (ntramp == 1) {
- dread(&callpc, prev_frame + 84, sizeof(callpc));
- } else {
- callpc = frame.save_pc;
- }
- if (frame.save_fp == nil) {
- newfrp = nil;
- } else if (callpc > 0x80000000 - 0x200 * UPAGES ) {
- ntramp++;
- prev_frame = frame.save_fp;
- goto nextf;
- } else {
- frame.save_pc = callpc;
- ntramp = 0;
- mask = ((frame.mask >> 16) & 0x0fff);
- j = 0;
- for (i = 0; i < NSAVEREG; i++) {
- if (bis(mask, i)) {
- newfrp->save_reg[i] = frame.save_reg[j];
- ++j;
- }
- }
- newfrp->condition_handler = frame.condition_handler;
- newfrp->mask = mask;
- newfrp->save_ap = frame.save_ap;
- newfrp->save_fp = frame.save_fp;
- newfrp->save_pc = frame.save_pc;
- }
- return newfrp;
- }
- /*
- * Return the frame associated with the given function.
- * If the function is nil, return the most recently activated frame.
- *
- * Static allocation for the frame.
- */
- public Frame findframe(f)
- Symbol f;
- {
- register Frame frp;
- static struct Frame frame;
- Symbol p;
- Boolean done;
- frp = &frame;
- getcurframe(frp);
- if (f != nil) {
- done = false;
- do {
- p = whatblock(frp->save_pc);
- if (p == f) {
- done = true;
- } else if (p == program) {
- done = true;
- frp = nil;
- } else {
- frp = nextframe(frp);
- if (frp == nil) {
- done = true;
- }
- }
- } while (not done);
- }
- return frp;
- }
- /*
- * Find the return address of the current procedure/function.
- */
- public Address return_addr()
- {
- Frame frp;
- Address addr;
- struct Frame frame;
- frp = &frame;
- getcurframe(frp);
- frp = nextframe(frp);
- if (frp == nil) {
- addr = 0;
- } else {
- addr = frp->save_pc;
- }
- return addr;
- }
- /*
- * Push the value associated with the current function.
- */
- public pushretval(len, isindirect)
- Integer len;
- Boolean isindirect;
- {
- Word r0;
- r0 = reg(0);
- if (isindirect) {
- rpush((Address) r0, len);
- } else {
- switch (len) {
- case sizeof(char):
- push(char, r0);
- break;
- case sizeof(short):
- push(short, r0);
- break;
- default:
- if (len == sizeof(Word)) {
- push(Word, r0);
- } else if (len == 2*sizeof(Word)) {
- push(Word, r0);
- push(Word, reg(1));
- } else {
- panic("not indirect in pushretval?");
- }
- break;
- }
- }
- }
- /*
- * Return the base address for locals in the given frame.
- */
- public Address locals_base(frp)
- register Frame frp;
- {
- return (frp == nil) ? reg(FRP) : frp->save_fp;
- }
- /*
- * Return the base address for arguments in the given frame.
- */
- public Address args_base(frp)
- register Frame frp;
- {
- return (frp == nil) ? reg(ARGP) : frp->save_ap;
- }
- /*
- * Return saved register n from the given frame.
- */
- public Word savereg(n, frp)
- register Integer n;
- register Frame frp;
- {
- register Word w;
- if (frp == nil) {
- w = reg(n);
- } else {
- switch (n) {
- case ARGP:
- w = frp->save_ap;
- break;
- case FRP:
- w = frp->save_fp;
- break;
- case STKP:
- w = reg(STKP);
- break;
- case PROGCTR:
- w = frp->save_pc;
- break;
- default:
- assert(n >= 0 and n < NSAVEREG);
- w = frp->save_reg[n];
- break;
- }
- }
- return w;
- }
- /*
- * Return the nth argument to the current procedure.
- */
- public Word argn(n, frp)
- Integer n;
- Frame frp;
- {
- Word w;
- dread(&w, args_base(frp) + (n * sizeof(Word)), sizeof(w));
- return w;
- }
- /*
- * Calculate the entry address for a procedure or function parameter,
- * given the address of the descriptor.
- */
- public Address fparamaddr(a)
- Address a;
- {
- Address r;
- dread(&r, a, sizeof(r));
- return r;
- }
- /*
- * Print a list of currently active blocks starting with most recent.
- */
- public wherecmd()
- {
- walkstack(false);
- }
- /*
- * Dump the world to the given file.
- * Like "where", but variables are dumped also.
- */
- public dump()
- {
- walkstack(true);
- }
- /*
- * Walk the stack of active procedures printing information
- * about each active procedure.
- */
- private walkstack(dumpvariables)
- Boolean dumpvariables;
- {
- register Frame frp;
- register Symbol f;
- register Boolean save;
- register Lineno line;
- struct Frame frame;
- if (notstarted(process)) {
- error("program is not active");
- } else {
- save = walkingstack;
- walkingstack = true;
- frp = &frame;
- getcurframe(frp);
- f = whatblock(frp->save_pc);
- do {
- printf("%s", symname(f));
- if (not isinline(f)) {
- printparams(f, frp);
- }
- line = srcline(frp->save_pc - 1);
- if (line != 0) {
- printf(", line %d", line);
- printf(" in \"%s\"\n", srcfilename(frp->save_pc - 1));
- } else {
- printf(" at 0x%x\n", frp->save_pc);
- }
- if (dumpvariables) {
- dumpvars(f, frp);
- putchar('\n');
- }
- if (isinline(f)) {
- f = container(f);
- } else {
- frp = nextframe(frp);
- if (frp != nil) {
- f = whatblock(frp->save_pc);
- }
- }
- } while (frp != nil and f != program);
- if (dumpvariables) {
- printf("in \"%s\":\n", symname(program));
- dumpvars(program, nil);
- putchar('\n');
- }
- walkingstack = save;
- }
- }
- /*
- * Find the entry point of a procedure or function.
- */
- public findbeginning(f)
- Symbol f;
- {
- f->symvalue.funcv.beginaddr += 2;
- }
- /*
- * Return the address corresponding to the first line in a function.
- */
- public Address firstline(f)
- Symbol f;
- {
- Address addr;
- addr = codeloc(f);
- while (linelookup(addr) == 0 and addr < objsize) {
- ++addr;
- }
- if (addr == objsize) {
- addr = -1;
- }
- return addr;
- }
- /*
- * Catcher drops strike three ...
- */
- public runtofirst()
- {
- Address addr;
- addr = pc;
- while (linelookup(addr) == 0 and addr < objsize) {
- ++addr;
- }
- if (addr < objsize) {
- stepto(addr);
- }
- }
- /*
- * Return the address corresponding to the end of the program.
- *
- * We look for the entry to "exit".
- */
- public Address lastaddr()
- {
- register Symbol s;
- s = lookup(identname("exit", true));
- if (s == nil) {
- panic("can't find exit");
- }
- return codeloc(s);
- }
- /*
- * Decide if the given function is currently active.
- *
- * We avoid calls to "findframe" during a stack trace for efficiency.
- * Presumably information evaluated while walking the stack is active.
- */
- public Boolean isactive(f)
- Symbol f;
- {
- register Boolean b;
- if (isfinished(process)) {
- b = false;
- } else {
- if (walkingstack or f == program or
- (ismodule(f) and isactive(container(f)))) {
- b = true;
- } else {
- b = (Boolean) (findframe(f) != nil);
- }
- }
- return b;
- }
- /*
- * Evaluate a call to a procedure.
- */
- public callproc(procnode, arglist)
- Node procnode;
- Node arglist;
- {
- Symbol proc;
- Integer argc;
- if (procnode->op != O_SYM) {
- beginerrmsg();
- fprintf(stderr, "can't call \"");
- prtree(stderr, procnode);
- fprintf(stderr, "\"");
- enderrmsg();
- }
- assert(procnode->op == O_SYM);
- proc = procnode->value.sym;
- if (not isblock(proc)) {
- error("\"%s\" is not a procedure or function", symname(proc));
- }
- pushenv();
- pc = codeloc(proc);
- argc = pushargs(proc, arglist);
- beginproc(proc, argc);
- isstopped = true;
- event_once(build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)),
- buildcmdlist(build(O_PROCRTN, proc)));
- cont();
- /* NOTREACHED */
- }
- /*
- * Push the arguments on the process' stack. We do this by first
- * evaluating them on the "eval" stack, then copying into the process'
- * space.
- */
- private Integer pushargs(proc, arglist)
- Symbol proc;
- Node arglist;
- {
- Stack *savesp;
- int argc, args_size;
- savesp = sp;
- argc = evalargs(proc, arglist);
- args_size = sp - savesp;
- setreg(STKP, reg(STKP) - args_size);
- dwrite(savesp, reg(STKP), args_size);
- sp = savesp;
- return argc;
- }
- /*
- * Evaluate arguments left-to-right.
- */
- private Integer evalargs(proc, arglist)
- Symbol proc;
- Node arglist;
- {
- Node p, exp;
- Symbol arg;
- Stack *savesp;
- Address addr;
- Integer count;
- savesp = sp;
- count = 0;
- arg = proc->chain;
- for (p = arglist; p != nil; p = p->value.arg[1]) {
- if (p->op != O_COMMA) {
- panic("evalargs: arglist missing comma");
- }
- if (arg == nil) {
- sp = savesp;
- error("too many parameters to %s", symname(proc));
- }
- exp = p->value.arg[0];
- if (not compatible(arg->type, exp->nodetype)) {
- sp = savesp;
- error("expression for parameter %s is of wrong type", symname(arg));
- }
- if (arg->class == REF) {
- if (exp->op != O_RVAL) {
- sp = savesp;
- error("variable expected for parameter \"%s\"", symname(arg));
- }
- addr = lval(exp->value.arg[0]);
- push(Address, addr);
- } else {
- eval(exp);
- }
- arg = arg->chain;
- ++count;
- }
- if (arg != nil) {
- sp = savesp;
- error("not enough parameters to %s", symname(proc));
- }
- return count;
- }
- public procreturn(f)
- Symbol f;
- {
- flushoutput();
- putchar('\n');
- printname(stdout, f);
- printf(" returns successfully\n", symname(f));
- popenv();
- erecover();
- }
- /*
- * Push the current environment.
- */
- private pushenv()
- {
- push(Address, pc);
- push(Lineno, curline);
- push(String, cursource);
- push(Boolean, isstopped);
- push(Symbol, curfunc);
- push(Word, reg(PROGCTR));
- push(Word, reg(STKP));
- }
- /*
- * Pop back to the real world.
- */
- public popenv()
- {
- register String filename;
- setreg(STKP, pop(Word));
- setreg(PROGCTR, pop(Word));
- curfunc = pop(Symbol);
- isstopped = pop(Boolean);
- filename = pop(String);
- curline = pop(Lineno);
- pc = pop(Address);
- setsource(filename);
- }
- /*
- * Flush the debuggee's standard output.
- *
- * This is VERY dependent on the use of stdio.
- */
- public flushoutput()
- {
- register Symbol p, iob;
- register Stack *savesp;
- p = lookup(identname("fflush", true));
- while (p != nil and not isblock(p)) {
- p = p->next_sym;
- }
- if (p != nil) {
- iob = lookup(identname("_iob", true));
- if (iob != nil) {
- pushenv();
- pc = codeloc(p);
- savesp = sp;
- push(long, address(iob, nil) + sizeof(struct _iobuf));
- setreg(STKP, reg(STKP) - sizeof(long));
- dwrite(savesp, reg(STKP), sizeof(long));
- sp = savesp;
- beginproc(p, 1);
- stepto(return_addr());
- popenv();
- }
- }
- }
|