112546Scsvaf 29678Slinton /* Copyright (c) 1982 Regents of the University of California */ 39678Slinton 4*16618Ssam static char sccsid[] = "@(#)runtime.c 1.8 8/10/83"; 59678Slinton 6*16618Ssam static char rcsid[] = "$Header: runtime.c,v 1.3 84/03/27 10:23:40 linton Exp $"; 7*16618Ssam 89678Slinton /* 99678Slinton * Runtime organization dependent routines, mostly dealing with 109678Slinton * activation records. 119678Slinton */ 129678Slinton 139678Slinton #include "defs.h" 149678Slinton #include "runtime.h" 159678Slinton #include "process.h" 169678Slinton #include "machine.h" 179678Slinton #include "events.h" 189678Slinton #include "mappings.h" 199678Slinton #include "symbols.h" 209678Slinton #include "tree.h" 219678Slinton #include "eval.h" 229678Slinton #include "operators.h" 239678Slinton #include "object.h" 2412546Scsvaf #include <sys/param.h> 259678Slinton 269678Slinton #ifndef public 279678Slinton typedef struct Frame *Frame; 289678Slinton 299678Slinton #include "machine.h" 309678Slinton #endif 319678Slinton 329678Slinton #define NSAVEREG 12 339678Slinton 349678Slinton struct Frame { 359678Slinton Integer condition_handler; 369678Slinton Integer mask; 379678Slinton Address save_ap; /* argument pointer */ 389678Slinton Address save_fp; /* frame pointer */ 399678Slinton Address save_pc; /* program counter */ 409678Slinton Word save_reg[NSAVEREG]; /* not necessarily there */ 419678Slinton }; 429678Slinton 43*16618Ssam private Frame curframe = nil; 44*16618Ssam private struct Frame curframerec; 459678Slinton private Boolean walkingstack = false; 469678Slinton 47*16618Ssam #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp) 48*16618Ssam 499678Slinton /* 509678Slinton * Set a frame to the current activation record. 519678Slinton */ 529678Slinton 539678Slinton private getcurframe(frp) 549678Slinton register Frame frp; 559678Slinton { 569678Slinton register int i; 579678Slinton 589678Slinton checkref(frp); 599678Slinton frp->mask = reg(NREG); 609678Slinton frp->save_ap = reg(ARGP); 619678Slinton frp->save_fp = reg(FRP); 6212051Slinton frp->save_pc = reg(PROGCTR) + 1; 639678Slinton for (i = 0; i < NSAVEREG; i++) { 649678Slinton frp->save_reg[i] = reg(i); 659678Slinton } 669678Slinton } 679678Slinton 689678Slinton /* 699678Slinton * Return a pointer to the next activation record up the stack. 709678Slinton * Return nil if there is none. 719678Slinton * Writes over space pointed to by given argument. 729678Slinton */ 739678Slinton 749678Slinton #define bis(b, n) ((b & (1 << (n))) != 0) 759678Slinton 769678Slinton private Frame nextframe(frp) 779678Slinton Frame frp; 789678Slinton { 799678Slinton register Frame newfrp; 809678Slinton struct Frame frame; 819678Slinton register Integer i, j, mask; 8212546Scsvaf Address prev_frame, callpc; 8313937Slinton static Integer ntramp = 0; 849678Slinton 859678Slinton newfrp = frp; 8612546Scsvaf prev_frame = frp->save_fp; 8712546Scsvaf 8813937Slinton /* 8913937Slinton * The check for interrupt generated frames is taken from adb with only 9013937Slinton * partial understanding. If you're in "sub" and on a sigxxx "sigsub" 9113937Slinton * gets control, then the stack does NOT look like <main, sub, sigsub>. 9212546Scsvaf * 9312546Scsvaf * As best I can make out it looks like: 9412546Scsvaf * 9513937Slinton * <main, (machine check exception block + sub), sysframe, sigsub>. 9613937Slinton * 9713937Slinton * When the signal occurs an exception block and a frame for the routine 9813937Slinton * in which it occured are pushed on the user stack. Then another frame 9913937Slinton * is pushed corresponding to a call from the kernel to sigsub. 10013937Slinton * 10112546Scsvaf * The addr in sub at which the exception occured is not in sub.save_pc 10213937Slinton * but in the machine check exception block. It is at the magic address 10314620Ssam * fp + 84. 10412546Scsvaf * 10512546Scsvaf * The current approach ignores the sys_frame (what adb reports as sigtramp) 10613937Slinton * and takes the pc for sub from the exception block. This allows the 10713937Slinton * "where" command to report <main, sub, sigsub>, which seems reasonable. 10812546Scsvaf */ 10912546Scsvaf 11013937Slinton nextf: 11113937Slinton dread(&frame, prev_frame, sizeof(struct Frame)); 11213937Slinton if (ntramp == 1) { 11314620Ssam dread(&callpc, prev_frame + 84, sizeof(callpc)); 11413937Slinton } else { 11513937Slinton callpc = frame.save_pc; 11613937Slinton } 1179678Slinton if (frame.save_fp == nil) { 1189678Slinton newfrp = nil; 11913937Slinton } else if (callpc > 0x80000000 - 0x200 * UPAGES ) { 12012546Scsvaf ntramp++; 12112546Scsvaf prev_frame = frame.save_fp; 12212546Scsvaf goto nextf; 12313937Slinton } else { 12412546Scsvaf frame.save_pc = callpc; 12513937Slinton ntramp = 0; 1269678Slinton mask = ((frame.mask >> 16) & 0x0fff); 1279678Slinton j = 0; 1289678Slinton for (i = 0; i < NSAVEREG; i++) { 1299678Slinton if (bis(mask, i)) { 1309678Slinton newfrp->save_reg[i] = frame.save_reg[j]; 1319678Slinton ++j; 1329678Slinton } 1339678Slinton } 1349678Slinton newfrp->condition_handler = frame.condition_handler; 1359678Slinton newfrp->mask = mask; 1369678Slinton newfrp->save_ap = frame.save_ap; 1379678Slinton newfrp->save_fp = frame.save_fp; 1389678Slinton newfrp->save_pc = frame.save_pc; 1399678Slinton } 1409678Slinton return newfrp; 1419678Slinton } 1429678Slinton 1439678Slinton /* 144*16618Ssam * Get the current frame information in the given Frame and store the 145*16618Ssam * associated function in the given value-result parameter. 146*16618Ssam */ 147*16618Ssam 148*16618Ssam private getcurfunc (frp, fp) 149*16618Ssam Frame frp; 150*16618Ssam Symbol *fp; 151*16618Ssam { 152*16618Ssam getcurframe(frp); 153*16618Ssam *fp = whatblock(frp->save_pc); 154*16618Ssam } 155*16618Ssam 156*16618Ssam /* 157*16618Ssam * Return the frame associated with the next function up the call stack, or 158*16618Ssam * nil if there is none. The function is returned in a value-result parameter. 159*16618Ssam * For "inline" functions the statically outer function and same frame 160*16618Ssam * are returned. 161*16618Ssam */ 162*16618Ssam 163*16618Ssam private Frame nextfunc (frp, fp) 164*16618Ssam Frame frp; 165*16618Ssam Symbol *fp; 166*16618Ssam { 167*16618Ssam Symbol t; 168*16618Ssam Frame nfrp; 169*16618Ssam 170*16618Ssam t = *fp; 171*16618Ssam checkref(t); 172*16618Ssam if (isinline(t)) { 173*16618Ssam t = container(t); 174*16618Ssam nfrp = frp; 175*16618Ssam } else { 176*16618Ssam nfrp = nextframe(frp); 177*16618Ssam if (nfrp == nil) { 178*16618Ssam t = nil; 179*16618Ssam } else { 180*16618Ssam t = whatblock(nfrp->save_pc); 181*16618Ssam } 182*16618Ssam } 183*16618Ssam *fp = t; 184*16618Ssam return nfrp; 185*16618Ssam } 186*16618Ssam 187*16618Ssam /* 1889678Slinton * Return the frame associated with the given function. 1899678Slinton * If the function is nil, return the most recently activated frame. 1909678Slinton * 1919678Slinton * Static allocation for the frame. 1929678Slinton */ 1939678Slinton 1949678Slinton public Frame findframe(f) 1959678Slinton Symbol f; 1969678Slinton { 1979678Slinton register Frame frp; 1989678Slinton static struct Frame frame; 19911866Slinton Symbol p; 200*16618Ssam Boolean done; 2019678Slinton 2029678Slinton frp = &frame; 2039678Slinton getcurframe(frp); 204*16618Ssam if (f != nil) { 205*16618Ssam if (f == curfunc and curframe != nil) { 206*16618Ssam *frp = *curframe; 207*16618Ssam } else { 208*16618Ssam done = false; 209*16618Ssam p = whatblock(frp->save_pc); 210*16618Ssam do { 211*16618Ssam if (p == f) { 212*16618Ssam done = true; 213*16618Ssam } else if (p == program) { 214*16618Ssam done = true; 215*16618Ssam frp = nil; 216*16618Ssam } else { 217*16618Ssam frp = nextfunc(frp, &p); 218*16618Ssam if (frp == nil) { 219*16618Ssam done = true; 220*16618Ssam } 221*16618Ssam } 222*16618Ssam } while (not done); 22315784Ssam } 2249678Slinton } 225*16618Ssam return frp; 2269678Slinton } 2279678Slinton 2289678Slinton /* 2299678Slinton * Find the return address of the current procedure/function. 2309678Slinton */ 2319678Slinton 2329678Slinton public Address return_addr() 2339678Slinton { 2349678Slinton Frame frp; 2359678Slinton Address addr; 2369678Slinton struct Frame frame; 2379678Slinton 2389678Slinton frp = &frame; 2399678Slinton getcurframe(frp); 2409678Slinton frp = nextframe(frp); 2419678Slinton if (frp == nil) { 2429678Slinton addr = 0; 2439678Slinton } else { 2449678Slinton addr = frp->save_pc; 2459678Slinton } 2469678Slinton return addr; 2479678Slinton } 2489678Slinton 2499678Slinton /* 2509678Slinton * Push the value associated with the current function. 2519678Slinton */ 2529678Slinton 2539678Slinton public pushretval(len, isindirect) 2549678Slinton Integer len; 2559678Slinton Boolean isindirect; 2569678Slinton { 2579678Slinton Word r0; 2589678Slinton 2599678Slinton r0 = reg(0); 2609678Slinton if (isindirect) { 2619678Slinton rpush((Address) r0, len); 2629678Slinton } else { 2639678Slinton switch (len) { 2649678Slinton case sizeof(char): 2659678Slinton push(char, r0); 2669678Slinton break; 2679678Slinton 2689678Slinton case sizeof(short): 2699678Slinton push(short, r0); 2709678Slinton break; 2719678Slinton 2729678Slinton default: 2739678Slinton if (len == sizeof(Word)) { 2749678Slinton push(Word, r0); 2759678Slinton } else if (len == 2*sizeof(Word)) { 2769678Slinton push(Word, r0); 2779678Slinton push(Word, reg(1)); 2789678Slinton } else { 2799678Slinton panic("not indirect in pushretval?"); 2809678Slinton } 2819678Slinton break; 2829678Slinton } 2839678Slinton } 2849678Slinton } 2859678Slinton 2869678Slinton /* 2879678Slinton * Return the base address for locals in the given frame. 2889678Slinton */ 2899678Slinton 2909678Slinton public Address locals_base(frp) 2919678Slinton register Frame frp; 2929678Slinton { 2939678Slinton return (frp == nil) ? reg(FRP) : frp->save_fp; 2949678Slinton } 2959678Slinton 2969678Slinton /* 2979678Slinton * Return the base address for arguments in the given frame. 2989678Slinton */ 2999678Slinton 3009678Slinton public Address args_base(frp) 3019678Slinton register Frame frp; 3029678Slinton { 3039678Slinton return (frp == nil) ? reg(ARGP) : frp->save_ap; 3049678Slinton } 3059678Slinton 3069678Slinton /* 3079678Slinton * Return saved register n from the given frame. 3089678Slinton */ 3099678Slinton 3109678Slinton public Word savereg(n, frp) 3119678Slinton register Integer n; 3129678Slinton register Frame frp; 3139678Slinton { 3149678Slinton register Word w; 3159678Slinton 3169678Slinton if (frp == nil) { 3179678Slinton w = reg(n); 3189678Slinton } else { 3199678Slinton switch (n) { 3209678Slinton case ARGP: 3219678Slinton w = frp->save_ap; 3229678Slinton break; 3239678Slinton 3249678Slinton case FRP: 3259678Slinton w = frp->save_fp; 3269678Slinton break; 3279678Slinton 3289678Slinton case STKP: 3299678Slinton w = reg(STKP); 3309678Slinton break; 3319678Slinton 3329678Slinton case PROGCTR: 3339678Slinton w = frp->save_pc; 3349678Slinton break; 3359678Slinton 3369678Slinton default: 3379678Slinton assert(n >= 0 and n < NSAVEREG); 3389678Slinton w = frp->save_reg[n]; 3399678Slinton break; 3409678Slinton } 3419678Slinton } 3429678Slinton return w; 3439678Slinton } 3449678Slinton 3459678Slinton /* 3469678Slinton * Return the nth argument to the current procedure. 3479678Slinton */ 3489678Slinton 3499678Slinton public Word argn(n, frp) 3509678Slinton Integer n; 3519678Slinton Frame frp; 3529678Slinton { 3539678Slinton Word w; 3549678Slinton 3559678Slinton dread(&w, args_base(frp) + (n * sizeof(Word)), sizeof(w)); 3569678Slinton return w; 3579678Slinton } 3589678Slinton 3599678Slinton /* 3609678Slinton * Calculate the entry address for a procedure or function parameter, 3619678Slinton * given the address of the descriptor. 3629678Slinton */ 3639678Slinton 3649678Slinton public Address fparamaddr(a) 3659678Slinton Address a; 3669678Slinton { 3679678Slinton Address r; 3689678Slinton 3699678Slinton dread(&r, a, sizeof(r)); 3709678Slinton return r; 3719678Slinton } 3729678Slinton 3739678Slinton /* 3749678Slinton * Print a list of currently active blocks starting with most recent. 3759678Slinton */ 3769678Slinton 3779678Slinton public wherecmd() 3789678Slinton { 3799678Slinton walkstack(false); 3809678Slinton } 3819678Slinton 3829678Slinton /* 3839678Slinton * Dump the world to the given file. 3849678Slinton * Like "where", but variables are dumped also. 3859678Slinton */ 3869678Slinton 3879678Slinton public dump() 3889678Slinton { 3899678Slinton walkstack(true); 3909678Slinton } 3919678Slinton 3929678Slinton /* 3939678Slinton * Walk the stack of active procedures printing information 3949678Slinton * about each active procedure. 3959678Slinton */ 3969678Slinton 3979678Slinton private walkstack(dumpvariables) 3989678Slinton Boolean dumpvariables; 3999678Slinton { 4009678Slinton register Frame frp; 4019678Slinton register Boolean save; 4029678Slinton register Lineno line; 403*16618Ssam Symbol f; 4049678Slinton struct Frame frame; 4059678Slinton 4069678Slinton if (notstarted(process)) { 4079678Slinton error("program is not active"); 4089678Slinton } else { 4099678Slinton save = walkingstack; 4109678Slinton walkingstack = true; 4119678Slinton frp = &frame; 412*16618Ssam getcurfunc(frp, &f); 4139678Slinton do { 4149678Slinton printf("%s", symname(f)); 41514442Slinton if (not isinline(f)) { 41614442Slinton printparams(f, frp); 41714442Slinton } 4189841Slinton line = srcline(frp->save_pc - 1); 4199678Slinton if (line != 0) { 4209678Slinton printf(", line %d", line); 4219841Slinton printf(" in \"%s\"\n", srcfilename(frp->save_pc - 1)); 4229678Slinton } else { 4239678Slinton printf(" at 0x%x\n", frp->save_pc); 4249678Slinton } 4259678Slinton if (dumpvariables) { 4269678Slinton dumpvars(f, frp); 4279678Slinton putchar('\n'); 4289678Slinton } 429*16618Ssam frp = nextfunc(frp, &f); 43011866Slinton } while (frp != nil and f != program); 4319678Slinton if (dumpvariables) { 4329678Slinton printf("in \"%s\":\n", symname(program)); 4339678Slinton dumpvars(program, nil); 4349678Slinton putchar('\n'); 4359678Slinton } 4369678Slinton walkingstack = save; 4379678Slinton } 4389678Slinton } 4399678Slinton 4409678Slinton /* 441*16618Ssam * Set the current function to the given symbol. 442*16618Ssam * We must adjust "curframe" so that subsequent operations are 443*16618Ssam * not confused; for simplicity we simply clear it. 444*16618Ssam */ 445*16618Ssam 446*16618Ssam public setcurfunc (f) 447*16618Ssam Symbol f; 448*16618Ssam { 449*16618Ssam curfunc = f; 450*16618Ssam curframe = nil; 451*16618Ssam } 452*16618Ssam 453*16618Ssam /* 454*16618Ssam * Set curfunc to be N up/down the stack from its current value. 455*16618Ssam */ 456*16618Ssam 457*16618Ssam public up (n) 458*16618Ssam integer n; 459*16618Ssam { 460*16618Ssam integer i; 461*16618Ssam Symbol f; 462*16618Ssam Frame frp; 463*16618Ssam boolean done; 464*16618Ssam 465*16618Ssam if (not isactive(program)) { 466*16618Ssam error("program is not active"); 467*16618Ssam } else if (curfunc == nil) { 468*16618Ssam error("no current function"); 469*16618Ssam } else { 470*16618Ssam i = 0; 471*16618Ssam f = curfunc; 472*16618Ssam if (curframe != nil) { 473*16618Ssam frp = curframe; 474*16618Ssam } else { 475*16618Ssam frp = findframe(f); 476*16618Ssam } 477*16618Ssam done = false; 478*16618Ssam do { 479*16618Ssam if (frp == nil) { 480*16618Ssam done = true; 481*16618Ssam error("not that many levels"); 482*16618Ssam } else if (i >= n) { 483*16618Ssam done = true; 484*16618Ssam curfunc = f; 485*16618Ssam curframe = &curframerec; 486*16618Ssam *curframe = *frp; 487*16618Ssam } else if (f == program) { 488*16618Ssam done = true; 489*16618Ssam error("not that many levels"); 490*16618Ssam } else { 491*16618Ssam frp = nextfunc(frp, &f); 492*16618Ssam } 493*16618Ssam ++i; 494*16618Ssam } while (not done); 495*16618Ssam } 496*16618Ssam } 497*16618Ssam 498*16618Ssam public down (n) 499*16618Ssam integer n; 500*16618Ssam { 501*16618Ssam integer i, depth; 502*16618Ssam register Frame frp; 503*16618Ssam Symbol f; 504*16618Ssam struct Frame frame; 505*16618Ssam 506*16618Ssam if (not isactive(program)) { 507*16618Ssam error("program is not active"); 508*16618Ssam } else if (curfunc == nil) { 509*16618Ssam error("no current function"); 510*16618Ssam } else { 511*16618Ssam depth = 0; 512*16618Ssam frp = &frame; 513*16618Ssam getcurfunc(frp, &f); 514*16618Ssam if (curframe == nil) { 515*16618Ssam curframe = &curframerec; 516*16618Ssam *curframe = *(findframe(curfunc)); 517*16618Ssam } 518*16618Ssam while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) { 519*16618Ssam frp = nextfunc(frp, &f); 520*16618Ssam ++depth; 521*16618Ssam } 522*16618Ssam if (f == nil or n > depth) { 523*16618Ssam error("not that many levels"); 524*16618Ssam } else { 525*16618Ssam depth -= n; 526*16618Ssam frp = &frame; 527*16618Ssam getcurfunc(frp, &f); 528*16618Ssam for (i = 0; i < depth; i++) { 529*16618Ssam frp = nextfunc(frp, &f); 530*16618Ssam assert(frp != nil); 531*16618Ssam } 532*16618Ssam curfunc = f; 533*16618Ssam *curframe = *frp; 534*16618Ssam } 535*16618Ssam } 536*16618Ssam } 537*16618Ssam 538*16618Ssam /* 5399678Slinton * Find the entry point of a procedure or function. 5409678Slinton */ 5419678Slinton 5429678Slinton public findbeginning(f) 5439678Slinton Symbol f; 5449678Slinton { 545*16618Ssam if (isinternal(f)) { 546*16618Ssam f->symvalue.funcv.beginaddr += 15; 547*16618Ssam } else { 548*16618Ssam f->symvalue.funcv.beginaddr += 2; 549*16618Ssam } 5509678Slinton } 5519678Slinton 5529678Slinton /* 5539678Slinton * Return the address corresponding to the first line in a function. 5549678Slinton */ 5559678Slinton 5569678Slinton public Address firstline(f) 5579678Slinton Symbol f; 5589678Slinton { 5599678Slinton Address addr; 5609678Slinton 5619678Slinton addr = codeloc(f); 5629678Slinton while (linelookup(addr) == 0 and addr < objsize) { 5639678Slinton ++addr; 5649678Slinton } 5659678Slinton if (addr == objsize) { 5669678Slinton addr = -1; 5679678Slinton } 5689678Slinton return addr; 5699678Slinton } 5709678Slinton 5719678Slinton /* 5729678Slinton * Catcher drops strike three ... 5739678Slinton */ 5749678Slinton 5759678Slinton public runtofirst() 5769678Slinton { 5779678Slinton Address addr; 5789678Slinton 5799678Slinton addr = pc; 5809678Slinton while (linelookup(addr) == 0 and addr < objsize) { 5819678Slinton ++addr; 5829678Slinton } 5839678Slinton if (addr < objsize) { 5849678Slinton stepto(addr); 5859678Slinton } 5869678Slinton } 5879678Slinton 5889678Slinton /* 5899678Slinton * Return the address corresponding to the end of the program. 5909678Slinton * 5919678Slinton * We look for the entry to "exit". 5929678Slinton */ 5939678Slinton 5949678Slinton public Address lastaddr() 5959678Slinton { 5969678Slinton register Symbol s; 5979678Slinton 5989678Slinton s = lookup(identname("exit", true)); 5999678Slinton if (s == nil) { 6009678Slinton panic("can't find exit"); 6019678Slinton } 6029678Slinton return codeloc(s); 6039678Slinton } 6049678Slinton 6059678Slinton /* 6069678Slinton * Decide if the given function is currently active. 6079678Slinton * 6089678Slinton * We avoid calls to "findframe" during a stack trace for efficiency. 6099678Slinton * Presumably information evaluated while walking the stack is active. 6109678Slinton */ 6119678Slinton 6129678Slinton public Boolean isactive(f) 6139678Slinton Symbol f; 6149678Slinton { 6159678Slinton register Boolean b; 6169678Slinton 6179678Slinton if (isfinished(process)) { 6189678Slinton b = false; 6199678Slinton } else { 6209678Slinton if (walkingstack or f == program or 6219678Slinton (ismodule(f) and isactive(container(f)))) { 6229678Slinton b = true; 6239678Slinton } else { 6249678Slinton b = (Boolean) (findframe(f) != nil); 6259678Slinton } 6269678Slinton } 6279678Slinton return b; 6289678Slinton } 6299678Slinton 6309678Slinton /* 6319678Slinton * Evaluate a call to a procedure. 6329678Slinton */ 6339678Slinton 6349678Slinton public callproc(procnode, arglist) 6359678Slinton Node procnode; 6369678Slinton Node arglist; 6379678Slinton { 6389678Slinton Symbol proc; 6399678Slinton Integer argc; 6409678Slinton 6419678Slinton if (procnode->op != O_SYM) { 6429678Slinton beginerrmsg(); 6439678Slinton fprintf(stderr, "can't call \""); 6449678Slinton prtree(stderr, procnode); 6459678Slinton fprintf(stderr, "\""); 6469678Slinton enderrmsg(); 6479678Slinton } 6489678Slinton assert(procnode->op == O_SYM); 6499678Slinton proc = procnode->value.sym; 6509678Slinton if (not isblock(proc)) { 6519678Slinton error("\"%s\" is not a procedure or function", symname(proc)); 6529678Slinton } 6539678Slinton pushenv(); 6549678Slinton pc = codeloc(proc); 6559678Slinton argc = pushargs(proc, arglist); 6569678Slinton beginproc(proc, argc); 6579678Slinton isstopped = true; 6589678Slinton event_once(build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)), 6599678Slinton buildcmdlist(build(O_PROCRTN, proc))); 660*16618Ssam cont(0); 6619678Slinton /* NOTREACHED */ 6629678Slinton } 6639678Slinton 6649678Slinton /* 6659678Slinton * Push the arguments on the process' stack. We do this by first 6669678Slinton * evaluating them on the "eval" stack, then copying into the process' 6679678Slinton * space. 6689678Slinton */ 6699678Slinton 6709678Slinton private Integer pushargs(proc, arglist) 6719678Slinton Symbol proc; 6729678Slinton Node arglist; 6739678Slinton { 6749678Slinton Stack *savesp; 6759678Slinton int argc, args_size; 6769678Slinton 6779678Slinton savesp = sp; 6789678Slinton argc = evalargs(proc, arglist); 6799678Slinton args_size = sp - savesp; 6809678Slinton setreg(STKP, reg(STKP) - args_size); 6819678Slinton dwrite(savesp, reg(STKP), args_size); 6829678Slinton sp = savesp; 6839678Slinton return argc; 6849678Slinton } 6859678Slinton 6869678Slinton /* 687*16618Ssam * Check to see if an expression is correct for a given parameter. 688*16618Ssam * If the given parameter is false, don't worry about type inconsistencies. 689*16618Ssam * 690*16618Ssam * Return whether or not it is ok. 6919678Slinton */ 6929678Slinton 693*16618Ssam private boolean chkparam (actual, formal, chk) 694*16618Ssam Node actual; 695*16618Ssam Symbol formal; 696*16618Ssam boolean chk; 697*16618Ssam { 698*16618Ssam boolean b; 699*16618Ssam 700*16618Ssam b = true; 701*16618Ssam if (chk) { 702*16618Ssam if (formal == nil) { 703*16618Ssam beginerrmsg(); 704*16618Ssam fprintf(stderr, "too many parameters"); 705*16618Ssam b = false; 706*16618Ssam } else if (not compatible(formal->type, actual->nodetype)) { 707*16618Ssam beginerrmsg(); 708*16618Ssam fprintf(stderr, "type mismatch for %s", symname(formal)); 709*16618Ssam b = false; 710*16618Ssam } 711*16618Ssam } 712*16618Ssam if (b and formal != nil and isvarparam(formal) and 713*16618Ssam not isopenarray(formal->type) and actual->op != O_RVAL) 714*16618Ssam { 715*16618Ssam beginerrmsg(); 716*16618Ssam fprintf(stderr, "expected variable, found \""); 717*16618Ssam prtree(stderr, actual); 718*16618Ssam fprintf(stderr, "\""); 719*16618Ssam b = false; 720*16618Ssam } 721*16618Ssam return b; 722*16618Ssam } 723*16618Ssam 724*16618Ssam /* 725*16618Ssam * Pass an expression to a particular parameter. 726*16618Ssam * 727*16618Ssam * Normally we pass either the address or value, but in some cases 728*16618Ssam * (such as C strings) we want to copy the value onto the stack and 729*16618Ssam * pass its address. 730*16618Ssam */ 731*16618Ssam 732*16618Ssam private passparam (actual, formal) 733*16618Ssam Node actual; 734*16618Ssam Symbol formal; 735*16618Ssam { 736*16618Ssam boolean b; 737*16618Ssam Address addr; 738*16618Ssam Stack *savesp; 739*16618Ssam integer paramsize; 740*16618Ssam 741*16618Ssam if (isvarparam(formal) and not isopenarray(formal->type)) { 742*16618Ssam addr = lval(actual->value.arg[0]); 743*16618Ssam push(Address, addr); 744*16618Ssam } else if (passaddr(formal, actual->nodetype)) { 745*16618Ssam savesp = sp; 746*16618Ssam eval(actual); 747*16618Ssam paramsize = sp - savesp; 748*16618Ssam setreg(STKP, reg(STKP) - paramsize); 749*16618Ssam dwrite(savesp, reg(STKP), paramsize); 750*16618Ssam sp = savesp; 751*16618Ssam push(Address, reg(STKP)); 752*16618Ssam if (formal != nil and isopenarray(formal->type)) { 753*16618Ssam push(integer, paramsize div size(formal->type->type)); 754*16618Ssam } 755*16618Ssam } else { 756*16618Ssam eval(actual); 757*16618Ssam } 758*16618Ssam } 759*16618Ssam 760*16618Ssam /* 761*16618Ssam * Evaluate an argument list left-to-right. 762*16618Ssam */ 763*16618Ssam 7649678Slinton private Integer evalargs(proc, arglist) 7659678Slinton Symbol proc; 7669678Slinton Node arglist; 7679678Slinton { 768*16618Ssam Node p, actual; 769*16618Ssam Symbol formal; 7709678Slinton Stack *savesp; 7719678Slinton Integer count; 772*16618Ssam boolean chk; 7739678Slinton 7749678Slinton savesp = sp; 7759678Slinton count = 0; 776*16618Ssam formal = proc->chain; 777*16618Ssam chk = (boolean) (not nosource(proc)); 7789678Slinton for (p = arglist; p != nil; p = p->value.arg[1]) { 779*16618Ssam assert(p->op == O_COMMA); 780*16618Ssam actual = p->value.arg[0]; 781*16618Ssam if (not chkparam(actual, formal, chk)) { 782*16618Ssam fprintf(stderr, " in call to %s", symname(proc)); 7839678Slinton sp = savesp; 784*16618Ssam enderrmsg(); 7859678Slinton } 786*16618Ssam passparam(actual, formal); 787*16618Ssam if (formal != nil) { 788*16618Ssam formal = formal->chain; 7899678Slinton } 7909678Slinton ++count; 7919678Slinton } 792*16618Ssam if (chk) { 793*16618Ssam if (formal != nil) { 794*16618Ssam sp = savesp; 795*16618Ssam error("not enough parameters to %s", symname(proc)); 796*16618Ssam } 7979678Slinton } 7989678Slinton return count; 7999678Slinton } 8009678Slinton 8019678Slinton public procreturn(f) 8029678Slinton Symbol f; 8039678Slinton { 8049678Slinton flushoutput(); 8059678Slinton putchar('\n'); 8069678Slinton printname(stdout, f); 8079678Slinton printf(" returns successfully\n", symname(f)); 8089678Slinton popenv(); 8099678Slinton erecover(); 8109678Slinton } 8119678Slinton 8129678Slinton /* 8139678Slinton * Push the current environment. 8149678Slinton */ 8159678Slinton 8169678Slinton private pushenv() 8179678Slinton { 8189678Slinton push(Address, pc); 8199678Slinton push(Lineno, curline); 8209678Slinton push(String, cursource); 8219678Slinton push(Boolean, isstopped); 8229678Slinton push(Symbol, curfunc); 823*16618Ssam push(Frame, curframe); 824*16618Ssam push(struct Frame, curframerec); 8259678Slinton push(Word, reg(PROGCTR)); 8269678Slinton push(Word, reg(STKP)); 8279678Slinton } 8289678Slinton 8299678Slinton /* 8309678Slinton * Pop back to the real world. 8319678Slinton */ 8329678Slinton 8339678Slinton public popenv() 8349678Slinton { 8359678Slinton register String filename; 8369678Slinton 8379678Slinton setreg(STKP, pop(Word)); 8389678Slinton setreg(PROGCTR, pop(Word)); 839*16618Ssam curframerec = pop(struct Frame); 840*16618Ssam curframe = pop(Frame); 8419678Slinton curfunc = pop(Symbol); 8429678Slinton isstopped = pop(Boolean); 8439678Slinton filename = pop(String); 8449678Slinton curline = pop(Lineno); 8459678Slinton pc = pop(Address); 8469678Slinton setsource(filename); 8479678Slinton } 8489678Slinton 8499678Slinton /* 8509678Slinton * Flush the debuggee's standard output. 8519678Slinton * 8529678Slinton * This is VERY dependent on the use of stdio. 8539678Slinton */ 8549678Slinton 8559678Slinton public flushoutput() 8569678Slinton { 8579678Slinton register Symbol p, iob; 8589678Slinton register Stack *savesp; 8599678Slinton 8609678Slinton p = lookup(identname("fflush", true)); 8619678Slinton while (p != nil and not isblock(p)) { 8629678Slinton p = p->next_sym; 8639678Slinton } 8649678Slinton if (p != nil) { 8659678Slinton iob = lookup(identname("_iob", true)); 8669678Slinton if (iob != nil) { 8679678Slinton pushenv(); 8689678Slinton pc = codeloc(p); 8699678Slinton savesp = sp; 8709678Slinton push(long, address(iob, nil) + sizeof(struct _iobuf)); 8719678Slinton setreg(STKP, reg(STKP) - sizeof(long)); 8729678Slinton dwrite(savesp, reg(STKP), sizeof(long)); 8739678Slinton sp = savesp; 8749678Slinton beginproc(p, 1); 8759678Slinton stepto(return_addr()); 8769678Slinton popenv(); 8779678Slinton } 8789678Slinton } 8799678Slinton } 880