runtime.c
来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 1,238 行 · 第 1/2 页
C
1,238 行
/*@(#)runtime.c 4.2 Ultrix 11/9/90*//************************************************************************ * * * Copyright (c) 1986 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//************************************************************************ * * * Modification History * * * * 007 - fixed 'print function()' and "can't set a breakpoint in * * a function and do a 'print function(). also, fixed the * * function return value to be correct. * * (L Miller, 25JAN90) * * * * 006 - Added support for vectors. * * (L Miller, 18JAN90) * * * * 005 - Re-merged 4.3 changes to fix: a) dump of variables in * * unnamed blocks was useless ("the mysterious $b" in 001; * * b) $unsafecall wasn't there though it was documented. * * (Jon Reeves, July 14, 1987) * * * * 004 - Merged in 4.3 changes. * * (vjh, April 29, 1986) * * * * 003 - Fixed bug in down(). Added test for jsb routine when * * determining the start address of a function in * * findbeginning(). * * (vjh, August 14, 1985) * * * * 002 - Pushretval() now returns a boolean value. Returns false * * when value is inaccessible; used to panic. * * (vjh, July 18, 1985) * * * * 001 - Fixed internal error - unexpected nil frame; occured when * * pc pointed to last instruction in main routine - * * getcurframe() was returning reg[PROGCTR]+1 as save_pc, * * which in this case is in hyper-space. Modified * * walkstack(): fixed dependencies on the above; removed * * the mysterious $b# from stack traces. * * (Victoria Holt, April 23, 1985) * * * ************************************************************************//* * Copyright (c) 1983 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */#ifndef lintstatic char sccsid[] = "@(#)runtime.c 2.1 ULTRIX 4/24/89";#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 "main.h"#include "symbols.h"#include "tree.h"#include "eval.h"#include "operators.h"#include "object.h"#include <sys/param.h>#include <sys/vm.h>#ifndef publictypedef struct Frame *Frame;#include "machine.h"#endif#define NSAVEREG 12struct 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 Frame curframe = nil;private struct Frame curframerec;private Boolean walkingstack = false;#define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp)#define isstackaddr(addr) \ (((addr) < 0x80000000) and ((addr) > USRSTACK))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->mask = reg(NREG); frp->save_ap = reg(ARGP); frp->save_fp = reg(FRP); frp->save_pc = reg(PROGCTR); for (i = 0; i < NSAVEREG; i++) { frp->save_reg[i] = reg(i); }}/* * 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; 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 or frame.save_pc == (Address) -1) { newfrp = nil; } else if (isstackaddr(callpc)) { ntramp++; prev_frame = frame.save_fp; goto nextf; } else { frame.save_pc = callpc; ntramp = 0; mask = ((frame.mask >> 16) & 0x0fff); getsaveregs(newfrp, &frame, mask); 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;}/* * 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(ARGP, frame.save_ap); setreg(FRP, frame.save_fp); setreg(PROGCTR, frame.save_pc); mask = ((frame.mask >> 16) & 0x0fff); j = 0; for (i = 0; i < NSAVEREG; i++) { if (bis(mask, i)) { setreg(i, frame.save_reg[j]); ++j; } } 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 Boolean pushretval(len, isindirect)Integer len;Boolean isindirect;{ Word r0; Boolean success; r0 = reg(0); success = true; 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 { success = false; } break; } } return success;}/* * 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(ARGP) : frp->save_ap;}/* * 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 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;}/* * 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); } } else { f = func; frp = findframe(f); } showaggrs = true; printcallinfo(f, frp); dumpvars(f, frp);}/* * Dump all values. */public dumpall (){ walkstack(true);}/* * Walk the stack of active procedures printing information * about each active procedure. */private walkstack(dumpvariables)Boolean dumpvariables;{ Frame frp; boolean save; Symbol f; struct Frame frame; if (notstarted(process) or isfinished(process)) { error("program is not active"); } else { save = walkingstack; walkingstack = true; showaggrs = dumpvariables; frp = &frame; getcurfunc(frp, &f); if(!never_run) { for (;;) { printcallinfo(f, frp); if (dumpvariables) { dumpvars(f, frp); putchar('\n'); } frp = nextfunc(frp, &f); if (frp == nil or f == program) { break; } } } if (dumpvariables) { printf("in \"%s\":\n", symname(program)); dumpvars(program, nil); putchar('\n'); } walkingstack = save; }}/* * Print out the information about a call, i.e., * routine name, parameter values, and source location. */private printcallinfo (f, frp)Symbol f;Frame frp;{ Lineno line; Address savepc; savepc = frp->save_pc; if (frp->save_fp != reg(FRP)) { savepc -= 1; } printname(stdout, f); if (not isinline(f)) { printparams(f, frp); } line = srcline(savepc); if (line != 0) { printf(", line %d", line); printf(" in \"%s\"\n", srcfilename(savepc)); } else { printf(" at 0x%x\n", savepc); }}/* * Set the current function to the given symbol. * We must adjust "curframe" so that subsequent operations are * not confused; for simplicity we simply clear it. */public setcurfunc (f)Symbol f;{ curfunc = f; curframe = nil;}/* * Return the frame for the current function. * The space for the frame is allocated statically. */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?