1*12546Scsvaf 29678Slinton /* Copyright (c) 1982 Regents of the University of California */ 39678Slinton 4*12546Scsvaf static char sccsid[] = "@(#)runtime.c 1.6 05/18/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" 22*12546Scsvaf #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; 76*12546Scsvaf Address prev_frame, callpc; 77*12546Scsvaf private Integer ntramp=0; 789678Slinton 799678Slinton newfrp = frp; 80*12546Scsvaf prev_frame = frp->save_fp; 81*12546Scsvaf 82*12546Scsvaf /* The check for interrupt generated frames is taken from adb with only 83*12546Scsvaf * partial understanding : say you're in sub and on a sigxxx siggsub 84*12546Scsvaf * gets control and dies; the stack does NOT look like main, sub, sigsub. 85*12546Scsvaf * 86*12546Scsvaf * As best I can make out it looks like: 87*12546Scsvaf * main (machine check exception block + sub) sysframe sigsub. 88*12546Scsvaf * ie when the sig occurs push an exception block on the user stack 89*12546Scsvaf * and a frame for the routine in which it occured then push another 90*12546Scsvaf * frame corresponding to a call from the kernel to sigsub. 91*12546Scsvaf * 92*12546Scsvaf * The addr in sub at which the exception occured is not in sub.save_pc 93*12546Scsvaf * but in the machine check exception block. It can be referenced as 94*12546Scsvaf * sub.save_reg[11]. 95*12546Scsvaf * 96*12546Scsvaf * The current approach ignores the sys_frame (what adb reports as sigtramp) 97*12546Scsvaf * and takes the pc for sub from the exception block. This 98*12546Scsvaf * allows where to report: main sub sigsub, which seems reasonable 99*12546Scsvaf */ 100*12546Scsvaf nextf: dread(&frame, prev_frame , sizeof(struct Frame)); 101*12546Scsvaf if(ntramp == 1 ) callpc = (Address) frame.save_reg[11]; 102*12546Scsvaf else callpc=frame.save_pc; 103*12546Scsvaf 1049678Slinton if (frame.save_fp == nil) { 1059678Slinton newfrp = nil; 106*12546Scsvaf } 107*12546Scsvaf else if (callpc > 0x80000000 - 0x200 * UPAGES ) { 108*12546Scsvaf ntramp++; 109*12546Scsvaf prev_frame = frame.save_fp; 110*12546Scsvaf goto nextf; 111*12546Scsvaf } 112*12546Scsvaf else { 113*12546Scsvaf frame.save_pc = callpc; 114*12546Scsvaf ntramp=0; 1159678Slinton mask = ((frame.mask >> 16) & 0x0fff); 1169678Slinton j = 0; 1179678Slinton for (i = 0; i < NSAVEREG; i++) { 1189678Slinton if (bis(mask, i)) { 1199678Slinton newfrp->save_reg[i] = frame.save_reg[j]; 1209678Slinton ++j; 1219678Slinton } 1229678Slinton } 1239678Slinton newfrp->condition_handler = frame.condition_handler; 1249678Slinton newfrp->mask = mask; 1259678Slinton newfrp->save_ap = frame.save_ap; 1269678Slinton newfrp->save_fp = frame.save_fp; 1279678Slinton newfrp->save_pc = frame.save_pc; 1289678Slinton } 1299678Slinton return newfrp; 1309678Slinton } 1319678Slinton 1329678Slinton /* 1339678Slinton * Return the frame associated with the given function. 1349678Slinton * If the function is nil, return the most recently activated frame. 1359678Slinton * 1369678Slinton * Static allocation for the frame. 1379678Slinton */ 1389678Slinton 1399678Slinton public Frame findframe(f) 1409678Slinton Symbol f; 1419678Slinton { 1429678Slinton register Frame frp; 1439678Slinton static struct Frame frame; 14411866Slinton Symbol p; 14511866Slinton Boolean done; 1469678Slinton 1479678Slinton frp = &frame; 1489678Slinton getcurframe(frp); 1499678Slinton if (f != nil) { 15011866Slinton done = false; 15111866Slinton do { 15211866Slinton p = whatblock(frp->save_pc); 15311866Slinton if (p == f) { 15411866Slinton done = true; 15511866Slinton } else if (p == program) { 15611866Slinton done = true; 15711866Slinton frp = nil; 15811866Slinton } else { 15911866Slinton frp = nextframe(frp); 16011866Slinton if (frp == nil) { 16111866Slinton done = true; 16211866Slinton } 16311866Slinton } 16411866Slinton } while (not done); 1659678Slinton } 1669678Slinton return frp; 1679678Slinton } 1689678Slinton 1699678Slinton /* 1709678Slinton * Find the return address of the current procedure/function. 1719678Slinton */ 1729678Slinton 1739678Slinton public Address return_addr() 1749678Slinton { 1759678Slinton Frame frp; 1769678Slinton Address addr; 1779678Slinton struct Frame frame; 1789678Slinton 1799678Slinton frp = &frame; 1809678Slinton getcurframe(frp); 1819678Slinton frp = nextframe(frp); 1829678Slinton if (frp == nil) { 1839678Slinton addr = 0; 1849678Slinton } else { 1859678Slinton addr = frp->save_pc; 1869678Slinton } 1879678Slinton return addr; 1889678Slinton } 1899678Slinton 1909678Slinton /* 1919678Slinton * Push the value associated with the current function. 1929678Slinton */ 1939678Slinton 1949678Slinton public pushretval(len, isindirect) 1959678Slinton Integer len; 1969678Slinton Boolean isindirect; 1979678Slinton { 1989678Slinton Word r0; 1999678Slinton 2009678Slinton r0 = reg(0); 2019678Slinton if (isindirect) { 2029678Slinton rpush((Address) r0, len); 2039678Slinton } else { 2049678Slinton switch (len) { 2059678Slinton case sizeof(char): 2069678Slinton push(char, r0); 2079678Slinton break; 2089678Slinton 2099678Slinton case sizeof(short): 2109678Slinton push(short, r0); 2119678Slinton break; 2129678Slinton 2139678Slinton default: 2149678Slinton if (len == sizeof(Word)) { 2159678Slinton push(Word, r0); 2169678Slinton } else if (len == 2*sizeof(Word)) { 2179678Slinton push(Word, r0); 2189678Slinton push(Word, reg(1)); 2199678Slinton } else { 2209678Slinton panic("not indirect in pushretval?"); 2219678Slinton } 2229678Slinton break; 2239678Slinton } 2249678Slinton } 2259678Slinton } 2269678Slinton 2279678Slinton /* 2289678Slinton * Return the base address for locals in the given frame. 2299678Slinton */ 2309678Slinton 2319678Slinton public Address locals_base(frp) 2329678Slinton register Frame frp; 2339678Slinton { 2349678Slinton return (frp == nil) ? reg(FRP) : frp->save_fp; 2359678Slinton } 2369678Slinton 2379678Slinton /* 2389678Slinton * Return the base address for arguments in the given frame. 2399678Slinton */ 2409678Slinton 2419678Slinton public Address args_base(frp) 2429678Slinton register Frame frp; 2439678Slinton { 2449678Slinton return (frp == nil) ? reg(ARGP) : frp->save_ap; 2459678Slinton } 2469678Slinton 2479678Slinton /* 2489678Slinton * Return saved register n from the given frame. 2499678Slinton */ 2509678Slinton 2519678Slinton public Word savereg(n, frp) 2529678Slinton register Integer n; 2539678Slinton register Frame frp; 2549678Slinton { 2559678Slinton register Word w; 2569678Slinton 2579678Slinton if (frp == nil) { 2589678Slinton w = reg(n); 2599678Slinton } else { 2609678Slinton switch (n) { 2619678Slinton case ARGP: 2629678Slinton w = frp->save_ap; 2639678Slinton break; 2649678Slinton 2659678Slinton case FRP: 2669678Slinton w = frp->save_fp; 2679678Slinton break; 2689678Slinton 2699678Slinton case STKP: 2709678Slinton w = reg(STKP); 2719678Slinton break; 2729678Slinton 2739678Slinton case PROGCTR: 2749678Slinton w = frp->save_pc; 2759678Slinton break; 2769678Slinton 2779678Slinton default: 2789678Slinton assert(n >= 0 and n < NSAVEREG); 2799678Slinton w = frp->save_reg[n]; 2809678Slinton break; 2819678Slinton } 2829678Slinton } 2839678Slinton return w; 2849678Slinton } 2859678Slinton 2869678Slinton /* 2879678Slinton * Return the nth argument to the current procedure. 2889678Slinton */ 2899678Slinton 2909678Slinton public Word argn(n, frp) 2919678Slinton Integer n; 2929678Slinton Frame frp; 2939678Slinton { 2949678Slinton Word w; 2959678Slinton 2969678Slinton dread(&w, args_base(frp) + (n * sizeof(Word)), sizeof(w)); 2979678Slinton return w; 2989678Slinton } 2999678Slinton 3009678Slinton /* 3019678Slinton * Calculate the entry address for a procedure or function parameter, 3029678Slinton * given the address of the descriptor. 3039678Slinton */ 3049678Slinton 3059678Slinton public Address fparamaddr(a) 3069678Slinton Address a; 3079678Slinton { 3089678Slinton Address r; 3099678Slinton 3109678Slinton dread(&r, a, sizeof(r)); 3119678Slinton return r; 3129678Slinton } 3139678Slinton 3149678Slinton /* 3159678Slinton * Print a list of currently active blocks starting with most recent. 3169678Slinton */ 3179678Slinton 3189678Slinton public wherecmd() 3199678Slinton { 3209678Slinton walkstack(false); 3219678Slinton } 3229678Slinton 3239678Slinton /* 3249678Slinton * Dump the world to the given file. 3259678Slinton * Like "where", but variables are dumped also. 3269678Slinton */ 3279678Slinton 3289678Slinton public dump() 3299678Slinton { 3309678Slinton walkstack(true); 3319678Slinton } 3329678Slinton 3339678Slinton /* 3349678Slinton * Walk the stack of active procedures printing information 3359678Slinton * about each active procedure. 3369678Slinton */ 3379678Slinton 3389678Slinton private walkstack(dumpvariables) 3399678Slinton Boolean dumpvariables; 3409678Slinton { 3419678Slinton register Frame frp; 3429678Slinton register Symbol f; 3439678Slinton register Boolean save; 3449678Slinton register Lineno line; 3459678Slinton struct Frame frame; 3469678Slinton 3479678Slinton if (notstarted(process)) { 3489678Slinton error("program is not active"); 3499678Slinton } else { 3509678Slinton save = walkingstack; 3519678Slinton walkingstack = true; 3529678Slinton frp = &frame; 3539678Slinton getcurframe(frp); 3549678Slinton f = whatblock(frp->save_pc); 3559678Slinton do { 3569678Slinton printf("%s", symname(f)); 3579678Slinton printparams(f, frp); 3589841Slinton line = srcline(frp->save_pc - 1); 3599678Slinton if (line != 0) { 3609678Slinton printf(", line %d", line); 3619841Slinton printf(" in \"%s\"\n", srcfilename(frp->save_pc - 1)); 3629678Slinton } else { 3639678Slinton printf(" at 0x%x\n", frp->save_pc); 3649678Slinton } 3659678Slinton if (dumpvariables) { 3669678Slinton dumpvars(f, frp); 3679678Slinton putchar('\n'); 3689678Slinton } 3699678Slinton frp = nextframe(frp); 3709678Slinton if (frp != nil) { 3719678Slinton f = whatblock(frp->save_pc); 3729678Slinton } 37311866Slinton } while (frp != nil and f != program); 3749678Slinton if (dumpvariables) { 3759678Slinton printf("in \"%s\":\n", symname(program)); 3769678Slinton dumpvars(program, nil); 3779678Slinton putchar('\n'); 3789678Slinton } 3799678Slinton walkingstack = save; 3809678Slinton } 3819678Slinton } 3829678Slinton 3839678Slinton /* 3849678Slinton * Find the entry point of a procedure or function. 3859678Slinton */ 3869678Slinton 3879678Slinton public findbeginning(f) 3889678Slinton Symbol f; 3899678Slinton { 3909678Slinton f->symvalue.funcv.beginaddr += 2; 3919678Slinton } 3929678Slinton 3939678Slinton /* 3949678Slinton * Return the address corresponding to the first line in a function. 3959678Slinton */ 3969678Slinton 3979678Slinton public Address firstline(f) 3989678Slinton Symbol f; 3999678Slinton { 4009678Slinton Address addr; 4019678Slinton 4029678Slinton addr = codeloc(f); 4039678Slinton while (linelookup(addr) == 0 and addr < objsize) { 4049678Slinton ++addr; 4059678Slinton } 4069678Slinton if (addr == objsize) { 4079678Slinton addr = -1; 4089678Slinton } 4099678Slinton return addr; 4109678Slinton } 4119678Slinton 4129678Slinton /* 4139678Slinton * Catcher drops strike three ... 4149678Slinton */ 4159678Slinton 4169678Slinton public runtofirst() 4179678Slinton { 4189678Slinton Address addr; 4199678Slinton 4209678Slinton addr = pc; 4219678Slinton while (linelookup(addr) == 0 and addr < objsize) { 4229678Slinton ++addr; 4239678Slinton } 4249678Slinton if (addr < objsize) { 4259678Slinton stepto(addr); 4269678Slinton } 4279678Slinton } 4289678Slinton 4299678Slinton /* 4309678Slinton * Return the address corresponding to the end of the program. 4319678Slinton * 4329678Slinton * We look for the entry to "exit". 4339678Slinton */ 4349678Slinton 4359678Slinton public Address lastaddr() 4369678Slinton { 4379678Slinton register Symbol s; 4389678Slinton 4399678Slinton s = lookup(identname("exit", true)); 4409678Slinton if (s == nil) { 4419678Slinton panic("can't find exit"); 4429678Slinton } 4439678Slinton return codeloc(s); 4449678Slinton } 4459678Slinton 4469678Slinton /* 4479678Slinton * Decide if the given function is currently active. 4489678Slinton * 4499678Slinton * We avoid calls to "findframe" during a stack trace for efficiency. 4509678Slinton * Presumably information evaluated while walking the stack is active. 4519678Slinton */ 4529678Slinton 4539678Slinton public Boolean isactive(f) 4549678Slinton Symbol f; 4559678Slinton { 4569678Slinton register Boolean b; 4579678Slinton 4589678Slinton if (isfinished(process)) { 4599678Slinton b = false; 4609678Slinton } else { 4619678Slinton if (walkingstack or f == program or 4629678Slinton (ismodule(f) and isactive(container(f)))) { 4639678Slinton b = true; 4649678Slinton } else { 4659678Slinton b = (Boolean) (findframe(f) != nil); 4669678Slinton } 4679678Slinton } 4689678Slinton return b; 4699678Slinton } 4709678Slinton 4719678Slinton /* 4729678Slinton * Evaluate a call to a procedure. 4739678Slinton */ 4749678Slinton 4759678Slinton public callproc(procnode, arglist) 4769678Slinton Node procnode; 4779678Slinton Node arglist; 4789678Slinton { 4799678Slinton Symbol proc; 4809678Slinton Integer argc; 4819678Slinton 4829678Slinton if (procnode->op != O_SYM) { 4839678Slinton beginerrmsg(); 4849678Slinton fprintf(stderr, "can't call \""); 4859678Slinton prtree(stderr, procnode); 4869678Slinton fprintf(stderr, "\""); 4879678Slinton enderrmsg(); 4889678Slinton } 4899678Slinton assert(procnode->op == O_SYM); 4909678Slinton proc = procnode->value.sym; 4919678Slinton if (not isblock(proc)) { 4929678Slinton error("\"%s\" is not a procedure or function", symname(proc)); 4939678Slinton } 4949678Slinton pushenv(); 4959678Slinton pc = codeloc(proc); 4969678Slinton argc = pushargs(proc, arglist); 4979678Slinton beginproc(proc, argc); 4989678Slinton isstopped = true; 4999678Slinton event_once(build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)), 5009678Slinton buildcmdlist(build(O_PROCRTN, proc))); 5019678Slinton cont(); 5029678Slinton /* NOTREACHED */ 5039678Slinton } 5049678Slinton 5059678Slinton /* 5069678Slinton * Push the arguments on the process' stack. We do this by first 5079678Slinton * evaluating them on the "eval" stack, then copying into the process' 5089678Slinton * space. 5099678Slinton */ 5109678Slinton 5119678Slinton private Integer pushargs(proc, arglist) 5129678Slinton Symbol proc; 5139678Slinton Node arglist; 5149678Slinton { 5159678Slinton Stack *savesp; 5169678Slinton int argc, args_size; 5179678Slinton 5189678Slinton savesp = sp; 5199678Slinton argc = evalargs(proc, arglist); 5209678Slinton args_size = sp - savesp; 5219678Slinton setreg(STKP, reg(STKP) - args_size); 5229678Slinton dwrite(savesp, reg(STKP), args_size); 5239678Slinton sp = savesp; 5249678Slinton return argc; 5259678Slinton } 5269678Slinton 5279678Slinton /* 5289678Slinton * Evaluate arguments left-to-right. 5299678Slinton */ 5309678Slinton 5319678Slinton private Integer evalargs(proc, arglist) 5329678Slinton Symbol proc; 5339678Slinton Node arglist; 5349678Slinton { 5359678Slinton Node p, exp; 5369678Slinton Symbol arg; 5379678Slinton Stack *savesp; 5389678Slinton Address addr; 5399678Slinton Integer count; 5409678Slinton 5419678Slinton savesp = sp; 5429678Slinton count = 0; 5439678Slinton arg = proc->chain; 5449678Slinton for (p = arglist; p != nil; p = p->value.arg[1]) { 5459678Slinton if (p->op != O_COMMA) { 5469678Slinton panic("evalargs: arglist missing comma"); 5479678Slinton } 5489678Slinton if (arg == nil) { 5499678Slinton sp = savesp; 5509678Slinton error("too many parameters to %s", symname(proc)); 5519678Slinton } 5529678Slinton exp = p->value.arg[0]; 5539678Slinton if (not compatible(arg->type, exp->nodetype)) { 5549678Slinton sp = savesp; 5559678Slinton error("expression for parameter %s is of wrong type", symname(arg)); 5569678Slinton } 5579678Slinton if (arg->class == REF) { 5589678Slinton if (exp->op != O_RVAL) { 5599678Slinton sp = savesp; 5609678Slinton error("variable expected for parameter \"%s\"", symname(arg)); 5619678Slinton } 5629678Slinton addr = lval(exp->value.arg[0]); 5639678Slinton push(Address, addr); 5649678Slinton } else { 5659678Slinton eval(exp); 5669678Slinton } 5679678Slinton arg = arg->chain; 5689678Slinton ++count; 5699678Slinton } 5709678Slinton if (arg != nil) { 5719678Slinton sp = savesp; 5729678Slinton error("not enough parameters to %s", symname(proc)); 5739678Slinton } 5749678Slinton return count; 5759678Slinton } 5769678Slinton 5779678Slinton public procreturn(f) 5789678Slinton Symbol f; 5799678Slinton { 5809678Slinton flushoutput(); 5819678Slinton putchar('\n'); 5829678Slinton printname(stdout, f); 5839678Slinton printf(" returns successfully\n", symname(f)); 5849678Slinton popenv(); 5859678Slinton erecover(); 5869678Slinton } 5879678Slinton 5889678Slinton /* 5899678Slinton * Push the current environment. 5909678Slinton */ 5919678Slinton 5929678Slinton private pushenv() 5939678Slinton { 5949678Slinton push(Address, pc); 5959678Slinton push(Lineno, curline); 5969678Slinton push(String, cursource); 5979678Slinton push(Boolean, isstopped); 5989678Slinton push(Symbol, curfunc); 5999678Slinton push(Word, reg(PROGCTR)); 6009678Slinton push(Word, reg(STKP)); 6019678Slinton } 6029678Slinton 6039678Slinton /* 6049678Slinton * Pop back to the real world. 6059678Slinton */ 6069678Slinton 6079678Slinton public popenv() 6089678Slinton { 6099678Slinton register String filename; 6109678Slinton 6119678Slinton setreg(STKP, pop(Word)); 6129678Slinton setreg(PROGCTR, pop(Word)); 6139678Slinton curfunc = pop(Symbol); 6149678Slinton isstopped = pop(Boolean); 6159678Slinton filename = pop(String); 6169678Slinton curline = pop(Lineno); 6179678Slinton pc = pop(Address); 6189678Slinton setsource(filename); 6199678Slinton } 6209678Slinton 6219678Slinton /* 6229678Slinton * Flush the debuggee's standard output. 6239678Slinton * 6249678Slinton * This is VERY dependent on the use of stdio. 6259678Slinton */ 6269678Slinton 6279678Slinton public flushoutput() 6289678Slinton { 6299678Slinton register Symbol p, iob; 6309678Slinton register Stack *savesp; 6319678Slinton 6329678Slinton p = lookup(identname("fflush", true)); 6339678Slinton while (p != nil and not isblock(p)) { 6349678Slinton p = p->next_sym; 6359678Slinton } 6369678Slinton if (p != nil) { 6379678Slinton iob = lookup(identname("_iob", true)); 6389678Slinton if (iob != nil) { 6399678Slinton pushenv(); 6409678Slinton pc = codeloc(p); 6419678Slinton savesp = sp; 6429678Slinton push(long, address(iob, nil) + sizeof(struct _iobuf)); 6439678Slinton setreg(STKP, reg(STKP) - sizeof(long)); 6449678Slinton dwrite(savesp, reg(STKP), sizeof(long)); 6459678Slinton sp = savesp; 6469678Slinton beginproc(p, 1); 6479678Slinton stepto(return_addr()); 6489678Slinton popenv(); 6499678Slinton } 6509678Slinton } 6519678Slinton } 652