126329Ssam /* 238105Sbostic * Copyright (c) 1985 The Regents of the University of California. 338105Sbostic * All rights reserved. 438105Sbostic * 5*42685Sbostic * %sccs.include.redist.c% 626329Ssam */ 726329Ssam 826329Ssam #ifndef lint 9*42685Sbostic static char sccsid[] = "@(#)runtime.tahoe.c 5.5 (Berkeley) 06/01/90"; 1038105Sbostic #endif /* not lint */ 1126329Ssam 1226329Ssam /* 1326329Ssam * Runtime organization dependent routines, mostly dealing with 1426329Ssam * activation records. 1526329Ssam */ 1626329Ssam 1726329Ssam #include "defs.h" 1826329Ssam #include "runtime.h" 1926329Ssam #include "process.h" 2026329Ssam #include "machine.h" 2126329Ssam #include "events.h" 2226329Ssam #include "mappings.h" 2326329Ssam #include "symbols.h" 2426329Ssam #include "tree.h" 2526329Ssam #include "eval.h" 2626329Ssam #include "operators.h" 2726329Ssam #include "object.h" 2826329Ssam 2926329Ssam #ifndef public 3026329Ssam #include "machine.h" 3126329Ssam 3226329Ssam typedef struct Frame { 3326329Ssam Address save_pc; /* program counter */ 3426329Ssam integer mask:16; /* register save mask */ 3526329Ssam integer removed:16; /* 4*number of arguments + 4 */ 3626329Ssam Address save_fp; /* frame pointer */ 3726329Ssam #define NSAVEREG 13 3826329Ssam Word save_reg[NSAVEREG]; /* not necessarily there */ 3926329Ssam } *Frame; 4026329Ssam #endif 4126329Ssam 4226329Ssam private Frame curframe = nil; 4326329Ssam private struct Frame curframerec; 4426329Ssam private Boolean walkingstack = false; 4526329Ssam 4626329Ssam #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp) 4726329Ssam 4833333Sdonn #define inSignalHandler(addr) \ 4926329Ssam (((addr) < 0xc0000000) and ((addr) > 0xc0000000 - 0x400 * UPAGES)) 5026329Ssam 5126329Ssam typedef struct { 5226329Ssam Node callnode; 5326329Ssam Node cmdnode; 5426329Ssam boolean isfunc; 5526329Ssam } CallEnv; 5626329Ssam 5726329Ssam private CallEnv endproc; 5826329Ssam 5926329Ssam /* 6026329Ssam * Set a frame to the current activation record. 6126329Ssam */ 6226329Ssam 6326329Ssam private getcurframe(frp) 6426329Ssam Frame frp; 6526329Ssam { 6626329Ssam register int i; 6726329Ssam long x; 6826329Ssam 6926329Ssam checkref(frp); 7026329Ssam frp->save_fp = reg(FRP); 7126329Ssam dread(&x, frp->save_fp-4, 4); 7226329Ssam frp->mask = x >> 16; 7326329Ssam frp->removed = x & 0xffff; 7426329Ssam frp->save_pc = reg(PROGCTR); 7526329Ssam for (i = 0; i < NSAVEREG; i++) { 7626329Ssam frp->save_reg[i] = reg(i); 7726329Ssam } 7826329Ssam } 7926329Ssam 8026329Ssam /* 8126329Ssam * Get the saved registers from one frame to another 8226329Ssam * given mask specifying which registers were actually saved. 8326329Ssam */ 8426329Ssam 8526329Ssam #define bis(b, n) ((b & (1 << (n))) != 0) 8626329Ssam 8726329Ssam private getsaveregs (newfrp, frp, mask) 8826329Ssam Frame newfrp, frp; 8926329Ssam integer mask; 9026329Ssam { 9126329Ssam integer i, j; 9226329Ssam 9326329Ssam j = 0; 9426329Ssam for (i = 0; i < NSAVEREG; i++) { 9526329Ssam if (bis(mask, i)) { 9626329Ssam newfrp->save_reg[i] = frp->save_reg[j]; 9726329Ssam ++j; 9826329Ssam } 9926329Ssam } 10026329Ssam } 10126329Ssam 10226329Ssam /* 10326329Ssam * Return a pointer to the next activation record up the stack. 10426329Ssam * Return nil if there is none. 10526329Ssam * Writes over space pointed to by given argument. 10626329Ssam */ 10726329Ssam 10826329Ssam private Frame nextframe(frp) 10926329Ssam Frame frp; 11026329Ssam { 11126329Ssam Frame newfrp; 11226329Ssam struct Frame frame; 11326329Ssam long x; 11433333Sdonn Address prev_frame, callpc; 11526329Ssam static integer ntramp = 0; 11626329Ssam 11726329Ssam newfrp = frp; 11826329Ssam prev_frame = frp->save_fp; 11926329Ssam 12026329Ssam /* 12126329Ssam * The check for interrupt generated frames is taken from adb with only 12226329Ssam * partial understanding. If you're in "sub" and on a sigxxx "sigsub" 12326329Ssam * gets control, then the stack does NOT look like <main, sub, sigsub>. 12426329Ssam * 12526329Ssam * As best I can make out it looks like: 12626329Ssam * 12726329Ssam * <main, (machine check exception block + sub), sysframe, sigsub>. 12826329Ssam * 12926329Ssam * When the signal occurs an exception block and a frame for the routine 13026329Ssam * in which it occured are pushed on the user stack. Then another frame 13126329Ssam * is pushed corresponding to a call from the kernel to sigsub. 13226329Ssam * 13326329Ssam * The addr in sub at which the exception occured is not in sub.save_pc 13426329Ssam * but in the machine check exception block. It is at the magic address 13526329Ssam * fp + 84. 13626329Ssam * 13726329Ssam * The current approach ignores the sys_frame (what adb reports as sigtramp) 13826329Ssam * and takes the pc for sub from the exception block. This allows the 13926329Ssam * "where" command to report <main, sub, sigsub>, which seems reasonable. 14026329Ssam */ 14126329Ssam 14226329Ssam nextf: 14326329Ssam dread(&frame, prev_frame-8, sizeof(struct Frame)); 14426329Ssam if (ntramp == 1) { 14526329Ssam dread(&callpc, prev_frame+44, sizeof(callpc)); 14626329Ssam } else { 14726329Ssam callpc = frame.save_pc; 14826329Ssam } 14926329Ssam if (frame.save_fp == nil or frame.save_pc == (Address) -1) { 15026329Ssam newfrp = nil; 15133333Sdonn } else if (inSignalHandler(callpc)) { 15226329Ssam ntramp++; 15326329Ssam prev_frame = frame.save_fp; 15426329Ssam goto nextf; 15526329Ssam } else { 15626329Ssam ntramp = 0; 15726329Ssam getsaveregs(newfrp, &frame, frame.mask); 15826329Ssam dread(&x, frame.save_fp-4, sizeof (x)); 15926329Ssam newfrp->mask = x >> 16; 16026329Ssam newfrp->removed = x & 0xffff; 16126329Ssam newfrp->save_fp = frame.save_fp; 16226329Ssam newfrp->save_pc = callpc; 16326329Ssam } 16426329Ssam return newfrp; 16526329Ssam } 16626329Ssam 16726329Ssam /* 16826329Ssam * Get the current frame information in the given Frame and store the 16926329Ssam * associated function in the given value-result parameter. 17026329Ssam */ 17126329Ssam 17226329Ssam private getcurfunc (frp, fp) 17326329Ssam Frame frp; 17426329Ssam Symbol *fp; 17526329Ssam { 17626329Ssam getcurframe(frp); 17726329Ssam *fp = whatblock(frp->save_pc); 17826329Ssam } 17926329Ssam 18026329Ssam /* 18126329Ssam * Return the frame associated with the next function up the call stack, or 18226329Ssam * nil if there is none. The function is returned in a value-result parameter. 18326329Ssam * For "inline" functions the statically outer function and same frame 18426329Ssam * are returned. 18526329Ssam */ 18626329Ssam 18726329Ssam public Frame nextfunc (frp, fp) 18826329Ssam Frame frp; 18926329Ssam Symbol *fp; 19026329Ssam { 19126329Ssam Symbol t; 19226329Ssam Frame nfrp; 19326329Ssam 19426329Ssam t = *fp; 19526329Ssam checkref(t); 19626329Ssam if (isinline(t)) { 19726329Ssam t = container(t); 19826329Ssam nfrp = frp; 19926329Ssam } else { 20026329Ssam nfrp = nextframe(frp); 20126329Ssam if (nfrp == nil) { 20226329Ssam t = nil; 20326329Ssam } else { 20426329Ssam t = whatblock(nfrp->save_pc); 20526329Ssam } 20626329Ssam } 20726329Ssam *fp = t; 20826329Ssam return nfrp; 20926329Ssam } 21026329Ssam 21126329Ssam /* 21226329Ssam * Return the frame associated with the given function. 21326329Ssam * If the function is nil, return the most recently activated frame. 21426329Ssam * 21526329Ssam * Static allocation for the frame. 21626329Ssam */ 21726329Ssam 21826329Ssam public Frame findframe(f) 21926329Ssam Symbol f; 22026329Ssam { 22126329Ssam Frame frp; 22226329Ssam static struct Frame frame; 22326329Ssam Symbol p; 22426329Ssam Boolean done; 22526329Ssam 22626329Ssam frp = &frame; 22726329Ssam getcurframe(frp); 22826329Ssam if (f != nil) { 22926329Ssam if (f == curfunc and curframe != nil) { 23026329Ssam *frp = *curframe; 23126329Ssam } else { 23226329Ssam done = false; 23326329Ssam p = whatblock(frp->save_pc); 23426329Ssam do { 23526329Ssam if (p == f) { 23626329Ssam done = true; 23726329Ssam } else if (p == program) { 23826329Ssam done = true; 23926329Ssam frp = nil; 24026329Ssam } else { 24126329Ssam frp = nextfunc(frp, &p); 24226329Ssam if (frp == nil) { 24326329Ssam done = true; 24426329Ssam } 24526329Ssam } 24626329Ssam } while (not done); 24726329Ssam } 24826329Ssam } 24926329Ssam return frp; 25026329Ssam } 25126329Ssam 25226329Ssam /* 25326329Ssam * Set the registers according to the given frame pointer. 25426329Ssam */ 25526329Ssam 25626329Ssam public getnewregs (addr) 25726329Ssam Address addr; 25826329Ssam { 25926329Ssam struct Frame frame; 26026329Ssam integer i, j, mask; 26126329Ssam 26226329Ssam dread(&frame, addr-8, sizeof(frame)); 26326329Ssam setreg(FRP, frame.save_fp); 26426329Ssam setreg(PROGCTR, frame.save_pc); 26526329Ssam mask = frame.mask; 26626329Ssam j = 0; 26726329Ssam for (i = 0; i < NSAVEREG; i++) { 26826329Ssam if (bis(mask, i)) { 26926329Ssam setreg(i, frame.save_reg[j]); 27026329Ssam ++j; 27126329Ssam } 27226329Ssam } 27326329Ssam pc = frame.save_pc; 27426329Ssam setcurfunc(whatblock(pc)); 27526329Ssam } 27626329Ssam 27726329Ssam /* 27826329Ssam * Find the return address of the current procedure/function. 27926329Ssam */ 28026329Ssam 28126329Ssam public Address return_addr() 28226329Ssam { 28326329Ssam Frame frp; 28426329Ssam Address addr; 28526329Ssam struct Frame frame; 28626329Ssam 28726329Ssam frp = &frame; 28826329Ssam getcurframe(frp); 28926329Ssam frp = nextframe(frp); 29026329Ssam if (frp == nil) { 29126329Ssam addr = 0; 29226329Ssam } else { 29326329Ssam addr = frp->save_pc; 29426329Ssam } 29526329Ssam return addr; 29626329Ssam } 29726329Ssam 29826329Ssam /* 29926329Ssam * Push the value associated with the current function. 30026329Ssam */ 30126329Ssam 30226329Ssam public pushretval(len, isindirect) 30326329Ssam integer len; 30426329Ssam boolean isindirect; 30526329Ssam { 30626329Ssam Word r0; 30726329Ssam 30826329Ssam r0 = reg(0); 30926329Ssam if (isindirect) { 31026329Ssam rpush((Address) r0, len); 31126329Ssam } else { 31226329Ssam switch (len) { 31326329Ssam case sizeof(char): 31426329Ssam push(char, r0); 31526329Ssam break; 31626329Ssam 31726329Ssam case sizeof(short): 31826329Ssam push(short, r0); 31926329Ssam break; 32026329Ssam 32126329Ssam default: 32226329Ssam if (len == sizeof(Word)) { 32326329Ssam push(Word, r0); 32426329Ssam } else if (len == 2*sizeof(Word)) { 32526329Ssam push(Word, r0); 32626329Ssam push(Word, reg(1)); 32726329Ssam } else { 32826329Ssam error("[internal error: bad size %d in pushretval]", len); 32926329Ssam } 33026329Ssam break; 33126329Ssam } 33226329Ssam } 33326329Ssam } 33426329Ssam 33526329Ssam /* 33626329Ssam * Return the base address for locals in the given frame. 33726329Ssam */ 33826329Ssam 33926329Ssam public Address locals_base(frp) 34026329Ssam Frame frp; 34126329Ssam { 34226329Ssam return (frp == nil ? reg(FRP) : frp->save_fp); 34326329Ssam } 34426329Ssam 34526329Ssam /* 34626329Ssam * Return the base address for arguments in the given frame. 34726329Ssam */ 34826329Ssam 34926329Ssam public Address args_base(frp) 35026329Ssam Frame frp; 35126329Ssam { 35226329Ssam return (frp == nil ? reg(FRP) : frp->save_fp); 35326329Ssam } 35426329Ssam 35526329Ssam /* 35626329Ssam * Return saved register n from the given frame. 35726329Ssam */ 35826329Ssam 35926329Ssam public Word savereg(n, frp) 36026329Ssam integer n; 36126329Ssam Frame frp; 36226329Ssam { 36326329Ssam Word w; 36426329Ssam 36526329Ssam if (frp == nil) { 36626329Ssam w = reg(n); 36726329Ssam } else { 36826329Ssam switch (n) { 36926329Ssam 37026329Ssam case FRP: 37126329Ssam w = frp->save_fp; 37226329Ssam break; 37326329Ssam 37426329Ssam case STKP: 37526329Ssam w = reg(STKP); 37626329Ssam break; 37726329Ssam 37826329Ssam case PROGCTR: 37926329Ssam w = frp->save_pc; 38026329Ssam break; 38126329Ssam 38226329Ssam default: 38326329Ssam assert(n >= 0 and n < NSAVEREG); 38426329Ssam w = frp->save_reg[n]; 38526329Ssam break; 38626329Ssam } 38726329Ssam } 38826329Ssam return w; 38926329Ssam } 39026329Ssam 39126329Ssam /* 39226329Ssam * Return the nth argument to the current procedure. 39326329Ssam */ 39426329Ssam 39526329Ssam public Word argn(n, frp) 39626329Ssam integer n; 39726329Ssam Frame frp; 39826329Ssam { 39933333Sdonn Address argaddr; 40026329Ssam Word w; 40126329Ssam 40233333Sdonn argaddr = args_base(frp) + (n * sizeof(Word)); 40333333Sdonn dread(&w, argaddr, sizeof(w)); 40426329Ssam return w; 40526329Ssam } 40626329Ssam 40726329Ssam /* 40826329Ssam * Print a list of currently active blocks starting with most recent. 40926329Ssam */ 41026329Ssam 41126329Ssam public wherecmd() 41226329Ssam { 41326329Ssam walkstack(false); 41426329Ssam } 41526329Ssam 41626329Ssam /* 41726329Ssam * Print the variables in the given frame or the current one if nil. 41826329Ssam */ 41926329Ssam 42026329Ssam public dump (func) 42126329Ssam Symbol func; 42226329Ssam { 42326329Ssam Symbol f; 42426329Ssam Frame frp; 42526329Ssam 42626329Ssam if (func == nil) { 42726329Ssam f = curfunc; 42826329Ssam if (curframe != nil) { 42926329Ssam frp = curframe; 43026329Ssam } else { 43126329Ssam frp = findframe(f); 43226329Ssam } 43326329Ssam } else { 43426329Ssam f = func; 43526329Ssam frp = findframe(f); 43626329Ssam } 43726329Ssam showaggrs = true; 43826329Ssam printcallinfo(f, frp); 43926329Ssam dumpvars(f, frp); 44026329Ssam } 44126329Ssam 44226329Ssam /* 44326329Ssam * Dump all values. 44426329Ssam */ 44526329Ssam 44626329Ssam public dumpall () 44726329Ssam { 44826329Ssam walkstack(true); 44926329Ssam } 45026329Ssam 45126329Ssam /* 45226329Ssam * Walk the stack of active procedures printing information 45326329Ssam * about each active procedure. 45426329Ssam */ 45526329Ssam 45626329Ssam private walkstack(dumpvariables) 45726329Ssam Boolean dumpvariables; 45826329Ssam { 45926329Ssam Frame frp; 46026329Ssam boolean save; 46126329Ssam Symbol f; 46226329Ssam struct Frame frame; 46326329Ssam 46426329Ssam if (notstarted(process) or isfinished(process)) { 46526329Ssam error("program is not active"); 46626329Ssam } else { 46726329Ssam save = walkingstack; 46826329Ssam walkingstack = true; 46926329Ssam showaggrs = dumpvariables; 47026329Ssam frp = &frame; 47126329Ssam getcurfunc(frp, &f); 47226329Ssam for (;;) { 47326329Ssam printcallinfo(f, frp); 47426329Ssam if (dumpvariables) { 47526329Ssam dumpvars(f, frp); 47626329Ssam putchar('\n'); 47726329Ssam } 47826329Ssam frp = nextfunc(frp, &f); 47926329Ssam if (frp == nil or f == program) { 48026329Ssam break; 48126329Ssam } 48226329Ssam } 48326329Ssam if (dumpvariables) { 48426329Ssam printf("in \"%s\":\n", symname(program)); 48526329Ssam dumpvars(program, nil); 48626329Ssam putchar('\n'); 48726329Ssam } 48826329Ssam walkingstack = save; 48926329Ssam } 49026329Ssam } 49126329Ssam 49226329Ssam /* 49326329Ssam * Print out the information about a call, i.e., 49426329Ssam * routine name, parameter values, and source location. 49526329Ssam */ 49626329Ssam 49726329Ssam private printcallinfo (f, frp) 49826329Ssam Symbol f; 49926329Ssam Frame frp; 50026329Ssam { 50126329Ssam Lineno line; 50226329Ssam Address savepc; 50326329Ssam 50426329Ssam savepc = frp->save_pc; 50526329Ssam if (frp->save_fp != reg(FRP)) { 50626329Ssam savepc -= 1; 50726329Ssam } 50826329Ssam printname(stdout, f); 50926329Ssam if (not isinline(f)) { 51026329Ssam printparams(f, frp); 51126329Ssam } 51226329Ssam line = srcline(savepc); 51326329Ssam if (line != 0) { 51426329Ssam printf(", line %d", line); 51526329Ssam printf(" in \"%s\"\n", srcfilename(savepc)); 51626329Ssam } else { 51726329Ssam printf(" at 0x%x\n", savepc); 51826329Ssam } 51926329Ssam } 52026329Ssam 52126329Ssam /* 52226329Ssam * Set the current function to the given symbol. 52326329Ssam * We must adjust "curframe" so that subsequent operations are 52426329Ssam * not confused; for simplicity we simply clear it. 52526329Ssam */ 52626329Ssam 52726329Ssam public setcurfunc (f) 52826329Ssam Symbol f; 52926329Ssam { 53026329Ssam curfunc = f; 53126329Ssam curframe = nil; 53226329Ssam } 53326329Ssam 53426329Ssam /* 53526329Ssam * Return the frame for the current function. 53626329Ssam * The space for the frame is allocated statically. 53726329Ssam */ 53826329Ssam 53926329Ssam public Frame curfuncframe () 54026329Ssam { 54126329Ssam static struct Frame frame; 54226329Ssam Frame frp; 54326329Ssam 54426329Ssam if (curframe == nil) { 54526329Ssam frp = findframe(curfunc); 54626329Ssam curframe = &curframerec; 54726329Ssam *curframe = *frp; 54826329Ssam } else { 54926329Ssam frp = &frame; 55026329Ssam *frp = *curframe; 55126329Ssam } 55226329Ssam return frp; 55326329Ssam } 55426329Ssam 55526329Ssam /* 55626329Ssam * Set curfunc to be N up/down the stack from its current value. 55726329Ssam */ 55826329Ssam 55926329Ssam public up (n) 56026329Ssam integer n; 56126329Ssam { 56226329Ssam integer i; 56326329Ssam Symbol f; 56426329Ssam Frame frp; 56526329Ssam boolean done; 56626329Ssam 56726329Ssam if (not isactive(program)) { 56826329Ssam error("program is not active"); 56926329Ssam } else if (curfunc == nil) { 57026329Ssam error("no current function"); 57126329Ssam } else { 57226329Ssam i = 0; 57326329Ssam f = curfunc; 57426329Ssam frp = curfuncframe(); 57526329Ssam done = false; 57626329Ssam do { 57726329Ssam if (frp == nil) { 57826329Ssam done = true; 57926329Ssam error("not that many levels"); 58026329Ssam } else if (i >= n) { 58126329Ssam done = true; 58226329Ssam curfunc = f; 58326329Ssam curframe = &curframerec; 58426329Ssam *curframe = *frp; 58526329Ssam showaggrs = false; 58626329Ssam printcallinfo(curfunc, curframe); 58726329Ssam } else if (f == program) { 58826329Ssam done = true; 58926329Ssam error("not that many levels"); 59026329Ssam } else { 59126329Ssam frp = nextfunc(frp, &f); 59226329Ssam } 59326329Ssam ++i; 59426329Ssam } while (not done); 59526329Ssam } 59626329Ssam } 59726329Ssam 59826329Ssam public down (n) 59926329Ssam integer n; 60026329Ssam { 60126329Ssam integer i, depth; 60226329Ssam Frame frp, curfrp; 60326329Ssam Symbol f; 60426329Ssam struct Frame frame; 60526329Ssam 60626329Ssam if (not isactive(program)) { 60726329Ssam error("program is not active"); 60826329Ssam } else if (curfunc == nil) { 60926329Ssam error("no current function"); 61026329Ssam } else { 61126329Ssam depth = 0; 61226329Ssam frp = &frame; 61326329Ssam getcurfunc(frp, &f); 61426329Ssam if (curframe == nil) { 61526329Ssam curfrp = findframe(curfunc); 61626329Ssam curframe = &curframerec; 61726329Ssam *curframe = *curfrp; 61826329Ssam } 61926329Ssam while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) { 62026329Ssam frp = nextfunc(frp, &f); 62126329Ssam ++depth; 62226329Ssam } 62326329Ssam if (f == nil or n > depth) { 62426329Ssam error("not that many levels"); 62526329Ssam } else { 62626329Ssam depth -= n; 62726329Ssam frp = &frame; 62826329Ssam getcurfunc(frp, &f); 62926329Ssam for (i = 0; i < depth; i++) { 63026329Ssam frp = nextfunc(frp, &f); 63126329Ssam assert(frp != nil); 63226329Ssam } 63326329Ssam curfunc = f; 63426329Ssam *curframe = *frp; 63526329Ssam showaggrs = false; 63626329Ssam printcallinfo(curfunc, curframe); 63726329Ssam } 63826329Ssam } 63926329Ssam } 64026329Ssam 64126329Ssam /* 64226329Ssam * Find the entry point of a procedure or function. 64326329Ssam */ 64426329Ssam 64526329Ssam public findbeginning (f) 64626329Ssam Symbol f; 64726329Ssam { 64826329Ssam if (isinternal(f)) { 64926329Ssam f->symvalue.funcv.beginaddr += 15; 65026329Ssam } else { 65133333Sdonn f->symvalue.funcv.beginaddr += FUNCOFFSET; 65226329Ssam } 65326329Ssam } 65426329Ssam 65526329Ssam /* 65626329Ssam * Return the address corresponding to the first line in a function. 65726329Ssam */ 65826329Ssam 65926329Ssam public Address firstline(f) 66026329Ssam Symbol f; 66126329Ssam { 66226329Ssam Address addr; 66326329Ssam 66426329Ssam addr = codeloc(f); 66526329Ssam while (linelookup(addr) == 0 and addr < objsize) { 66626329Ssam ++addr; 66726329Ssam } 66826329Ssam if (addr == objsize) { 66926329Ssam addr = -1; 67026329Ssam } 67126329Ssam return addr; 67226329Ssam } 67326329Ssam 67426329Ssam /* 67526329Ssam * Catcher drops strike three ... 67626329Ssam */ 67726329Ssam 67826329Ssam public runtofirst() 67926329Ssam { 68033333Sdonn Address addr, endaddr; 68126329Ssam 68226329Ssam addr = pc; 68333333Sdonn endaddr = objsize + CODESTART; 68433333Sdonn while (linelookup(addr) == 0 and addr < endaddr) { 68526329Ssam ++addr; 68626329Ssam } 68733333Sdonn if (addr < endaddr) { 68826329Ssam stepto(addr); 68926329Ssam } 69026329Ssam } 69126329Ssam 69226329Ssam /* 69326329Ssam * Return the address corresponding to the end of the program. 69426329Ssam * 69526329Ssam * We look for the entry to "exit". 69626329Ssam */ 69726329Ssam 69826329Ssam public Address lastaddr() 69926329Ssam { 70026329Ssam Symbol s; 70126329Ssam 70226329Ssam s = lookup(identname("exit", true)); 70326329Ssam if (s == nil) { 70426329Ssam panic("can't find exit"); 70526329Ssam } 70626329Ssam return codeloc(s); 70726329Ssam } 70826329Ssam 70926329Ssam /* 71026329Ssam * Decide if the given function is currently active. 71126329Ssam * 71226329Ssam * We avoid calls to "findframe" during a stack trace for efficiency. 71326329Ssam * Presumably information evaluated while walking the stack is active. 71426329Ssam */ 71526329Ssam 71633333Sdonn public Boolean isactive (f) 71726329Ssam Symbol f; 71826329Ssam { 71926329Ssam Boolean b; 72026329Ssam 72126329Ssam if (isfinished(process)) { 72226329Ssam b = false; 72326329Ssam } else { 72433333Sdonn if (walkingstack or f == program or f == nil or 72526329Ssam (ismodule(f) and isactive(container(f)))) { 72626329Ssam b = true; 72726329Ssam } else { 72826329Ssam b = (Boolean) (findframe(f) != nil); 72926329Ssam } 73026329Ssam } 73126329Ssam return b; 73226329Ssam } 73326329Ssam 73426329Ssam /* 73526329Ssam * Evaluate a call to a procedure. 73626329Ssam */ 73726329Ssam 73826329Ssam public callproc(exprnode, isfunc) 73926329Ssam Node exprnode; 74026329Ssam boolean isfunc; 74126329Ssam { 74226329Ssam Node procnode, arglist; 74326329Ssam Symbol proc; 74426329Ssam integer argc; 74526329Ssam 74626329Ssam procnode = exprnode->value.arg[0]; 74726329Ssam arglist = exprnode->value.arg[1]; 74826329Ssam if (procnode->op != O_SYM) { 74926329Ssam beginerrmsg(); 75026329Ssam fprintf(stderr, "can't call \""); 75126329Ssam prtree(stderr, procnode); 75226329Ssam fprintf(stderr, "\""); 75326329Ssam enderrmsg(); 75426329Ssam } 75526329Ssam assert(procnode->op == O_SYM); 75626329Ssam proc = procnode->value.sym; 75726329Ssam if (not isblock(proc)) { 75826329Ssam error("\"%s\" is not a procedure or function", symname(proc)); 75926329Ssam } 76026329Ssam endproc.isfunc = isfunc; 76126329Ssam endproc.callnode = exprnode; 76226329Ssam endproc.cmdnode = topnode; 76326329Ssam pushenv(); 76426329Ssam pc = codeloc(proc); 76526329Ssam argc = pushargs(proc, arglist); 76633333Sdonn setreg(FRP, 1); /* have to ensure it's non-zero for return_addr() */ 76726329Ssam beginproc(proc, argc); 76826329Ssam event_once( 76926329Ssam build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)), 77026329Ssam buildcmdlist(build(O_PROCRTN, proc)) 77126329Ssam ); 77226329Ssam isstopped = false; 77326329Ssam if (not bpact()) { 77426329Ssam isstopped = true; 77526329Ssam cont(0); 77626329Ssam } 77726329Ssam /* 77826329Ssam * bpact() won't return true, it will call printstatus() and go back 77926329Ssam * to command input if a breakpoint is found. 78026329Ssam */ 78126329Ssam /* NOTREACHED */ 78226329Ssam } 78326329Ssam 78426329Ssam /* 78526329Ssam * Push the arguments on the process' stack. We do this by first 78626329Ssam * evaluating them on the "eval" stack, then copying into the process' 78726329Ssam * space. 78826329Ssam */ 78926329Ssam 79026329Ssam private integer pushargs(proc, arglist) 79126329Ssam Symbol proc; 79226329Ssam Node arglist; 79326329Ssam { 79426329Ssam Stack *savesp; 79526329Ssam int argc, args_size; 79626329Ssam 79726329Ssam savesp = sp; 79826329Ssam argc = evalargs(proc, arglist); 79926329Ssam args_size = sp - savesp; 80026329Ssam setreg(STKP, reg(STKP) - args_size); 80126329Ssam dwrite(savesp, reg(STKP), args_size); 80226329Ssam sp = savesp; 80326329Ssam return argc; 80426329Ssam } 80526329Ssam 80626329Ssam /* 80726329Ssam * Check to see if an expression is correct for a given parameter. 80826329Ssam * If the given parameter is false, don't worry about type inconsistencies. 80926329Ssam * 81026329Ssam * Return whether or not it is ok. 81126329Ssam */ 81226329Ssam 81326329Ssam private boolean chkparam (actual, formal, chk) 81426329Ssam Node actual; 81526329Ssam Symbol formal; 81626329Ssam boolean chk; 81726329Ssam { 81826329Ssam boolean b; 81926329Ssam 82026329Ssam b = true; 82126329Ssam if (chk) { 82226329Ssam if (formal == nil) { 82326329Ssam beginerrmsg(); 82426329Ssam fprintf(stderr, "too many parameters"); 82526329Ssam b = false; 82626329Ssam } else if (not compatible(formal->type, actual->nodetype)) { 82726329Ssam beginerrmsg(); 82826329Ssam fprintf(stderr, "type mismatch for %s", symname(formal)); 82926329Ssam b = false; 83026329Ssam } 83126329Ssam } 83226329Ssam if (b and formal != nil and 83326329Ssam isvarparam(formal) and not isopenarray(formal->type) and 83426329Ssam not ( 83526329Ssam actual->op == O_RVAL or actual->nodetype == t_addr or 83626329Ssam ( 83726329Ssam actual->op == O_TYPERENAME and 83826329Ssam ( 83926329Ssam actual->value.arg[0]->op == O_RVAL or 84026329Ssam actual->value.arg[0]->nodetype == t_addr 84126329Ssam ) 84226329Ssam ) 84326329Ssam ) 84426329Ssam ) { 84526329Ssam beginerrmsg(); 84626329Ssam fprintf(stderr, "expected variable, found \""); 84726329Ssam prtree(stderr, actual); 84826329Ssam fprintf(stderr, "\""); 84926329Ssam b = false; 85026329Ssam } 85126329Ssam return b; 85226329Ssam } 85326329Ssam 85426329Ssam /* 85526329Ssam * Pass an expression to a particular parameter. 85626329Ssam * 85726329Ssam * Normally we pass either the address or value, but in some cases 85826329Ssam * (such as C strings) we want to copy the value onto the stack and 85926329Ssam * pass its address. 86026329Ssam * 86126329Ssam * Another special case raised by strings is the possibility that 86226329Ssam * the actual parameter will be larger than the formal, even with 86326329Ssam * appropriate type-checking. This occurs because we assume during 86426329Ssam * evaluation that strings are null-terminated, whereas some languages, 86526329Ssam * notably Pascal, do not work under that assumption. 86626329Ssam */ 86726329Ssam 86826329Ssam private passparam (actual, formal) 86926329Ssam Node actual; 87026329Ssam Symbol formal; 87126329Ssam { 87226329Ssam boolean b; 87326329Ssam Address addr; 87426329Ssam Stack *savesp; 87526329Ssam integer actsize, formsize; 87626329Ssam 87726329Ssam if (formal != nil and isvarparam(formal) and 87826329Ssam (not isopenarray(formal->type)) 87926329Ssam ) { 88026329Ssam addr = lval(actual->value.arg[0]); 88126329Ssam push(Address, addr); 88226329Ssam } else if (passaddr(formal, actual->nodetype)) { 88326329Ssam savesp = sp; 88426329Ssam eval(actual); 88526329Ssam actsize = sp - savesp; 88626329Ssam setreg(STKP, reg(STKP) - roundup(actsize, sizeof (Word))); 88726329Ssam dwrite(savesp, reg(STKP), actsize); 88826329Ssam sp = savesp; 88926329Ssam push(Address, reg(STKP)); 89026329Ssam if (formal != nil and isopenarray(formal->type)) { 89126329Ssam push(integer, actsize div size(formal->type->type)); 89226329Ssam } 89326329Ssam } else if (formal != nil) { 89426329Ssam formsize = size(formal); 89526329Ssam savesp = sp; 89626329Ssam eval(actual); 89726329Ssam actsize = sp - savesp; 89826329Ssam if (actsize > formsize) { 89926329Ssam sp -= (actsize - formsize); 90026329Ssam } 90126329Ssam } else { 90226329Ssam eval(actual); 90326329Ssam } 90426329Ssam } 90526329Ssam 90626329Ssam /* 90726329Ssam * Evaluate an argument list left-to-right. 90826329Ssam */ 90926329Ssam 91026329Ssam private integer evalargs(proc, arglist) 91126329Ssam Symbol proc; 91226329Ssam Node arglist; 91326329Ssam { 91426329Ssam Node p, actual; 91526329Ssam Symbol formal; 91626329Ssam Stack *savesp; 91726329Ssam integer count; 91826329Ssam boolean chk; 91926329Ssam 92026329Ssam savesp = sp; 92126329Ssam count = 0; 92226329Ssam formal = proc->chain; 92326329Ssam chk = (boolean) (not nosource(proc)); 92426329Ssam for (p = arglist; p != nil; p = p->value.arg[1]) { 92526329Ssam assert(p->op == O_COMMA); 92626329Ssam actual = p->value.arg[0]; 92726329Ssam if (not chkparam(actual, formal, chk)) { 92826329Ssam fprintf(stderr, " in call to %s", symname(proc)); 92926329Ssam sp = savesp; 93026329Ssam enderrmsg(); 93126329Ssam } 93226329Ssam passparam(actual, formal); 93326329Ssam if (formal != nil) { 93426329Ssam formal = formal->chain; 93526329Ssam } 93626329Ssam ++count; 93726329Ssam } 93826329Ssam if (chk) { 93926329Ssam if (formal != nil) { 94026329Ssam sp = savesp; 94126329Ssam error("not enough parameters to %s", symname(proc)); 94226329Ssam } 94326329Ssam } 94426329Ssam return count; 94526329Ssam } 94626329Ssam 94733333Sdonn /* 94833333Sdonn * Evaluate an argument list without any type checking. 94933333Sdonn * This is only useful for procedures with a varying number of 95033333Sdonn * arguments that are compiled -g. 95133333Sdonn */ 95233333Sdonn 95333333Sdonn private integer unsafe_evalargs (proc, arglist) 95433333Sdonn Symbol proc; 95533333Sdonn Node arglist; 95633333Sdonn { 95733333Sdonn Node p; 95833333Sdonn integer count; 95933333Sdonn 96033333Sdonn count = 0; 96133333Sdonn for (p = arglist; p != nil; p = p->value.arg[1]) { 96233333Sdonn assert(p->op == O_COMMA); 96333333Sdonn eval(p->value.arg[0]); 96433333Sdonn ++count; 96533333Sdonn } 96633333Sdonn return count; 96733333Sdonn } 96833333Sdonn 96926329Ssam public procreturn(f) 97026329Ssam Symbol f; 97126329Ssam { 97226329Ssam integer retvalsize; 97326329Ssam Node tmp; 97426329Ssam char *copy; 97526329Ssam 97626329Ssam flushoutput(); 97726329Ssam popenv(); 97826329Ssam if (endproc.isfunc) { 97926329Ssam retvalsize = size(f->type); 98026329Ssam if (retvalsize > sizeof(long)) { 98126329Ssam pushretval(retvalsize, true); 98226329Ssam copy = newarr(char, retvalsize); 98326329Ssam popn(retvalsize, copy); 98426329Ssam tmp = build(O_SCON, copy); 98526329Ssam } else { 98626329Ssam tmp = build(O_LCON, (long) (reg(0))); 98726329Ssam } 98826329Ssam tmp->nodetype = f->type; 98926329Ssam tfree(endproc.callnode); 99026329Ssam *(endproc.callnode) = *(tmp); 99126329Ssam dispose(tmp); 99226329Ssam eval(endproc.cmdnode); 99326329Ssam } else { 99426329Ssam putchar('\n'); 99526329Ssam printname(stdout, f); 99633333Sdonn printf(" returns successfully\n"); 99726329Ssam } 99826329Ssam erecover(); 99926329Ssam } 100026329Ssam 100126329Ssam /* 100226329Ssam * Push the current environment. 100326329Ssam */ 100426329Ssam 100526329Ssam private pushenv() 100626329Ssam { 100726329Ssam push(Address, pc); 100826329Ssam push(Lineno, curline); 100926329Ssam push(String, cursource); 101026329Ssam push(Boolean, isstopped); 101126329Ssam push(Symbol, curfunc); 101226329Ssam push(Frame, curframe); 101326329Ssam push(struct Frame, curframerec); 101426329Ssam push(CallEnv, endproc); 101526329Ssam push(Word, reg(PROGCTR)); 101626329Ssam push(Word, reg(STKP)); 101726329Ssam } 101826329Ssam 101926329Ssam /* 102026329Ssam * Pop back to the real world. 102126329Ssam */ 102226329Ssam 102326329Ssam public popenv() 102426329Ssam { 102526329Ssam String filename; 102626329Ssam 102726329Ssam setreg(STKP, pop(Word)); 102826329Ssam setreg(PROGCTR, pop(Word)); 102926329Ssam endproc = pop(CallEnv); 103026329Ssam curframerec = pop(struct Frame); 103126329Ssam curframe = pop(Frame); 103226329Ssam curfunc = pop(Symbol); 103326329Ssam isstopped = pop(Boolean); 103426329Ssam filename = pop(String); 103526329Ssam curline = pop(Lineno); 103626329Ssam pc = pop(Address); 103726329Ssam setsource(filename); 103826329Ssam } 103926329Ssam 104026329Ssam /* 104126329Ssam * Flush the debuggee's standard output. 104226329Ssam * 104326329Ssam * This is VERY dependent on the use of stdio. 104426329Ssam */ 104526329Ssam 104626329Ssam public flushoutput() 104726329Ssam { 104826329Ssam Symbol p, iob; 104926329Ssam Stack *savesp; 105026329Ssam 105126329Ssam p = lookup(identname("fflush", true)); 105226329Ssam while (p != nil and not isblock(p)) { 105326329Ssam p = p->next_sym; 105426329Ssam } 105526329Ssam if (p != nil) { 105626329Ssam iob = lookup(identname("_iob", true)); 105726329Ssam if (iob != nil) { 105826329Ssam pushenv(); 105926329Ssam pc = codeloc(p); 106026329Ssam savesp = sp; 106126329Ssam push(long, address(iob, nil) + sizeof(struct _iobuf)); 106226329Ssam setreg(STKP, reg(STKP) - sizeof(long)); 106326329Ssam dwrite(savesp, reg(STKP), sizeof(long)); 106426329Ssam sp = savesp; 106526329Ssam beginproc(p, 1); 106626329Ssam stepto(return_addr()); 106726329Ssam popenv(); 106826329Ssam } 106926329Ssam } 107026329Ssam } 1071