runtime.sun.c

来自「早期freebsd实现」· C语言 代码 · 共 1,303 行 · 第 1/2 页

C
1,303
字号
/* * Copyright (c) 1983 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char sccsid[] = "@(#)runtime.sun.c	5.2 (Berkeley) 6/1/90";#endif /* not lint *//* * 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>#include <signal.h>#ifndef publictypedef struct Frame *Frame;#include "machine.h"#endif#define NSAVEREG 14struct Frame {    Address save_fp;		/* frame pointer */    Address save_pc;		/* program counter */    Word save_reg[NSAVEREG];	/* not necessarily there */    integer nargwords;		/* computed, not stored */};private Frame curframe = nil;private struct Frame curframerec;private Boolean walkingstack = false;#define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp)private boolean inSignalHandler (addr)Address addr;{    Symbol f;#ifdef IRIS    return false;#else /* sun */    f = whatblock(addr);    return (boolean) (f != nil and streq(symname(f), "_sigtramp"));#endif}typedef struct {    Node callnode;    Node cmdnode;    boolean isfunc;} CallEnv;private CallEnv endproc;/* * Set a frame to the current activation record. */private getcurframe(frp)Frame frp;{    register int i;    checkref(frp);    frp->save_fp = reg(FRP);    frp->save_pc = reg(PROGCTR);    for (i = 0; i < NSAVEREG; i++) {	frp->save_reg[i] = reg(i);    }    if (frp->save_fp == nil) {	frp->nargwords = 0;    } else {	findnumargs(frp);    }}/* * Get the saved registers from one frame to another * given mask specifying which registers were actually saved. */#define bis(b, n) ((b & (1 << (n))) != 0)private getsaveregs (newfrp, frp, mask)Frame newfrp, frp;integer mask;{    integer i, j;    j = 0;    for (i = 0; i < NSAVEREG; i++) {	if (bis(mask, i)) {	    newfrp->save_reg[i] = frp->save_reg[j];	    ++j;	}    }}/* * 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. */private Frame nextframe(frp)Frame frp;{    Frame newfrp;    struct Frame frame;    integer mask;    Address prev_frame, callpc, higher_fp, higher_pc;    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:    if (prev_frame + sizeof(struct Frame) <= USRSTACK) {	dread(&frame, prev_frame, sizeof(struct Frame));    } else if (USRSTACK - prev_frame > 2 * sizeof(Word)) {	dread(&frame, prev_frame, USRSTACK - prev_frame);    } else {	frame.save_fp = nil;    }    if (ntramp == 1) {	dread(&callpc, prev_frame + 92, sizeof(callpc));    } else {	callpc = frame.save_pc;    }    if (frame.save_fp == nil or frame.save_pc == (Address) -1) {	newfrp = nil;    } else {	if (inSignalHandler(callpc)) {#	ifdef sun	    Address scp;	    dread(&scp, prev_frame + 16, sizeof(scp));	    dread(&callpc,		&(((struct sigcontext *)scp)->sc_pc), sizeof(Word)	    );#	endif /* sun */	}	frame.save_pc = callpc;        ntramp = 0;	higher_fp = frp->save_fp;	higher_pc = frp->save_pc;	newfrp->save_fp = frame.save_fp;	newfrp->save_pc = frame.save_pc;	    findnumargs(newfrp);	    findsavedregs(newfrp, higher_fp, higher_pc);    }    return newfrp;}/* * Finding the saved registers and number of arguments passed to * the current procedure is painful for the 68000. * * This is a version of the way adb for the 68000 does this. */#define HIWORD	0xffff0000#define LOWORD	0x0000ffff#define LINKA6	0x4e560000	/* link a6,#x    */#define ADDLSP	0xdffc0000	/* addl #x,sp    */#define ADDWSP	0xdefc0000	/* addw #x,sp    */#define LEASP	0x4fef0000	/* lea	sp@(x),sp*/#define TSTBSP	0x4a2f0000	/* tstb sp@(x)   */#define INSMSK	0xfff80000#define MOVLSP	0x2e800000	/* movl dx,sp@   */#define MOVLD0	0x20000000	/* movl d0,dx	 */#define MOVLA0	0x20400000	/* movl d0,ax	 */#define MVLMSK	0xf1ff0000#define MOVEML	0x48d70000	/* moveml #x,sp@ */#define JSR	0x4eb80000	/* jsr x.[WL]    */#define JSRPC	0x4eba0000	/* jsr PC@( )    */#define LONGBIT 0x00010000#define BSR	0x61000000	/* bsr x	 */#define BYTE3	0x0000ff00#define LOBYTE	0x000000ff#define ADQMSK	0xf1ff0000#define ADDQSP	0x508f0000	/* addql #x,sp   */#define ADDQWSP	0x504f0000	/* addqw #x,sp   */private int savedregsmask;private int savedregp;/* * Find out how many words of arguments were passed to * the current procedure. */private findnumargs (newfrp)Frame newfrp;{    integer val;    integer instruc;    Address addr;    dread(&addr, newfrp->save_fp + sizeof(Address), sizeof(addr));    iread(&instruc, addr, sizeof(instruc));    if ((instruc&MVLMSK) == MOVLA0 or (instruc&MVLMSK) == MOVLD0) {	addr += 2;	iread(&instruc, addr, sizeof(instruc));    }    if ((instruc&ADQMSK) == ADDQSP or (instruc&ADQMSK) == ADDQWSP){	val = (instruc >> (16+9)) & 07;	if (val == 0) {	    val = 8;	}    } else if ((instruc&HIWORD) == ADDLSP){	iread(&val, addr + 2, sizeof(val));    } else if ((instruc&HIWORD) == ADDWSP || (instruc&HIWORD) == LEASP){	val = instruc&LOWORD;    } else {	val = 0;    }    newfrp->nargwords = val / sizeof(Word);}/* * Get the saved registers for the given Frame. */private findsavedregs (newfrp, higher_fp, higher_pc)Frame newfrp;register Address higher_fp, higher_pc;{    int val, regp, i;    Address addr;    Symbol func;    Address calladdr;    int instruc;    /*     * Find the entry point of the current procedure.     * This is done by finding the procedure for the higher frame's pc     * and taking its starting address.     */    func = whatblock(higher_pc, true);    calladdr = codeloc(func) - FUNCOFFSET;    /*     * Look at the entry code for the current procedure     * to determine which registers were saved, and where they are.     *     * First find the size of the activation record.     */    addr = calladdr;    iread(&instruc, addr, sizeof(instruc));    if ((instruc&HIWORD) == LINKA6) {	if ((instruc &= LOWORD) == 0) {	    /* look for addl */	    addr += 4;	    iread(&instruc, addr, sizeof(instruc));	    if ((instruc&HIWORD) == ADDLSP) {		iread(&instruc, addr + 2, sizeof(instruc));		addr += 6;	    } else {		instruc = 0;	    }	} else {	    /* link offset was non-zero -- sign extend it */	    instruc <<= 16;	    instruc >>= 16;	}	/* we now have the negative frame size */	regp = higher_fp + instruc;	savedregp = regp;    }    /*     * Now find which registers were saved.     * (expecting a probe instruction next)     */    iread(&instruc, addr, sizeof(instruc));    if ((instruc&HIWORD) == TSTBSP) {	addr += 4;	iread(&instruc, addr, sizeof(instruc));    }    /*     * expect either a moveml or a movl next     */    if ((instruc&INSMSK) == MOVLSP){	/*	 * Only one register saved.	 */	i = (instruc>>16) & 07;	dread(&(newfrp->save_reg[i]), regp, sizeof(Word));	savedregsmask = 1 << i;    } else if ((instruc&HIWORD) == MOVEML) {	/*	 * Saving multiple registers or unoptimized code	 */	val = instruc & LOWORD;	savedregsmask = val;	i = 0;	while (val != 0) {	    if (val&1) {		dread(&(newfrp->save_reg[i]), regp, sizeof(Word));		regp += sizeof(Word);	    }	    val >>= 1;	    ++i;	}    } else {	savedregsmask = 0;    }}/* * Get the current frame information in the given Frame and store the * associated function in the given value-result parameter. */private getcurfunc (frp, fp)Frame frp;Symbol *fp;{    getcurframe(frp);    *fp = whatblock(frp->save_pc);}/* * Return the frame associated with the next function up the call stack, or * nil if there is none.  The function is returned in a value-result parameter. * For "inline" functions the statically outer function and same frame * are returned. */public Frame nextfunc (frp, fp)Frame frp;Symbol *fp;{    Symbol t;    Frame nfrp;    t = *fp;    checkref(t);    if (isinline(t)) {	t = container(t);	nfrp = frp;    } else {	nfrp = nextframe(frp);	if (nfrp == nil) {	    t = nil;	} else {	    t = whatblock(nfrp->save_pc);	}    }    *fp = t;    return nfrp;}/* * 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;{    Frame frp;    static struct Frame frame;    Symbol p;    Boolean done;    frp = &frame;    getcurframe(frp);    if (f != nil) {	if (f == curfunc and curframe != nil) {	    *frp = *curframe;	} else {	    done = false;	    p = whatblock(frp->save_pc);	    do {		if (p == f) {		    done = true;		} else if (p == program) {		    done = true;		    frp = nil;		} else {		    frp = nextfunc(frp, &p);		    if (frp == nil) {			done = true;		    }		}	    } while (not done);	}    }    return frp;}/* * Set the registers according to the given frame pointer. */public getnewregs (addr)Address addr;{    struct Frame frame;    integer i, j, mask;    dread(&frame, addr, sizeof(frame));    setreg(FRP, frame.save_fp);    setreg(PROGCTR, frame.save_pc);    pc = frame.save_pc;    setcurfunc(whatblock(pc));}/* * 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 {		    error("[internal error: bad size %d in pushretval]", len);		}		break;	}    }}/* * Return the base address for locals in the given frame. */public Address locals_base(frp)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)Frame frp;{    return (frp == nil) ? reg(FRP) : frp->save_fp;}/* * Return saved register n from the given frame. */public Word savereg(n, frp)integer n;Frame frp;{    Word w;    if (frp == nil) {	w = reg(n);    } else {	switch (n) {	    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;{    Address argaddr;    Word w;    argaddr = args_base(frp) + 4 + (n * sizeof(Word));    dread(&w, argaddr, sizeof(w));    return w;}/* * Return the number of words of arguments passed to the procedure * associated with the given frame (it's a macro for the VAX). */public integer nargspassed (frp)Frame frp;{    integer n;    struct Frame frame;    if (frp == nil) {	getcurframe(&frame);	n = frame.nargwords;    } else {	n = frp->nargwords;    }    return n;}/* * Print a list of currently active blocks starting with most recent. */public wherecmd(){    walkstack(false);}/* * Print the variables in the given frame or the current one if nil. */public dump (func)Symbol func;{    Symbol f;    Frame frp;    if (func == nil) {	f = curfunc;	if (curframe != nil) {	    frp = curframe;	} else {	    frp = findframe(f);

⌨️ 快捷键说明

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