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