runtime.c

来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 1,238 行 · 第 1/2 页

C
1,238
字号
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 if (not isactive(curfunc)) {        error("current function \"%s\" is not active", symname(curfunc));    } 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);	    setsource(srcfilename(frp->save_pc));	    cursrcline = srcline(frp->save_pc);	    } 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;    Symbol f;    struct Frame frame;    if (not isactive(program)) {	error("program is not active");    } else if (curfunc == nil) {	error("no current function");    } else if (not isactive(curfunc)) {        error("current function \"%s\" is not active", symname(curfunc));    } else {	depth = 0;	frp = &frame;	getcurfunc(frp, &f);	if (curframe == nil) {	    /* The next two assigns must be done in this order.  See	     * findframe() to determine why.	     */	    curframerec = *(findframe(curfunc));	    curframe = &curframerec;	}	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);	    setsource(srcfilename(frp->save_pc));	    cursrcline = srcline(frp->save_pc);	}    }}/* * Find the entry point of a procedure or function. */public findbeginning (f)Symbol f;{    if (isinternal(f)) {	f->symvalue.funcv.beginaddr += 15;    } else if (not jsbroutine(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(){    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	  (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();	if(exprnode->value.arg[2]) {    	pushvenv();	}    argc = pushargs(proc, arglist);    pc = codeloc(proc);    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);    }    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) - ((actsize + sizeof(Word) - 1) & ~(sizeof(Word) - 1))	);	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 concern for matching the formal * parameters of a function in type or quantity.  Useful for functions * like C's printf(). */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;	if(endproc.callnode->value.arg[2]) {    	popvenv();	}    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)));		}    	flushoutput();		tmp->nodetype = f->type;		tfree(endproc.callnode);		*(endproc.callnode) = *(tmp);		dispose(tmp);		eval(endproc.cmdnode);    } else {    	flushoutput();		putchar('\n');		printname(stdout, f);		printf(" returns successfully\n", symname(f));    }    erecover();}/* * Push the current vector environment. */private pushvenv(){	int i = 0;    Vreg v;	if (vectorcapable && vector_context()) {		for(; i < 16; i++)		{			v = vreg(i);			push(struct Vreg, *v);		}		v = vreg(VMR);		push(Vquad, *(Vquad *)v);		v = vreg(VCR);		push(long, (long)v);		v = vreg(VLR);		push(long, (long)v);		v = vreg(VAER);		push(long, (long)v);	}}/* * 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));}/* * Pop back the vector environment. */public popvenv(){	int i = 15;			if (vectorcapable && vector_context()) {		setnreg(VAER, pop(long));		setnreg(VLR, pop(long));		setnreg(VCR, pop(long));		popn(sizeof(Vquad), vregaddr(VMR));		for(; i >= 0; i--) {			popn(sizeof(struct Vreg), vregaddr(i));		}	}}/* * Pop back to the real world. */public popenv(){    String filename;    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("_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();	}    }}/* force the process being debugged to declare itself a vector process. * this will cause the kernel to modify the user area and allocate the * structures to hold the vector registers. if the user process has * already done this then we have a NOP. */#define SYNC 4void vp_declare(){	if(!is_vector_capable()) {		error("unable to declare the process vector capable");	} else if(coredump) {		error("process must be active to be declared vector capable");	} else {		if(!vector_context())			execsync(SYNC);	}}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?