112546Scsvaf 29678Slinton /* Copyright (c) 1982 Regents of the University of California */ 39678Slinton 4*16636Ssam static char sccsid[] = "@(#)runtime.c 1.11 (Berkeley) 06/23/84"; 59678Slinton 69678Slinton /* 79678Slinton * Runtime organization dependent routines, mostly dealing with 89678Slinton * activation records. 99678Slinton */ 109678Slinton 119678Slinton #include "defs.h" 129678Slinton #include "runtime.h" 139678Slinton #include "process.h" 149678Slinton #include "machine.h" 159678Slinton #include "events.h" 169678Slinton #include "mappings.h" 179678Slinton #include "symbols.h" 189678Slinton #include "tree.h" 199678Slinton #include "eval.h" 209678Slinton #include "operators.h" 219678Slinton #include "object.h" 2212546Scsvaf #include <sys/param.h> 239678Slinton 249678Slinton #ifndef public 259678Slinton typedef struct Frame *Frame; 269678Slinton 279678Slinton #include "machine.h" 289678Slinton #endif 299678Slinton 309678Slinton #define NSAVEREG 12 319678Slinton 329678Slinton struct Frame { 339678Slinton Integer condition_handler; 349678Slinton Integer mask; 359678Slinton Address save_ap; /* argument pointer */ 369678Slinton Address save_fp; /* frame pointer */ 379678Slinton Address save_pc; /* program counter */ 389678Slinton Word save_reg[NSAVEREG]; /* not necessarily there */ 399678Slinton }; 409678Slinton 4116618Ssam private Frame curframe = nil; 4216618Ssam private struct Frame curframerec; 439678Slinton private Boolean walkingstack = false; 449678Slinton 4516618Ssam #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp) 4616618Ssam 479678Slinton /* 489678Slinton * Set a frame to the current activation record. 499678Slinton */ 509678Slinton 519678Slinton private getcurframe(frp) 529678Slinton register Frame frp; 539678Slinton { 549678Slinton register int i; 559678Slinton 569678Slinton checkref(frp); 579678Slinton frp->mask = reg(NREG); 589678Slinton frp->save_ap = reg(ARGP); 599678Slinton frp->save_fp = reg(FRP); 6012051Slinton frp->save_pc = reg(PROGCTR) + 1; 619678Slinton for (i = 0; i < NSAVEREG; i++) { 629678Slinton frp->save_reg[i] = reg(i); 639678Slinton } 649678Slinton } 659678Slinton 669678Slinton /* 679678Slinton * Return a pointer to the next activation record up the stack. 689678Slinton * Return nil if there is none. 699678Slinton * Writes over space pointed to by given argument. 709678Slinton */ 719678Slinton 729678Slinton #define bis(b, n) ((b & (1 << (n))) != 0) 739678Slinton 749678Slinton private Frame nextframe(frp) 759678Slinton Frame frp; 769678Slinton { 779678Slinton register Frame newfrp; 789678Slinton struct Frame frame; 799678Slinton register Integer i, j, mask; 8012546Scsvaf Address prev_frame, callpc; 8113937Slinton static Integer ntramp = 0; 829678Slinton 839678Slinton newfrp = frp; 8412546Scsvaf prev_frame = frp->save_fp; 8512546Scsvaf 8613937Slinton /* 8713937Slinton * The check for interrupt generated frames is taken from adb with only 8813937Slinton * partial understanding. If you're in "sub" and on a sigxxx "sigsub" 8913937Slinton * gets control, then the stack does NOT look like <main, sub, sigsub>. 9012546Scsvaf * 9112546Scsvaf * As best I can make out it looks like: 9212546Scsvaf * 9313937Slinton * <main, (machine check exception block + sub), sysframe, sigsub>. 9413937Slinton * 9513937Slinton * When the signal occurs an exception block and a frame for the routine 9613937Slinton * in which it occured are pushed on the user stack. Then another frame 9713937Slinton * is pushed corresponding to a call from the kernel to sigsub. 9813937Slinton * 9912546Scsvaf * The addr in sub at which the exception occured is not in sub.save_pc 10013937Slinton * but in the machine check exception block. It is at the magic address 10114620Ssam * fp + 84. 10212546Scsvaf * 10312546Scsvaf * The current approach ignores the sys_frame (what adb reports as sigtramp) 10413937Slinton * and takes the pc for sub from the exception block. This allows the 10513937Slinton * "where" command to report <main, sub, sigsub>, which seems reasonable. 10612546Scsvaf */ 10712546Scsvaf 10813937Slinton nextf: 10913937Slinton dread(&frame, prev_frame, sizeof(struct Frame)); 11013937Slinton if (ntramp == 1) { 11114620Ssam dread(&callpc, prev_frame + 84, sizeof(callpc)); 11213937Slinton } else { 11313937Slinton callpc = frame.save_pc; 11413937Slinton } 1159678Slinton if (frame.save_fp == nil) { 1169678Slinton newfrp = nil; 11713937Slinton } else if (callpc > 0x80000000 - 0x200 * UPAGES ) { 11812546Scsvaf ntramp++; 11912546Scsvaf prev_frame = frame.save_fp; 12012546Scsvaf goto nextf; 12113937Slinton } else { 12212546Scsvaf frame.save_pc = callpc; 12313937Slinton ntramp = 0; 1249678Slinton mask = ((frame.mask >> 16) & 0x0fff); 1259678Slinton j = 0; 1269678Slinton for (i = 0; i < NSAVEREG; i++) { 1279678Slinton if (bis(mask, i)) { 1289678Slinton newfrp->save_reg[i] = frame.save_reg[j]; 1299678Slinton ++j; 1309678Slinton } 1319678Slinton } 1329678Slinton newfrp->condition_handler = frame.condition_handler; 1339678Slinton newfrp->mask = mask; 1349678Slinton newfrp->save_ap = frame.save_ap; 1359678Slinton newfrp->save_fp = frame.save_fp; 1369678Slinton newfrp->save_pc = frame.save_pc; 1379678Slinton } 1389678Slinton return newfrp; 1399678Slinton } 1409678Slinton 1419678Slinton /* 14216618Ssam * Get the current frame information in the given Frame and store the 14316618Ssam * associated function in the given value-result parameter. 14416618Ssam */ 14516618Ssam 14616618Ssam private getcurfunc (frp, fp) 14716618Ssam Frame frp; 14816618Ssam Symbol *fp; 14916618Ssam { 15016618Ssam getcurframe(frp); 15116618Ssam *fp = whatblock(frp->save_pc); 15216618Ssam } 15316618Ssam 15416618Ssam /* 15516618Ssam * Return the frame associated with the next function up the call stack, or 15616618Ssam * nil if there is none. The function is returned in a value-result parameter. 15716618Ssam * For "inline" functions the statically outer function and same frame 15816618Ssam * are returned. 15916618Ssam */ 16016618Ssam 16116618Ssam private Frame nextfunc (frp, fp) 16216618Ssam Frame frp; 16316618Ssam Symbol *fp; 16416618Ssam { 16516618Ssam Symbol t; 16616618Ssam Frame nfrp; 16716618Ssam 16816618Ssam t = *fp; 16916618Ssam checkref(t); 17016618Ssam if (isinline(t)) { 17116618Ssam t = container(t); 17216618Ssam nfrp = frp; 17316618Ssam } else { 17416618Ssam nfrp = nextframe(frp); 17516618Ssam if (nfrp == nil) { 17616618Ssam t = nil; 17716618Ssam } else { 17816618Ssam t = whatblock(nfrp->save_pc); 17916618Ssam } 18016618Ssam } 18116618Ssam *fp = t; 18216618Ssam return nfrp; 18316618Ssam } 18416618Ssam 18516618Ssam /* 1869678Slinton * Return the frame associated with the given function. 1879678Slinton * If the function is nil, return the most recently activated frame. 1889678Slinton * 1899678Slinton * Static allocation for the frame. 1909678Slinton */ 1919678Slinton 1929678Slinton public Frame findframe(f) 1939678Slinton Symbol f; 1949678Slinton { 1959678Slinton register Frame frp; 1969678Slinton static struct Frame frame; 19711866Slinton Symbol p; 1989678Slinton 1999678Slinton frp = &frame; 2009678Slinton getcurframe(frp); 201*16636Ssam if (f == nil) 202*16636Ssam return (frp); 203*16636Ssam /* 204*16636Ssam * Starting at the current stack frame, 205*16636Ssam * walk backwards looking for a symbol 206*16636Ssam * match. Beware of local blocks which 207*16636Ssam * have a back pointer but no stack frame. 208*16636Ssam */ 209*16636Ssam p = whatblock(frp->save_pc); 210*16636Ssam while (p != f) { 211*16636Ssam if (p == program) { 212*16636Ssam frp = nil; 213*16636Ssam break; 21415784Ssam } 215*16636Ssam if (isinline(p)) { 216*16636Ssam p = container(p); 217*16636Ssam continue; 218*16636Ssam } 219*16636Ssam frp = nextframe(frp); 220*16636Ssam if (frp == nil) 221*16636Ssam break; 222*16636Ssam p = whatblock(frp->save_pc); 2239678Slinton } 224*16636Ssam return (frp); 2259678Slinton } 2269678Slinton 2279678Slinton /* 2289678Slinton * Find the return address of the current procedure/function. 2299678Slinton */ 2309678Slinton 2319678Slinton public Address return_addr() 2329678Slinton { 2339678Slinton Frame frp; 2349678Slinton Address addr; 2359678Slinton struct Frame frame; 2369678Slinton 2379678Slinton frp = &frame; 2389678Slinton getcurframe(frp); 2399678Slinton frp = nextframe(frp); 2409678Slinton if (frp == nil) { 2419678Slinton addr = 0; 2429678Slinton } else { 2439678Slinton addr = frp->save_pc; 2449678Slinton } 2459678Slinton return addr; 2469678Slinton } 2479678Slinton 2489678Slinton /* 2499678Slinton * Push the value associated with the current function. 2509678Slinton */ 2519678Slinton 2529678Slinton public pushretval(len, isindirect) 2539678Slinton Integer len; 2549678Slinton Boolean isindirect; 2559678Slinton { 2569678Slinton Word r0; 2579678Slinton 2589678Slinton r0 = reg(0); 2599678Slinton if (isindirect) { 2609678Slinton rpush((Address) r0, len); 2619678Slinton } else { 2629678Slinton switch (len) { 2639678Slinton case sizeof(char): 2649678Slinton push(char, r0); 2659678Slinton break; 2669678Slinton 2679678Slinton case sizeof(short): 2689678Slinton push(short, r0); 2699678Slinton break; 2709678Slinton 2719678Slinton default: 2729678Slinton if (len == sizeof(Word)) { 2739678Slinton push(Word, r0); 2749678Slinton } else if (len == 2*sizeof(Word)) { 2759678Slinton push(Word, r0); 2769678Slinton push(Word, reg(1)); 2779678Slinton } else { 2789678Slinton panic("not indirect in pushretval?"); 2799678Slinton } 2809678Slinton break; 2819678Slinton } 2829678Slinton } 2839678Slinton } 2849678Slinton 2859678Slinton /* 2869678Slinton * Return the base address for locals in the given frame. 2879678Slinton */ 2889678Slinton 2899678Slinton public Address locals_base(frp) 2909678Slinton register Frame frp; 2919678Slinton { 2929678Slinton return (frp == nil) ? reg(FRP) : frp->save_fp; 2939678Slinton } 2949678Slinton 2959678Slinton /* 2969678Slinton * Return the base address for arguments in the given frame. 2979678Slinton */ 2989678Slinton 2999678Slinton public Address args_base(frp) 3009678Slinton register Frame frp; 3019678Slinton { 3029678Slinton return (frp == nil) ? reg(ARGP) : frp->save_ap; 3039678Slinton } 3049678Slinton 3059678Slinton /* 3069678Slinton * Return saved register n from the given frame. 3079678Slinton */ 3089678Slinton 3099678Slinton public Word savereg(n, frp) 3109678Slinton register Integer n; 3119678Slinton register Frame frp; 3129678Slinton { 3139678Slinton register Word w; 3149678Slinton 3159678Slinton if (frp == nil) { 3169678Slinton w = reg(n); 3179678Slinton } else { 3189678Slinton switch (n) { 3199678Slinton case ARGP: 3209678Slinton w = frp->save_ap; 3219678Slinton break; 3229678Slinton 3239678Slinton case FRP: 3249678Slinton w = frp->save_fp; 3259678Slinton break; 3269678Slinton 3279678Slinton case STKP: 3289678Slinton w = reg(STKP); 3299678Slinton break; 3309678Slinton 3319678Slinton case PROGCTR: 3329678Slinton w = frp->save_pc; 3339678Slinton break; 3349678Slinton 3359678Slinton default: 3369678Slinton assert(n >= 0 and n < NSAVEREG); 3379678Slinton w = frp->save_reg[n]; 3389678Slinton break; 3399678Slinton } 3409678Slinton } 3419678Slinton return w; 3429678Slinton } 3439678Slinton 3449678Slinton /* 3459678Slinton * Return the nth argument to the current procedure. 3469678Slinton */ 3479678Slinton 3489678Slinton public Word argn(n, frp) 3499678Slinton Integer n; 3509678Slinton Frame frp; 3519678Slinton { 3529678Slinton Word w; 3539678Slinton 3549678Slinton dread(&w, args_base(frp) + (n * sizeof(Word)), sizeof(w)); 3559678Slinton return w; 3569678Slinton } 3579678Slinton 3589678Slinton /* 3599678Slinton * Calculate the entry address for a procedure or function parameter, 3609678Slinton * given the address of the descriptor. 3619678Slinton */ 3629678Slinton 3639678Slinton public Address fparamaddr(a) 3649678Slinton Address a; 3659678Slinton { 3669678Slinton Address r; 3679678Slinton 3689678Slinton dread(&r, a, sizeof(r)); 3699678Slinton return r; 3709678Slinton } 3719678Slinton 3729678Slinton /* 3739678Slinton * Print a list of currently active blocks starting with most recent. 3749678Slinton */ 3759678Slinton 3769678Slinton public wherecmd() 3779678Slinton { 3789678Slinton walkstack(false); 3799678Slinton } 3809678Slinton 3819678Slinton /* 3829678Slinton * Dump the world to the given file. 3839678Slinton * Like "where", but variables are dumped also. 3849678Slinton */ 3859678Slinton 3869678Slinton public dump() 3879678Slinton { 3889678Slinton walkstack(true); 3899678Slinton } 3909678Slinton 3919678Slinton /* 3929678Slinton * Walk the stack of active procedures printing information 3939678Slinton * about each active procedure. 3949678Slinton */ 3959678Slinton 3969678Slinton private walkstack(dumpvariables) 3979678Slinton Boolean dumpvariables; 3989678Slinton { 3999678Slinton register Frame frp; 4009678Slinton register Boolean save; 4019678Slinton register Lineno line; 40216618Ssam Symbol f; 4039678Slinton struct Frame frame; 4049678Slinton 4059678Slinton if (notstarted(process)) { 4069678Slinton error("program is not active"); 4079678Slinton } else { 4089678Slinton save = walkingstack; 4099678Slinton walkingstack = true; 4109678Slinton frp = &frame; 41116618Ssam getcurfunc(frp, &f); 4129678Slinton do { 4139678Slinton printf("%s", symname(f)); 41414442Slinton if (not isinline(f)) { 41514442Slinton printparams(f, frp); 41614442Slinton } 4179841Slinton line = srcline(frp->save_pc - 1); 4189678Slinton if (line != 0) { 4199678Slinton printf(", line %d", line); 4209841Slinton printf(" in \"%s\"\n", srcfilename(frp->save_pc - 1)); 4219678Slinton } else { 4229678Slinton printf(" at 0x%x\n", frp->save_pc); 4239678Slinton } 4249678Slinton if (dumpvariables) { 4259678Slinton dumpvars(f, frp); 4269678Slinton putchar('\n'); 4279678Slinton } 42816618Ssam frp = nextfunc(frp, &f); 42911866Slinton } while (frp != nil and f != program); 4309678Slinton if (dumpvariables) { 4319678Slinton printf("in \"%s\":\n", symname(program)); 4329678Slinton dumpvars(program, nil); 4339678Slinton putchar('\n'); 4349678Slinton } 4359678Slinton walkingstack = save; 4369678Slinton } 4379678Slinton } 4389678Slinton 4399678Slinton /* 44016618Ssam * Set the current function to the given symbol. 44116618Ssam * We must adjust "curframe" so that subsequent operations are 44216618Ssam * not confused; for simplicity we simply clear it. 44316618Ssam */ 44416618Ssam 44516618Ssam public setcurfunc (f) 44616618Ssam Symbol f; 44716618Ssam { 44816618Ssam curfunc = f; 44916618Ssam curframe = nil; 45016618Ssam } 45116618Ssam 45216618Ssam /* 45316618Ssam * Set curfunc to be N up/down the stack from its current value. 45416618Ssam */ 45516618Ssam 45616618Ssam public up (n) 45716618Ssam integer n; 45816618Ssam { 45916618Ssam integer i; 46016618Ssam Symbol f; 46116618Ssam Frame frp; 46216618Ssam boolean done; 46316618Ssam 46416618Ssam if (not isactive(program)) { 46516618Ssam error("program is not active"); 46616618Ssam } else if (curfunc == nil) { 46716618Ssam error("no current function"); 46816618Ssam } else { 46916618Ssam i = 0; 47016618Ssam f = curfunc; 47116618Ssam if (curframe != nil) { 47216618Ssam frp = curframe; 47316618Ssam } else { 47416618Ssam frp = findframe(f); 47516618Ssam } 47616618Ssam done = false; 47716618Ssam do { 47816618Ssam if (frp == nil) { 47916618Ssam done = true; 48016618Ssam error("not that many levels"); 48116618Ssam } else if (i >= n) { 48216618Ssam done = true; 48316618Ssam curfunc = f; 48416618Ssam curframe = &curframerec; 48516618Ssam *curframe = *frp; 48616618Ssam } else if (f == program) { 48716618Ssam done = true; 48816618Ssam error("not that many levels"); 48916618Ssam } else { 49016618Ssam frp = nextfunc(frp, &f); 49116618Ssam } 49216618Ssam ++i; 49316618Ssam } while (not done); 49416618Ssam } 49516618Ssam } 49616618Ssam 49716618Ssam public down (n) 49816618Ssam integer n; 49916618Ssam { 50016618Ssam integer i, depth; 50116618Ssam register Frame frp; 50216618Ssam Symbol f; 50316618Ssam struct Frame frame; 50416618Ssam 50516618Ssam if (not isactive(program)) { 50616618Ssam error("program is not active"); 50716618Ssam } else if (curfunc == nil) { 50816618Ssam error("no current function"); 50916618Ssam } else { 51016618Ssam depth = 0; 51116618Ssam frp = &frame; 51216618Ssam getcurfunc(frp, &f); 51316618Ssam if (curframe == nil) { 51416618Ssam curframe = &curframerec; 51516618Ssam *curframe = *(findframe(curfunc)); 51616618Ssam } 51716618Ssam while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) { 51816618Ssam frp = nextfunc(frp, &f); 51916618Ssam ++depth; 52016618Ssam } 52116618Ssam if (f == nil or n > depth) { 52216618Ssam error("not that many levels"); 52316618Ssam } else { 52416618Ssam depth -= n; 52516618Ssam frp = &frame; 52616618Ssam getcurfunc(frp, &f); 52716618Ssam for (i = 0; i < depth; i++) { 52816618Ssam frp = nextfunc(frp, &f); 52916618Ssam assert(frp != nil); 53016618Ssam } 53116618Ssam curfunc = f; 53216618Ssam *curframe = *frp; 53316618Ssam } 53416618Ssam } 53516618Ssam } 53616618Ssam 53716618Ssam /* 5389678Slinton * Find the entry point of a procedure or function. 5399678Slinton */ 5409678Slinton 5419678Slinton public findbeginning(f) 5429678Slinton Symbol f; 5439678Slinton { 54416618Ssam if (isinternal(f)) { 54516618Ssam f->symvalue.funcv.beginaddr += 15; 54616618Ssam } else { 54716618Ssam f->symvalue.funcv.beginaddr += 2; 54816618Ssam } 5499678Slinton } 5509678Slinton 5519678Slinton /* 5529678Slinton * Return the address corresponding to the first line in a function. 5539678Slinton */ 5549678Slinton 5559678Slinton public Address firstline(f) 5569678Slinton Symbol f; 5579678Slinton { 5589678Slinton Address addr; 5599678Slinton 5609678Slinton addr = codeloc(f); 5619678Slinton while (linelookup(addr) == 0 and addr < objsize) { 5629678Slinton ++addr; 5639678Slinton } 5649678Slinton if (addr == objsize) { 5659678Slinton addr = -1; 5669678Slinton } 5679678Slinton return addr; 5689678Slinton } 5699678Slinton 5709678Slinton /* 5719678Slinton * Catcher drops strike three ... 5729678Slinton */ 5739678Slinton 5749678Slinton public runtofirst() 5759678Slinton { 5769678Slinton Address addr; 5779678Slinton 5789678Slinton addr = pc; 5799678Slinton while (linelookup(addr) == 0 and addr < objsize) { 5809678Slinton ++addr; 5819678Slinton } 5829678Slinton if (addr < objsize) { 5839678Slinton stepto(addr); 5849678Slinton } 5859678Slinton } 5869678Slinton 5879678Slinton /* 5889678Slinton * Return the address corresponding to the end of the program. 5899678Slinton * 5909678Slinton * We look for the entry to "exit". 5919678Slinton */ 5929678Slinton 5939678Slinton public Address lastaddr() 5949678Slinton { 5959678Slinton register Symbol s; 5969678Slinton 5979678Slinton s = lookup(identname("exit", true)); 5989678Slinton if (s == nil) { 5999678Slinton panic("can't find exit"); 6009678Slinton } 6019678Slinton return codeloc(s); 6029678Slinton } 6039678Slinton 6049678Slinton /* 6059678Slinton * Decide if the given function is currently active. 6069678Slinton * 6079678Slinton * We avoid calls to "findframe" during a stack trace for efficiency. 6089678Slinton * Presumably information evaluated while walking the stack is active. 6099678Slinton */ 6109678Slinton 6119678Slinton public Boolean isactive(f) 6129678Slinton Symbol f; 6139678Slinton { 6149678Slinton register Boolean b; 6159678Slinton 6169678Slinton if (isfinished(process)) { 6179678Slinton b = false; 6189678Slinton } else { 6199678Slinton if (walkingstack or f == program or 6209678Slinton (ismodule(f) and isactive(container(f)))) { 6219678Slinton b = true; 6229678Slinton } else { 6239678Slinton b = (Boolean) (findframe(f) != nil); 6249678Slinton } 6259678Slinton } 6269678Slinton return b; 6279678Slinton } 6289678Slinton 6299678Slinton /* 6309678Slinton * Evaluate a call to a procedure. 6319678Slinton */ 6329678Slinton 6339678Slinton public callproc(procnode, arglist) 6349678Slinton Node procnode; 6359678Slinton Node arglist; 6369678Slinton { 6379678Slinton Symbol proc; 6389678Slinton Integer argc; 6399678Slinton 6409678Slinton if (procnode->op != O_SYM) { 6419678Slinton beginerrmsg(); 6429678Slinton fprintf(stderr, "can't call \""); 6439678Slinton prtree(stderr, procnode); 6449678Slinton fprintf(stderr, "\""); 6459678Slinton enderrmsg(); 6469678Slinton } 6479678Slinton assert(procnode->op == O_SYM); 6489678Slinton proc = procnode->value.sym; 6499678Slinton if (not isblock(proc)) { 6509678Slinton error("\"%s\" is not a procedure or function", symname(proc)); 6519678Slinton } 6529678Slinton pushenv(); 6539678Slinton pc = codeloc(proc); 6549678Slinton argc = pushargs(proc, arglist); 6559678Slinton beginproc(proc, argc); 6569678Slinton isstopped = true; 6579678Slinton event_once(build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)), 6589678Slinton buildcmdlist(build(O_PROCRTN, proc))); 65916618Ssam cont(0); 6609678Slinton /* NOTREACHED */ 6619678Slinton } 6629678Slinton 6639678Slinton /* 6649678Slinton * Push the arguments on the process' stack. We do this by first 6659678Slinton * evaluating them on the "eval" stack, then copying into the process' 6669678Slinton * space. 6679678Slinton */ 6689678Slinton 6699678Slinton private Integer pushargs(proc, arglist) 6709678Slinton Symbol proc; 6719678Slinton Node arglist; 6729678Slinton { 6739678Slinton Stack *savesp; 6749678Slinton int argc, args_size; 6759678Slinton 6769678Slinton savesp = sp; 6779678Slinton argc = evalargs(proc, arglist); 6789678Slinton args_size = sp - savesp; 6799678Slinton setreg(STKP, reg(STKP) - args_size); 6809678Slinton dwrite(savesp, reg(STKP), args_size); 6819678Slinton sp = savesp; 6829678Slinton return argc; 6839678Slinton } 6849678Slinton 6859678Slinton /* 68616618Ssam * Check to see if an expression is correct for a given parameter. 68716618Ssam * If the given parameter is false, don't worry about type inconsistencies. 68816618Ssam * 68916618Ssam * Return whether or not it is ok. 6909678Slinton */ 6919678Slinton 69216618Ssam private boolean chkparam (actual, formal, chk) 69316618Ssam Node actual; 69416618Ssam Symbol formal; 69516618Ssam boolean chk; 69616618Ssam { 69716618Ssam boolean b; 69816618Ssam 69916618Ssam b = true; 70016618Ssam if (chk) { 70116618Ssam if (formal == nil) { 70216618Ssam beginerrmsg(); 70316618Ssam fprintf(stderr, "too many parameters"); 70416618Ssam b = false; 70516618Ssam } else if (not compatible(formal->type, actual->nodetype)) { 70616618Ssam beginerrmsg(); 70716618Ssam fprintf(stderr, "type mismatch for %s", symname(formal)); 70816618Ssam b = false; 70916618Ssam } 71016618Ssam } 71116618Ssam if (b and formal != nil and isvarparam(formal) and 71216618Ssam not isopenarray(formal->type) and actual->op != O_RVAL) 71316618Ssam { 71416618Ssam beginerrmsg(); 71516618Ssam fprintf(stderr, "expected variable, found \""); 71616618Ssam prtree(stderr, actual); 71716618Ssam fprintf(stderr, "\""); 71816618Ssam b = false; 71916618Ssam } 72016618Ssam return b; 72116618Ssam } 72216618Ssam 72316618Ssam /* 72416618Ssam * Pass an expression to a particular parameter. 72516618Ssam * 72616618Ssam * Normally we pass either the address or value, but in some cases 72716618Ssam * (such as C strings) we want to copy the value onto the stack and 72816618Ssam * pass its address. 72916618Ssam */ 73016618Ssam 73116618Ssam private passparam (actual, formal) 73216618Ssam Node actual; 73316618Ssam Symbol formal; 73416618Ssam { 73516618Ssam boolean b; 73616618Ssam Address addr; 73716618Ssam Stack *savesp; 73816618Ssam integer paramsize; 73916618Ssam 74016618Ssam if (isvarparam(formal) and not isopenarray(formal->type)) { 74116618Ssam addr = lval(actual->value.arg[0]); 74216618Ssam push(Address, addr); 74316618Ssam } else if (passaddr(formal, actual->nodetype)) { 74416618Ssam savesp = sp; 74516618Ssam eval(actual); 74616618Ssam paramsize = sp - savesp; 74716618Ssam setreg(STKP, reg(STKP) - paramsize); 74816618Ssam dwrite(savesp, reg(STKP), paramsize); 74916618Ssam sp = savesp; 75016618Ssam push(Address, reg(STKP)); 75116618Ssam if (formal != nil and isopenarray(formal->type)) { 75216618Ssam push(integer, paramsize div size(formal->type->type)); 75316618Ssam } 75416618Ssam } else { 75516618Ssam eval(actual); 75616618Ssam } 75716618Ssam } 75816618Ssam 75916618Ssam /* 76016618Ssam * Evaluate an argument list left-to-right. 76116618Ssam */ 76216618Ssam 7639678Slinton private Integer evalargs(proc, arglist) 7649678Slinton Symbol proc; 7659678Slinton Node arglist; 7669678Slinton { 76716618Ssam Node p, actual; 76816618Ssam Symbol formal; 7699678Slinton Stack *savesp; 7709678Slinton Integer count; 77116618Ssam boolean chk; 7729678Slinton 7739678Slinton savesp = sp; 7749678Slinton count = 0; 77516618Ssam formal = proc->chain; 77616618Ssam chk = (boolean) (not nosource(proc)); 7779678Slinton for (p = arglist; p != nil; p = p->value.arg[1]) { 77816618Ssam assert(p->op == O_COMMA); 77916618Ssam actual = p->value.arg[0]; 78016618Ssam if (not chkparam(actual, formal, chk)) { 78116618Ssam fprintf(stderr, " in call to %s", symname(proc)); 7829678Slinton sp = savesp; 78316618Ssam enderrmsg(); 7849678Slinton } 78516618Ssam passparam(actual, formal); 78616618Ssam if (formal != nil) { 78716618Ssam formal = formal->chain; 7889678Slinton } 7899678Slinton ++count; 7909678Slinton } 79116618Ssam if (chk) { 79216618Ssam if (formal != nil) { 79316618Ssam sp = savesp; 79416618Ssam error("not enough parameters to %s", symname(proc)); 79516618Ssam } 7969678Slinton } 7979678Slinton return count; 7989678Slinton } 7999678Slinton 8009678Slinton public procreturn(f) 8019678Slinton Symbol f; 8029678Slinton { 8039678Slinton flushoutput(); 8049678Slinton putchar('\n'); 8059678Slinton printname(stdout, f); 8069678Slinton printf(" returns successfully\n", symname(f)); 8079678Slinton popenv(); 8089678Slinton erecover(); 8099678Slinton } 8109678Slinton 8119678Slinton /* 8129678Slinton * Push the current environment. 8139678Slinton */ 8149678Slinton 8159678Slinton private pushenv() 8169678Slinton { 8179678Slinton push(Address, pc); 8189678Slinton push(Lineno, curline); 8199678Slinton push(String, cursource); 8209678Slinton push(Boolean, isstopped); 8219678Slinton push(Symbol, curfunc); 82216618Ssam push(Frame, curframe); 82316618Ssam push(struct Frame, curframerec); 8249678Slinton push(Word, reg(PROGCTR)); 8259678Slinton push(Word, reg(STKP)); 8269678Slinton } 8279678Slinton 8289678Slinton /* 8299678Slinton * Pop back to the real world. 8309678Slinton */ 8319678Slinton 8329678Slinton public popenv() 8339678Slinton { 8349678Slinton register String filename; 8359678Slinton 8369678Slinton setreg(STKP, pop(Word)); 8379678Slinton setreg(PROGCTR, pop(Word)); 83816618Ssam curframerec = pop(struct Frame); 83916618Ssam curframe = pop(Frame); 8409678Slinton curfunc = pop(Symbol); 8419678Slinton isstopped = pop(Boolean); 8429678Slinton filename = pop(String); 8439678Slinton curline = pop(Lineno); 8449678Slinton pc = pop(Address); 8459678Slinton setsource(filename); 8469678Slinton } 8479678Slinton 8489678Slinton /* 8499678Slinton * Flush the debuggee's standard output. 8509678Slinton * 8519678Slinton * This is VERY dependent on the use of stdio. 8529678Slinton */ 8539678Slinton 8549678Slinton public flushoutput() 8559678Slinton { 8569678Slinton register Symbol p, iob; 8579678Slinton register Stack *savesp; 8589678Slinton 8599678Slinton p = lookup(identname("fflush", true)); 8609678Slinton while (p != nil and not isblock(p)) { 8619678Slinton p = p->next_sym; 8629678Slinton } 8639678Slinton if (p != nil) { 8649678Slinton iob = lookup(identname("_iob", true)); 8659678Slinton if (iob != nil) { 8669678Slinton pushenv(); 8679678Slinton pc = codeloc(p); 8689678Slinton savesp = sp; 8699678Slinton push(long, address(iob, nil) + sizeof(struct _iobuf)); 8709678Slinton setreg(STKP, reg(STKP) - sizeof(long)); 8719678Slinton dwrite(savesp, reg(STKP), sizeof(long)); 8729678Slinton sp = savesp; 8739678Slinton beginproc(p, 1); 8749678Slinton stepto(return_addr()); 8759678Slinton popenv(); 8769678Slinton } 8779678Slinton } 8789678Slinton } 879