📄 runtime.tahoe.c
字号:
public setcurfunc (f)Symbol f;{ curfunc = f; curframe = nil;}/* * Return the frame for the current function. * The space for the frame is allocated statically. */public Frame curfuncframe (){ static struct Frame frame; Frame frp; if (curframe == nil) { frp = findframe(curfunc); curframe = &curframerec; *curframe = *frp; } else { frp = &frame; *frp = *curframe; } return frp;}/* * Set curfunc to be N up/down the stack from its current value. */public up (n)integer n;{ integer i; Symbol f; Frame frp; boolean done; if (not isactive(program)) { error("program is not active"); } else if (curfunc == nil) { error("no current function"); } else { i = 0; f = curfunc; frp = curfuncframe(); done = false; do { if (frp == nil) { done = true; error("not that many levels"); } else if (i >= n) { done = true; curfunc = f; curframe = &curframerec; *curframe = *frp; showaggrs = false; printcallinfo(curfunc, curframe); } else if (f == program) { done = true; error("not that many levels"); } else { frp = nextfunc(frp, &f); } ++i; } while (not done); }}public down (n)integer n;{ integer i, depth; Frame frp, curfrp; Symbol f; struct Frame frame; if (not isactive(program)) { error("program is not active"); } else if (curfunc == nil) { error("no current function"); } else { depth = 0; frp = &frame; getcurfunc(frp, &f); if (curframe == nil) { curfrp = findframe(curfunc); curframe = &curframerec; *curframe = *curfrp; } while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) { frp = nextfunc(frp, &f); ++depth; } if (f == nil or n > depth) { error("not that many levels"); } else { depth -= n; frp = &frame; getcurfunc(frp, &f); for (i = 0; i < depth; i++) { frp = nextfunc(frp, &f); assert(frp != nil); } curfunc = f; *curframe = *frp; showaggrs = false; printcallinfo(curfunc, curframe); } }}/* * Find the entry point of a procedure or function. */public findbeginning (f)Symbol f;{ if (isinternal(f)) { f->symvalue.funcv.beginaddr += 15; } else { f->symvalue.funcv.beginaddr += FUNCOFFSET; }}/* * 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, endaddr; addr = pc; endaddr = objsize + CODESTART; while (linelookup(addr) == 0 and addr < endaddr) { ++addr; } if (addr < endaddr) { stepto(addr); }}/* * Return the address corresponding to the end of the program. * * We look for the entry to "exit". */public Address lastaddr(){ 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;{ Boolean b; if (isfinished(process)) { b = false; } else { if (walkingstack or f == program or f == nil 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(exprnode, isfunc)Node exprnode;boolean isfunc;{ Node procnode, arglist; Symbol proc; integer argc; procnode = exprnode->value.arg[0]; arglist = exprnode->value.arg[1]; 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)); } endproc.isfunc = isfunc; endproc.callnode = exprnode; endproc.cmdnode = topnode; pushenv(); pc = codeloc(proc); argc = pushargs(proc, arglist); setreg(FRP, 1); /* have to ensure it's non-zero for return_addr() */ beginproc(proc, argc); event_once( build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)), buildcmdlist(build(O_PROCRTN, proc)) ); isstopped = false; if (not bpact()) { isstopped = true; cont(0); } /* * bpact() won't return true, it will call printstatus() and go back * to command input if a breakpoint is found. */ /* 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; if (varIsSet("$unsafecall")) { argc = unsafe_evalargs(proc, arglist); } else { argc = evalargs(proc, arglist); } argc = evalargs(proc, arglist); args_size = sp - savesp; setreg(STKP, reg(STKP) - args_size); dwrite(savesp, reg(STKP), args_size); sp = savesp; return argc;}/* * Check to see if an expression is correct for a given parameter. * If the given parameter is false, don't worry about type inconsistencies. * * Return whether or not it is ok. */private boolean chkparam (actual, formal, chk)Node actual;Symbol formal;boolean chk;{ boolean b; b = true; if (chk) { if (formal == nil) { beginerrmsg(); fprintf(stderr, "too many parameters"); b = false; } else if (not compatible(formal->type, actual->nodetype)) { beginerrmsg(); fprintf(stderr, "type mismatch for %s", symname(formal)); b = false; } } if (b and formal != nil and isvarparam(formal) and not isopenarray(formal->type) and not ( actual->op == O_RVAL or actual->nodetype == t_addr or ( actual->op == O_TYPERENAME and ( actual->value.arg[0]->op == O_RVAL or actual->value.arg[0]->nodetype == t_addr ) ) ) ) { beginerrmsg(); fprintf(stderr, "expected variable, found \""); prtree(stderr, actual); fprintf(stderr, "\""); b = false; } return b;}/* * Pass an expression to a particular parameter. * * Normally we pass either the address or value, but in some cases * (such as C strings) we want to copy the value onto the stack and * pass its address. * * Another special case raised by strings is the possibility that * the actual parameter will be larger than the formal, even with * appropriate type-checking. This occurs because we assume during * evaluation that strings are null-terminated, whereas some languages, * notably Pascal, do not work under that assumption. */private passparam (actual, formal)Node actual;Symbol formal;{ boolean b; Address addr; Stack *savesp; integer actsize, formsize; if (formal != nil and isvarparam(formal) and (not isopenarray(formal->type)) ) { addr = lval(actual->value.arg[0]); push(Address, addr); } else if (passaddr(formal, actual->nodetype)) { savesp = sp; eval(actual); actsize = sp - savesp; setreg(STKP, reg(STKP) - roundup(actsize, sizeof (Word))); dwrite(savesp, reg(STKP), actsize); sp = savesp; push(Address, reg(STKP)); if (formal != nil and isopenarray(formal->type)) { push(integer, actsize div size(formal->type->type)); } } else if (formal != nil) { formsize = size(formal); savesp = sp; eval(actual); actsize = sp - savesp; if (actsize > formsize) { sp -= (actsize - formsize); } } else { eval(actual); }}/* * Evaluate an argument list left-to-right. */private integer evalargs(proc, arglist)Symbol proc;Node arglist;{ Node p, actual; Symbol formal; Stack *savesp; integer count; boolean chk; savesp = sp; count = 0; formal = proc->chain; chk = (boolean) (not nosource(proc)); for (p = arglist; p != nil; p = p->value.arg[1]) { assert(p->op == O_COMMA); actual = p->value.arg[0]; if (not chkparam(actual, formal, chk)) { fprintf(stderr, " in call to %s", symname(proc)); sp = savesp; enderrmsg(); } passparam(actual, formal); if (formal != nil) { formal = formal->chain; } ++count; } if (chk) { if (formal != nil) { sp = savesp; error("not enough parameters to %s", symname(proc)); } } return count;}/* * Evaluate an argument list without any type checking. * This is only useful for procedures with a varying number of * arguments that are compiled -g. */private integer unsafe_evalargs (proc, arglist)Symbol proc;Node arglist;{ Node p; integer count; count = 0; for (p = arglist; p != nil; p = p->value.arg[1]) { assert(p->op == O_COMMA); eval(p->value.arg[0]); ++count; } return count;}public procreturn(f)Symbol f;{ integer retvalsize; Node tmp; char *copy; flushoutput(); popenv(); if (endproc.isfunc) { retvalsize = size(f->type); if (retvalsize > sizeof(long)) { pushretval(retvalsize, true); copy = newarr(char, retvalsize); popn(retvalsize, copy); tmp = build(O_SCON, copy); } else { tmp = build(O_LCON, (long) (reg(0))); } tmp->nodetype = f->type; tfree(endproc.callnode); *(endproc.callnode) = *(tmp); dispose(tmp); eval(endproc.cmdnode); } else { putchar('\n'); printname(stdout, f); printf(" returns successfully\n"); } erecover();}/* * Push the current environment. */private pushenv(){ push(Address, pc); push(Lineno, curline); push(String, cursource); push(Boolean, isstopped); push(Symbol, curfunc); push(Frame, curframe); push(struct Frame, curframerec); push(CallEnv, endproc); push(Word, reg(PROGCTR)); push(Word, reg(STKP)); push(Word, reg(FRP));}/* * Pop back to the real world. */public popenv(){ String filename; setreg(FRP, pop(Word)); setreg(STKP, pop(Word)); setreg(PROGCTR, pop(Word)); endproc = pop(CallEnv); curframerec = pop(struct Frame); curframe = pop(Frame); 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(){ Symbol p, iob; Stack *savesp; p = lookup(identname("fflush", true)); while (p != nil and not isblock(p)) { p = p->next_sym; } if (p != nil) { iob = lookup(identname("__sF", true)); if (iob != nil) { pushenv(); pc = codeloc(p); savesp = sp; push(long, address(iob, nil) + sizeof(*stdout)); setreg(STKP, reg(STKP) - sizeof(long)); dwrite(savesp, reg(STKP), sizeof(long)); sp = savesp; beginproc(p, 1); stepto(return_addr()); popenv(); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -