112546Scsvaf 29678Slinton /* Copyright (c) 1982 Regents of the University of California */ 39678Slinton 4*15784Ssam static char sccsid[] = "@(#)runtime.c 1.10 12/30/83"; 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 419678Slinton private Boolean walkingstack = false; 429678Slinton 439678Slinton /* 449678Slinton * Set a frame to the current activation record. 459678Slinton */ 469678Slinton 479678Slinton private getcurframe(frp) 489678Slinton register Frame frp; 499678Slinton { 509678Slinton register int i; 519678Slinton 529678Slinton checkref(frp); 539678Slinton frp->mask = reg(NREG); 549678Slinton frp->save_ap = reg(ARGP); 559678Slinton frp->save_fp = reg(FRP); 5612051Slinton frp->save_pc = reg(PROGCTR) + 1; 579678Slinton for (i = 0; i < NSAVEREG; i++) { 589678Slinton frp->save_reg[i] = reg(i); 599678Slinton } 609678Slinton } 619678Slinton 629678Slinton /* 639678Slinton * Return a pointer to the next activation record up the stack. 649678Slinton * Return nil if there is none. 659678Slinton * Writes over space pointed to by given argument. 669678Slinton */ 679678Slinton 689678Slinton #define bis(b, n) ((b & (1 << (n))) != 0) 699678Slinton 709678Slinton private Frame nextframe(frp) 719678Slinton Frame frp; 729678Slinton { 739678Slinton register Frame newfrp; 749678Slinton struct Frame frame; 759678Slinton register Integer i, j, mask; 7612546Scsvaf Address prev_frame, callpc; 7713937Slinton static Integer ntramp = 0; 789678Slinton 799678Slinton newfrp = frp; 8012546Scsvaf prev_frame = frp->save_fp; 8112546Scsvaf 8213937Slinton /* 8313937Slinton * The check for interrupt generated frames is taken from adb with only 8413937Slinton * partial understanding. If you're in "sub" and on a sigxxx "sigsub" 8513937Slinton * gets control, then the stack does NOT look like <main, sub, sigsub>. 8612546Scsvaf * 8712546Scsvaf * As best I can make out it looks like: 8812546Scsvaf * 8913937Slinton * <main, (machine check exception block + sub), sysframe, sigsub>. 9013937Slinton * 9113937Slinton * When the signal occurs an exception block and a frame for the routine 9213937Slinton * in which it occured are pushed on the user stack. Then another frame 9313937Slinton * is pushed corresponding to a call from the kernel to sigsub. 9413937Slinton * 9512546Scsvaf * The addr in sub at which the exception occured is not in sub.save_pc 9613937Slinton * but in the machine check exception block. It is at the magic address 9714620Ssam * fp + 84. 9812546Scsvaf * 9912546Scsvaf * The current approach ignores the sys_frame (what adb reports as sigtramp) 10013937Slinton * and takes the pc for sub from the exception block. This allows the 10113937Slinton * "where" command to report <main, sub, sigsub>, which seems reasonable. 10212546Scsvaf */ 10312546Scsvaf 10413937Slinton nextf: 10513937Slinton dread(&frame, prev_frame, sizeof(struct Frame)); 10613937Slinton if (ntramp == 1) { 10714620Ssam dread(&callpc, prev_frame + 84, sizeof(callpc)); 10813937Slinton } else { 10913937Slinton callpc = frame.save_pc; 11013937Slinton } 1119678Slinton if (frame.save_fp == nil) { 1129678Slinton newfrp = nil; 11313937Slinton } else if (callpc > 0x80000000 - 0x200 * UPAGES ) { 11412546Scsvaf ntramp++; 11512546Scsvaf prev_frame = frame.save_fp; 11612546Scsvaf goto nextf; 11713937Slinton } else { 11812546Scsvaf frame.save_pc = callpc; 11913937Slinton ntramp = 0; 1209678Slinton mask = ((frame.mask >> 16) & 0x0fff); 1219678Slinton j = 0; 1229678Slinton for (i = 0; i < NSAVEREG; i++) { 1239678Slinton if (bis(mask, i)) { 1249678Slinton newfrp->save_reg[i] = frame.save_reg[j]; 1259678Slinton ++j; 1269678Slinton } 1279678Slinton } 1289678Slinton newfrp->condition_handler = frame.condition_handler; 1299678Slinton newfrp->mask = mask; 1309678Slinton newfrp->save_ap = frame.save_ap; 1319678Slinton newfrp->save_fp = frame.save_fp; 1329678Slinton newfrp->save_pc = frame.save_pc; 1339678Slinton } 1349678Slinton return newfrp; 1359678Slinton } 1369678Slinton 1379678Slinton /* 1389678Slinton * Return the frame associated with the given function. 1399678Slinton * If the function is nil, return the most recently activated frame. 1409678Slinton * 1419678Slinton * Static allocation for the frame. 1429678Slinton */ 1439678Slinton 1449678Slinton public Frame findframe(f) 1459678Slinton Symbol f; 1469678Slinton { 1479678Slinton register Frame frp; 1489678Slinton static struct Frame frame; 14911866Slinton Symbol p; 1509678Slinton 1519678Slinton frp = &frame; 1529678Slinton getcurframe(frp); 153*15784Ssam if (f == nil) 154*15784Ssam return (frp); 155*15784Ssam /* 156*15784Ssam * Starting at the current stack frame, 157*15784Ssam * walk backwards looking for a symbol 158*15784Ssam * match. Beware of local blocks which 159*15784Ssam * have a back pointer but no stack frame. 160*15784Ssam */ 161*15784Ssam p = whatblock(frp->save_pc); 162*15784Ssam while (p != f) { 163*15784Ssam if (p == program) { 164*15784Ssam frp = nil; 165*15784Ssam break; 166*15784Ssam } 167*15784Ssam if (isinline(p)) { 168*15784Ssam p = container(p); 169*15784Ssam continue; 170*15784Ssam } 171*15784Ssam frp = nextframe(frp); 172*15784Ssam if (frp == nil) 173*15784Ssam break; 174*15784Ssam p = whatblock(frp->save_pc); 1759678Slinton } 176*15784Ssam return (frp); 1779678Slinton } 1789678Slinton 1799678Slinton /* 1809678Slinton * Find the return address of the current procedure/function. 1819678Slinton */ 1829678Slinton 1839678Slinton public Address return_addr() 1849678Slinton { 1859678Slinton Frame frp; 1869678Slinton Address addr; 1879678Slinton struct Frame frame; 1889678Slinton 1899678Slinton frp = &frame; 1909678Slinton getcurframe(frp); 1919678Slinton frp = nextframe(frp); 1929678Slinton if (frp == nil) { 1939678Slinton addr = 0; 1949678Slinton } else { 1959678Slinton addr = frp->save_pc; 1969678Slinton } 1979678Slinton return addr; 1989678Slinton } 1999678Slinton 2009678Slinton /* 2019678Slinton * Push the value associated with the current function. 2029678Slinton */ 2039678Slinton 2049678Slinton public pushretval(len, isindirect) 2059678Slinton Integer len; 2069678Slinton Boolean isindirect; 2079678Slinton { 2089678Slinton Word r0; 2099678Slinton 2109678Slinton r0 = reg(0); 2119678Slinton if (isindirect) { 2129678Slinton rpush((Address) r0, len); 2139678Slinton } else { 2149678Slinton switch (len) { 2159678Slinton case sizeof(char): 2169678Slinton push(char, r0); 2179678Slinton break; 2189678Slinton 2199678Slinton case sizeof(short): 2209678Slinton push(short, r0); 2219678Slinton break; 2229678Slinton 2239678Slinton default: 2249678Slinton if (len == sizeof(Word)) { 2259678Slinton push(Word, r0); 2269678Slinton } else if (len == 2*sizeof(Word)) { 2279678Slinton push(Word, r0); 2289678Slinton push(Word, reg(1)); 2299678Slinton } else { 2309678Slinton panic("not indirect in pushretval?"); 2319678Slinton } 2329678Slinton break; 2339678Slinton } 2349678Slinton } 2359678Slinton } 2369678Slinton 2379678Slinton /* 2389678Slinton * Return the base address for locals in the given frame. 2399678Slinton */ 2409678Slinton 2419678Slinton public Address locals_base(frp) 2429678Slinton register Frame frp; 2439678Slinton { 2449678Slinton return (frp == nil) ? reg(FRP) : frp->save_fp; 2459678Slinton } 2469678Slinton 2479678Slinton /* 2489678Slinton * Return the base address for arguments in the given frame. 2499678Slinton */ 2509678Slinton 2519678Slinton public Address args_base(frp) 2529678Slinton register Frame frp; 2539678Slinton { 2549678Slinton return (frp == nil) ? reg(ARGP) : frp->save_ap; 2559678Slinton } 2569678Slinton 2579678Slinton /* 2589678Slinton * Return saved register n from the given frame. 2599678Slinton */ 2609678Slinton 2619678Slinton public Word savereg(n, frp) 2629678Slinton register Integer n; 2639678Slinton register Frame frp; 2649678Slinton { 2659678Slinton register Word w; 2669678Slinton 2679678Slinton if (frp == nil) { 2689678Slinton w = reg(n); 2699678Slinton } else { 2709678Slinton switch (n) { 2719678Slinton case ARGP: 2729678Slinton w = frp->save_ap; 2739678Slinton break; 2749678Slinton 2759678Slinton case FRP: 2769678Slinton w = frp->save_fp; 2779678Slinton break; 2789678Slinton 2799678Slinton case STKP: 2809678Slinton w = reg(STKP); 2819678Slinton break; 2829678Slinton 2839678Slinton case PROGCTR: 2849678Slinton w = frp->save_pc; 2859678Slinton break; 2869678Slinton 2879678Slinton default: 2889678Slinton assert(n >= 0 and n < NSAVEREG); 2899678Slinton w = frp->save_reg[n]; 2909678Slinton break; 2919678Slinton } 2929678Slinton } 2939678Slinton return w; 2949678Slinton } 2959678Slinton 2969678Slinton /* 2979678Slinton * Return the nth argument to the current procedure. 2989678Slinton */ 2999678Slinton 3009678Slinton public Word argn(n, frp) 3019678Slinton Integer n; 3029678Slinton Frame frp; 3039678Slinton { 3049678Slinton Word w; 3059678Slinton 3069678Slinton dread(&w, args_base(frp) + (n * sizeof(Word)), sizeof(w)); 3079678Slinton return w; 3089678Slinton } 3099678Slinton 3109678Slinton /* 3119678Slinton * Calculate the entry address for a procedure or function parameter, 3129678Slinton * given the address of the descriptor. 3139678Slinton */ 3149678Slinton 3159678Slinton public Address fparamaddr(a) 3169678Slinton Address a; 3179678Slinton { 3189678Slinton Address r; 3199678Slinton 3209678Slinton dread(&r, a, sizeof(r)); 3219678Slinton return r; 3229678Slinton } 3239678Slinton 3249678Slinton /* 3259678Slinton * Print a list of currently active blocks starting with most recent. 3269678Slinton */ 3279678Slinton 3289678Slinton public wherecmd() 3299678Slinton { 3309678Slinton walkstack(false); 3319678Slinton } 3329678Slinton 3339678Slinton /* 3349678Slinton * Dump the world to the given file. 3359678Slinton * Like "where", but variables are dumped also. 3369678Slinton */ 3379678Slinton 3389678Slinton public dump() 3399678Slinton { 3409678Slinton walkstack(true); 3419678Slinton } 3429678Slinton 3439678Slinton /* 3449678Slinton * Walk the stack of active procedures printing information 3459678Slinton * about each active procedure. 3469678Slinton */ 3479678Slinton 3489678Slinton private walkstack(dumpvariables) 3499678Slinton Boolean dumpvariables; 3509678Slinton { 3519678Slinton register Frame frp; 3529678Slinton register Symbol f; 3539678Slinton register Boolean save; 3549678Slinton register Lineno line; 3559678Slinton struct Frame frame; 3569678Slinton 3579678Slinton if (notstarted(process)) { 3589678Slinton error("program is not active"); 3599678Slinton } else { 3609678Slinton save = walkingstack; 3619678Slinton walkingstack = true; 3629678Slinton frp = &frame; 3639678Slinton getcurframe(frp); 3649678Slinton f = whatblock(frp->save_pc); 3659678Slinton do { 3669678Slinton printf("%s", symname(f)); 36714442Slinton if (not isinline(f)) { 36814442Slinton printparams(f, frp); 36914442Slinton } 3709841Slinton line = srcline(frp->save_pc - 1); 3719678Slinton if (line != 0) { 3729678Slinton printf(", line %d", line); 3739841Slinton printf(" in \"%s\"\n", srcfilename(frp->save_pc - 1)); 3749678Slinton } else { 3759678Slinton printf(" at 0x%x\n", frp->save_pc); 3769678Slinton } 3779678Slinton if (dumpvariables) { 3789678Slinton dumpvars(f, frp); 3799678Slinton putchar('\n'); 3809678Slinton } 38114442Slinton if (isinline(f)) { 38214442Slinton f = container(f); 38314442Slinton } else { 38414442Slinton frp = nextframe(frp); 38514442Slinton if (frp != nil) { 38614442Slinton f = whatblock(frp->save_pc); 38714442Slinton } 3889678Slinton } 38911866Slinton } while (frp != nil and f != program); 3909678Slinton if (dumpvariables) { 3919678Slinton printf("in \"%s\":\n", symname(program)); 3929678Slinton dumpvars(program, nil); 3939678Slinton putchar('\n'); 3949678Slinton } 3959678Slinton walkingstack = save; 3969678Slinton } 3979678Slinton } 3989678Slinton 3999678Slinton /* 4009678Slinton * Find the entry point of a procedure or function. 4019678Slinton */ 4029678Slinton 4039678Slinton public findbeginning(f) 4049678Slinton Symbol f; 4059678Slinton { 4069678Slinton f->symvalue.funcv.beginaddr += 2; 4079678Slinton } 4089678Slinton 4099678Slinton /* 4109678Slinton * Return the address corresponding to the first line in a function. 4119678Slinton */ 4129678Slinton 4139678Slinton public Address firstline(f) 4149678Slinton Symbol f; 4159678Slinton { 4169678Slinton Address addr; 4179678Slinton 4189678Slinton addr = codeloc(f); 4199678Slinton while (linelookup(addr) == 0 and addr < objsize) { 4209678Slinton ++addr; 4219678Slinton } 4229678Slinton if (addr == objsize) { 4239678Slinton addr = -1; 4249678Slinton } 4259678Slinton return addr; 4269678Slinton } 4279678Slinton 4289678Slinton /* 4299678Slinton * Catcher drops strike three ... 4309678Slinton */ 4319678Slinton 4329678Slinton public runtofirst() 4339678Slinton { 4349678Slinton Address addr; 4359678Slinton 4369678Slinton addr = pc; 4379678Slinton while (linelookup(addr) == 0 and addr < objsize) { 4389678Slinton ++addr; 4399678Slinton } 4409678Slinton if (addr < objsize) { 4419678Slinton stepto(addr); 4429678Slinton } 4439678Slinton } 4449678Slinton 4459678Slinton /* 4469678Slinton * Return the address corresponding to the end of the program. 4479678Slinton * 4489678Slinton * We look for the entry to "exit". 4499678Slinton */ 4509678Slinton 4519678Slinton public Address lastaddr() 4529678Slinton { 4539678Slinton register Symbol s; 4549678Slinton 4559678Slinton s = lookup(identname("exit", true)); 4569678Slinton if (s == nil) { 4579678Slinton panic("can't find exit"); 4589678Slinton } 4599678Slinton return codeloc(s); 4609678Slinton } 4619678Slinton 4629678Slinton /* 4639678Slinton * Decide if the given function is currently active. 4649678Slinton * 4659678Slinton * We avoid calls to "findframe" during a stack trace for efficiency. 4669678Slinton * Presumably information evaluated while walking the stack is active. 4679678Slinton */ 4689678Slinton 4699678Slinton public Boolean isactive(f) 4709678Slinton Symbol f; 4719678Slinton { 4729678Slinton register Boolean b; 4739678Slinton 4749678Slinton if (isfinished(process)) { 4759678Slinton b = false; 4769678Slinton } else { 4779678Slinton if (walkingstack or f == program or 4789678Slinton (ismodule(f) and isactive(container(f)))) { 4799678Slinton b = true; 4809678Slinton } else { 4819678Slinton b = (Boolean) (findframe(f) != nil); 4829678Slinton } 4839678Slinton } 4849678Slinton return b; 4859678Slinton } 4869678Slinton 4879678Slinton /* 4889678Slinton * Evaluate a call to a procedure. 4899678Slinton */ 4909678Slinton 4919678Slinton public callproc(procnode, arglist) 4929678Slinton Node procnode; 4939678Slinton Node arglist; 4949678Slinton { 4959678Slinton Symbol proc; 4969678Slinton Integer argc; 4979678Slinton 4989678Slinton if (procnode->op != O_SYM) { 4999678Slinton beginerrmsg(); 5009678Slinton fprintf(stderr, "can't call \""); 5019678Slinton prtree(stderr, procnode); 5029678Slinton fprintf(stderr, "\""); 5039678Slinton enderrmsg(); 5049678Slinton } 5059678Slinton assert(procnode->op == O_SYM); 5069678Slinton proc = procnode->value.sym; 5079678Slinton if (not isblock(proc)) { 5089678Slinton error("\"%s\" is not a procedure or function", symname(proc)); 5099678Slinton } 5109678Slinton pushenv(); 5119678Slinton pc = codeloc(proc); 5129678Slinton argc = pushargs(proc, arglist); 5139678Slinton beginproc(proc, argc); 5149678Slinton isstopped = true; 5159678Slinton event_once(build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)), 5169678Slinton buildcmdlist(build(O_PROCRTN, proc))); 5179678Slinton cont(); 5189678Slinton /* NOTREACHED */ 5199678Slinton } 5209678Slinton 5219678Slinton /* 5229678Slinton * Push the arguments on the process' stack. We do this by first 5239678Slinton * evaluating them on the "eval" stack, then copying into the process' 5249678Slinton * space. 5259678Slinton */ 5269678Slinton 5279678Slinton private Integer pushargs(proc, arglist) 5289678Slinton Symbol proc; 5299678Slinton Node arglist; 5309678Slinton { 5319678Slinton Stack *savesp; 5329678Slinton int argc, args_size; 5339678Slinton 5349678Slinton savesp = sp; 5359678Slinton argc = evalargs(proc, arglist); 5369678Slinton args_size = sp - savesp; 5379678Slinton setreg(STKP, reg(STKP) - args_size); 5389678Slinton dwrite(savesp, reg(STKP), args_size); 5399678Slinton sp = savesp; 5409678Slinton return argc; 5419678Slinton } 5429678Slinton 5439678Slinton /* 5449678Slinton * Evaluate arguments left-to-right. 5459678Slinton */ 5469678Slinton 5479678Slinton private Integer evalargs(proc, arglist) 5489678Slinton Symbol proc; 5499678Slinton Node arglist; 5509678Slinton { 5519678Slinton Node p, exp; 5529678Slinton Symbol arg; 5539678Slinton Stack *savesp; 5549678Slinton Address addr; 5559678Slinton Integer count; 5569678Slinton 5579678Slinton savesp = sp; 5589678Slinton count = 0; 5599678Slinton arg = proc->chain; 5609678Slinton for (p = arglist; p != nil; p = p->value.arg[1]) { 5619678Slinton if (p->op != O_COMMA) { 5629678Slinton panic("evalargs: arglist missing comma"); 5639678Slinton } 5649678Slinton if (arg == nil) { 5659678Slinton sp = savesp; 5669678Slinton error("too many parameters to %s", symname(proc)); 5679678Slinton } 5689678Slinton exp = p->value.arg[0]; 5699678Slinton if (not compatible(arg->type, exp->nodetype)) { 5709678Slinton sp = savesp; 5719678Slinton error("expression for parameter %s is of wrong type", symname(arg)); 5729678Slinton } 5739678Slinton if (arg->class == REF) { 5749678Slinton if (exp->op != O_RVAL) { 5759678Slinton sp = savesp; 5769678Slinton error("variable expected for parameter \"%s\"", symname(arg)); 5779678Slinton } 5789678Slinton addr = lval(exp->value.arg[0]); 5799678Slinton push(Address, addr); 5809678Slinton } else { 5819678Slinton eval(exp); 5829678Slinton } 5839678Slinton arg = arg->chain; 5849678Slinton ++count; 5859678Slinton } 5869678Slinton if (arg != nil) { 5879678Slinton sp = savesp; 5889678Slinton error("not enough parameters to %s", symname(proc)); 5899678Slinton } 5909678Slinton return count; 5919678Slinton } 5929678Slinton 5939678Slinton public procreturn(f) 5949678Slinton Symbol f; 5959678Slinton { 5969678Slinton flushoutput(); 5979678Slinton putchar('\n'); 5989678Slinton printname(stdout, f); 5999678Slinton printf(" returns successfully\n", symname(f)); 6009678Slinton popenv(); 6019678Slinton erecover(); 6029678Slinton } 6039678Slinton 6049678Slinton /* 6059678Slinton * Push the current environment. 6069678Slinton */ 6079678Slinton 6089678Slinton private pushenv() 6099678Slinton { 6109678Slinton push(Address, pc); 6119678Slinton push(Lineno, curline); 6129678Slinton push(String, cursource); 6139678Slinton push(Boolean, isstopped); 6149678Slinton push(Symbol, curfunc); 6159678Slinton push(Word, reg(PROGCTR)); 6169678Slinton push(Word, reg(STKP)); 6179678Slinton } 6189678Slinton 6199678Slinton /* 6209678Slinton * Pop back to the real world. 6219678Slinton */ 6229678Slinton 6239678Slinton public popenv() 6249678Slinton { 6259678Slinton register String filename; 6269678Slinton 6279678Slinton setreg(STKP, pop(Word)); 6289678Slinton setreg(PROGCTR, pop(Word)); 6299678Slinton curfunc = pop(Symbol); 6309678Slinton isstopped = pop(Boolean); 6319678Slinton filename = pop(String); 6329678Slinton curline = pop(Lineno); 6339678Slinton pc = pop(Address); 6349678Slinton setsource(filename); 6359678Slinton } 6369678Slinton 6379678Slinton /* 6389678Slinton * Flush the debuggee's standard output. 6399678Slinton * 6409678Slinton * This is VERY dependent on the use of stdio. 6419678Slinton */ 6429678Slinton 6439678Slinton public flushoutput() 6449678Slinton { 6459678Slinton register Symbol p, iob; 6469678Slinton register Stack *savesp; 6479678Slinton 6489678Slinton p = lookup(identname("fflush", true)); 6499678Slinton while (p != nil and not isblock(p)) { 6509678Slinton p = p->next_sym; 6519678Slinton } 6529678Slinton if (p != nil) { 6539678Slinton iob = lookup(identname("_iob", true)); 6549678Slinton if (iob != nil) { 6559678Slinton pushenv(); 6569678Slinton pc = codeloc(p); 6579678Slinton savesp = sp; 6589678Slinton push(long, address(iob, nil) + sizeof(struct _iobuf)); 6599678Slinton setreg(STKP, reg(STKP) - sizeof(long)); 6609678Slinton dwrite(savesp, reg(STKP), sizeof(long)); 6619678Slinton sp = savesp; 6629678Slinton beginproc(p, 1); 6639678Slinton stepto(return_addr()); 6649678Slinton popenv(); 6659678Slinton } 6669678Slinton } 6679678Slinton } 668