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