19678Slinton /* Copyright (c) 1982 Regents of the University of California */ 29678Slinton 3*11866Slinton static char sccsid[] = "@(#)runtime.c 1.4 04/08/83"; 49678Slinton 59678Slinton /* 69678Slinton * Runtime organization dependent routines, mostly dealing with 79678Slinton * activation records. 89678Slinton */ 99678Slinton 109678Slinton #include "defs.h" 119678Slinton #include "runtime.h" 129678Slinton #include "process.h" 139678Slinton #include "machine.h" 149678Slinton #include "events.h" 159678Slinton #include "mappings.h" 169678Slinton #include "symbols.h" 179678Slinton #include "tree.h" 189678Slinton #include "eval.h" 199678Slinton #include "operators.h" 209678Slinton #include "object.h" 219678Slinton 229678Slinton #ifndef public 239678Slinton typedef struct Frame *Frame; 249678Slinton 259678Slinton #include "machine.h" 269678Slinton #endif 279678Slinton 289678Slinton #define NSAVEREG 12 299678Slinton 309678Slinton struct Frame { 319678Slinton Integer condition_handler; 329678Slinton Integer mask; 339678Slinton Address save_ap; /* argument pointer */ 349678Slinton Address save_fp; /* frame pointer */ 359678Slinton Address save_pc; /* program counter */ 369678Slinton Word save_reg[NSAVEREG]; /* not necessarily there */ 379678Slinton }; 389678Slinton 399678Slinton private Boolean walkingstack = false; 409678Slinton 419678Slinton /* 429678Slinton * Set a frame to the current activation record. 439678Slinton */ 449678Slinton 459678Slinton private getcurframe(frp) 469678Slinton register Frame frp; 479678Slinton { 489678Slinton register int i; 499678Slinton 509678Slinton checkref(frp); 519678Slinton frp->mask = reg(NREG); 529678Slinton frp->save_ap = reg(ARGP); 539678Slinton frp->save_fp = reg(FRP); 549678Slinton frp->save_pc = reg(PROGCTR); 559678Slinton for (i = 0; i < NSAVEREG; i++) { 569678Slinton frp->save_reg[i] = reg(i); 579678Slinton } 589678Slinton } 599678Slinton 609678Slinton /* 619678Slinton * Return a pointer to the next activation record up the stack. 629678Slinton * Return nil if there is none. 639678Slinton * Writes over space pointed to by given argument. 649678Slinton */ 659678Slinton 669678Slinton #define bis(b, n) ((b & (1 << (n))) != 0) 679678Slinton 689678Slinton private Frame nextframe(frp) 699678Slinton Frame frp; 709678Slinton { 719678Slinton register Frame newfrp; 729678Slinton struct Frame frame; 739678Slinton register Integer i, j, mask; 749678Slinton 759678Slinton newfrp = frp; 769678Slinton dread(&frame, newfrp->save_fp, sizeof(struct Frame)); 779678Slinton if (frame.save_fp == nil) { 789678Slinton newfrp = nil; 799678Slinton } else { 809678Slinton mask = ((frame.mask >> 16) & 0x0fff); 819678Slinton j = 0; 829678Slinton for (i = 0; i < NSAVEREG; i++) { 839678Slinton if (bis(mask, i)) { 849678Slinton newfrp->save_reg[i] = frame.save_reg[j]; 859678Slinton ++j; 869678Slinton } 879678Slinton } 889678Slinton newfrp->condition_handler = frame.condition_handler; 899678Slinton newfrp->mask = mask; 909678Slinton newfrp->save_ap = frame.save_ap; 919678Slinton newfrp->save_fp = frame.save_fp; 929678Slinton newfrp->save_pc = frame.save_pc; 939678Slinton } 949678Slinton return newfrp; 959678Slinton } 969678Slinton 979678Slinton /* 989678Slinton * Return the frame associated with the given function. 999678Slinton * If the function is nil, return the most recently activated frame. 1009678Slinton * 1019678Slinton * Static allocation for the frame. 1029678Slinton */ 1039678Slinton 1049678Slinton public Frame findframe(f) 1059678Slinton Symbol f; 1069678Slinton { 1079678Slinton register Frame frp; 1089678Slinton static struct Frame frame; 109*11866Slinton Symbol p; 110*11866Slinton Boolean done; 1119678Slinton 1129678Slinton frp = &frame; 1139678Slinton getcurframe(frp); 1149678Slinton if (f != nil) { 115*11866Slinton done = false; 116*11866Slinton do { 117*11866Slinton p = whatblock(frp->save_pc); 118*11866Slinton if (p == f) { 119*11866Slinton done = true; 120*11866Slinton } else if (p == program) { 121*11866Slinton done = true; 122*11866Slinton frp = nil; 123*11866Slinton } else { 124*11866Slinton frp = nextframe(frp); 125*11866Slinton if (frp == nil) { 126*11866Slinton done = true; 127*11866Slinton } 128*11866Slinton } 129*11866Slinton } while (not done); 1309678Slinton } 1319678Slinton return frp; 1329678Slinton } 1339678Slinton 1349678Slinton /* 1359678Slinton * Find the return address of the current procedure/function. 1369678Slinton */ 1379678Slinton 1389678Slinton public Address return_addr() 1399678Slinton { 1409678Slinton Frame frp; 1419678Slinton Address addr; 1429678Slinton struct Frame frame; 1439678Slinton 1449678Slinton frp = &frame; 1459678Slinton getcurframe(frp); 1469678Slinton frp = nextframe(frp); 1479678Slinton if (frp == nil) { 1489678Slinton addr = 0; 1499678Slinton } else { 1509678Slinton addr = frp->save_pc; 1519678Slinton } 1529678Slinton return addr; 1539678Slinton } 1549678Slinton 1559678Slinton /* 1569678Slinton * Push the value associated with the current function. 1579678Slinton */ 1589678Slinton 1599678Slinton public pushretval(len, isindirect) 1609678Slinton Integer len; 1619678Slinton Boolean isindirect; 1629678Slinton { 1639678Slinton Word r0; 1649678Slinton 1659678Slinton r0 = reg(0); 1669678Slinton if (isindirect) { 1679678Slinton rpush((Address) r0, len); 1689678Slinton } else { 1699678Slinton switch (len) { 1709678Slinton case sizeof(char): 1719678Slinton push(char, r0); 1729678Slinton break; 1739678Slinton 1749678Slinton case sizeof(short): 1759678Slinton push(short, r0); 1769678Slinton break; 1779678Slinton 1789678Slinton default: 1799678Slinton if (len == sizeof(Word)) { 1809678Slinton push(Word, r0); 1819678Slinton } else if (len == 2*sizeof(Word)) { 1829678Slinton push(Word, r0); 1839678Slinton push(Word, reg(1)); 1849678Slinton } else { 1859678Slinton panic("not indirect in pushretval?"); 1869678Slinton } 1879678Slinton break; 1889678Slinton } 1899678Slinton } 1909678Slinton } 1919678Slinton 1929678Slinton /* 1939678Slinton * Return the base address for locals in the given frame. 1949678Slinton */ 1959678Slinton 1969678Slinton public Address locals_base(frp) 1979678Slinton register Frame frp; 1989678Slinton { 1999678Slinton return (frp == nil) ? reg(FRP) : frp->save_fp; 2009678Slinton } 2019678Slinton 2029678Slinton /* 2039678Slinton * Return the base address for arguments in the given frame. 2049678Slinton */ 2059678Slinton 2069678Slinton public Address args_base(frp) 2079678Slinton register Frame frp; 2089678Slinton { 2099678Slinton return (frp == nil) ? reg(ARGP) : frp->save_ap; 2109678Slinton } 2119678Slinton 2129678Slinton /* 2139678Slinton * Return saved register n from the given frame. 2149678Slinton */ 2159678Slinton 2169678Slinton public Word savereg(n, frp) 2179678Slinton register Integer n; 2189678Slinton register Frame frp; 2199678Slinton { 2209678Slinton register Word w; 2219678Slinton 2229678Slinton if (frp == nil) { 2239678Slinton w = reg(n); 2249678Slinton } else { 2259678Slinton switch (n) { 2269678Slinton case ARGP: 2279678Slinton w = frp->save_ap; 2289678Slinton break; 2299678Slinton 2309678Slinton case FRP: 2319678Slinton w = frp->save_fp; 2329678Slinton break; 2339678Slinton 2349678Slinton case STKP: 2359678Slinton w = reg(STKP); 2369678Slinton break; 2379678Slinton 2389678Slinton case PROGCTR: 2399678Slinton w = frp->save_pc; 2409678Slinton break; 2419678Slinton 2429678Slinton default: 2439678Slinton assert(n >= 0 and n < NSAVEREG); 2449678Slinton w = frp->save_reg[n]; 2459678Slinton break; 2469678Slinton } 2479678Slinton } 2489678Slinton return w; 2499678Slinton } 2509678Slinton 2519678Slinton /* 2529678Slinton * Return the nth argument to the current procedure. 2539678Slinton */ 2549678Slinton 2559678Slinton public Word argn(n, frp) 2569678Slinton Integer n; 2579678Slinton Frame frp; 2589678Slinton { 2599678Slinton Word w; 2609678Slinton 2619678Slinton dread(&w, args_base(frp) + (n * sizeof(Word)), sizeof(w)); 2629678Slinton return w; 2639678Slinton } 2649678Slinton 2659678Slinton /* 2669678Slinton * Calculate the entry address for a procedure or function parameter, 2679678Slinton * given the address of the descriptor. 2689678Slinton */ 2699678Slinton 2709678Slinton public Address fparamaddr(a) 2719678Slinton Address a; 2729678Slinton { 2739678Slinton Address r; 2749678Slinton 2759678Slinton dread(&r, a, sizeof(r)); 2769678Slinton return r; 2779678Slinton } 2789678Slinton 2799678Slinton /* 2809678Slinton * Print a list of currently active blocks starting with most recent. 2819678Slinton */ 2829678Slinton 2839678Slinton public wherecmd() 2849678Slinton { 2859678Slinton walkstack(false); 2869678Slinton } 2879678Slinton 2889678Slinton /* 2899678Slinton * Dump the world to the given file. 2909678Slinton * Like "where", but variables are dumped also. 2919678Slinton */ 2929678Slinton 2939678Slinton public dump() 2949678Slinton { 2959678Slinton walkstack(true); 2969678Slinton } 2979678Slinton 2989678Slinton /* 2999678Slinton * Walk the stack of active procedures printing information 3009678Slinton * about each active procedure. 3019678Slinton */ 3029678Slinton 3039678Slinton private walkstack(dumpvariables) 3049678Slinton Boolean dumpvariables; 3059678Slinton { 3069678Slinton register Frame frp; 3079678Slinton register Symbol f; 3089678Slinton register Boolean save; 3099678Slinton register Lineno line; 3109678Slinton struct Frame frame; 3119678Slinton 3129678Slinton if (notstarted(process)) { 3139678Slinton error("program is not active"); 3149678Slinton } else { 3159678Slinton save = walkingstack; 3169678Slinton walkingstack = true; 3179678Slinton frp = &frame; 3189678Slinton getcurframe(frp); 3199678Slinton f = whatblock(frp->save_pc); 3209678Slinton do { 3219678Slinton printf("%s", symname(f)); 3229678Slinton printparams(f, frp); 3239841Slinton line = srcline(frp->save_pc - 1); 3249678Slinton if (line != 0) { 3259678Slinton printf(", line %d", line); 3269841Slinton printf(" in \"%s\"\n", srcfilename(frp->save_pc - 1)); 3279678Slinton } else { 3289678Slinton printf(" at 0x%x\n", frp->save_pc); 3299678Slinton } 3309678Slinton if (dumpvariables) { 3319678Slinton dumpvars(f, frp); 3329678Slinton putchar('\n'); 3339678Slinton } 3349678Slinton frp = nextframe(frp); 3359678Slinton if (frp != nil) { 3369678Slinton f = whatblock(frp->save_pc); 3379678Slinton } 338*11866Slinton } while (frp != nil and f != program); 3399678Slinton if (dumpvariables) { 3409678Slinton printf("in \"%s\":\n", symname(program)); 3419678Slinton dumpvars(program, nil); 3429678Slinton putchar('\n'); 3439678Slinton } 3449678Slinton walkingstack = save; 3459678Slinton } 3469678Slinton } 3479678Slinton 3489678Slinton /* 3499678Slinton * Find the entry point of a procedure or function. 3509678Slinton */ 3519678Slinton 3529678Slinton public findbeginning(f) 3539678Slinton Symbol f; 3549678Slinton { 3559678Slinton f->symvalue.funcv.beginaddr += 2; 3569678Slinton } 3579678Slinton 3589678Slinton /* 3599678Slinton * Return the address corresponding to the first line in a function. 3609678Slinton */ 3619678Slinton 3629678Slinton public Address firstline(f) 3639678Slinton Symbol f; 3649678Slinton { 3659678Slinton Address addr; 3669678Slinton 3679678Slinton addr = codeloc(f); 3689678Slinton while (linelookup(addr) == 0 and addr < objsize) { 3699678Slinton ++addr; 3709678Slinton } 3719678Slinton if (addr == objsize) { 3729678Slinton addr = -1; 3739678Slinton } 3749678Slinton return addr; 3759678Slinton } 3769678Slinton 3779678Slinton /* 3789678Slinton * Catcher drops strike three ... 3799678Slinton */ 3809678Slinton 3819678Slinton public runtofirst() 3829678Slinton { 3839678Slinton Address addr; 3849678Slinton 3859678Slinton addr = pc; 3869678Slinton while (linelookup(addr) == 0 and addr < objsize) { 3879678Slinton ++addr; 3889678Slinton } 3899678Slinton if (addr < objsize) { 3909678Slinton stepto(addr); 3919678Slinton } 3929678Slinton } 3939678Slinton 3949678Slinton /* 3959678Slinton * Return the address corresponding to the end of the program. 3969678Slinton * 3979678Slinton * We look for the entry to "exit". 3989678Slinton */ 3999678Slinton 4009678Slinton public Address lastaddr() 4019678Slinton { 4029678Slinton register Symbol s; 4039678Slinton 4049678Slinton s = lookup(identname("exit", true)); 4059678Slinton if (s == nil) { 4069678Slinton panic("can't find exit"); 4079678Slinton } 4089678Slinton return codeloc(s); 4099678Slinton } 4109678Slinton 4119678Slinton /* 4129678Slinton * Decide if the given function is currently active. 4139678Slinton * 4149678Slinton * We avoid calls to "findframe" during a stack trace for efficiency. 4159678Slinton * Presumably information evaluated while walking the stack is active. 4169678Slinton */ 4179678Slinton 4189678Slinton public Boolean isactive(f) 4199678Slinton Symbol f; 4209678Slinton { 4219678Slinton register Boolean b; 4229678Slinton 4239678Slinton if (isfinished(process)) { 4249678Slinton b = false; 4259678Slinton } else { 4269678Slinton if (walkingstack or f == program or 4279678Slinton (ismodule(f) and isactive(container(f)))) { 4289678Slinton b = true; 4299678Slinton } else { 4309678Slinton b = (Boolean) (findframe(f) != nil); 4319678Slinton } 4329678Slinton } 4339678Slinton return b; 4349678Slinton } 4359678Slinton 4369678Slinton /* 4379678Slinton * Evaluate a call to a procedure. 4389678Slinton */ 4399678Slinton 4409678Slinton public callproc(procnode, arglist) 4419678Slinton Node procnode; 4429678Slinton Node arglist; 4439678Slinton { 4449678Slinton Symbol proc; 4459678Slinton Integer argc; 4469678Slinton 4479678Slinton if (procnode->op != O_SYM) { 4489678Slinton beginerrmsg(); 4499678Slinton fprintf(stderr, "can't call \""); 4509678Slinton prtree(stderr, procnode); 4519678Slinton fprintf(stderr, "\""); 4529678Slinton enderrmsg(); 4539678Slinton } 4549678Slinton assert(procnode->op == O_SYM); 4559678Slinton proc = procnode->value.sym; 4569678Slinton if (not isblock(proc)) { 4579678Slinton error("\"%s\" is not a procedure or function", symname(proc)); 4589678Slinton } 4599678Slinton pushenv(); 4609678Slinton pc = codeloc(proc); 4619678Slinton argc = pushargs(proc, arglist); 4629678Slinton beginproc(proc, argc); 4639678Slinton isstopped = true; 4649678Slinton event_once(build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)), 4659678Slinton buildcmdlist(build(O_PROCRTN, proc))); 4669678Slinton cont(); 4679678Slinton /* NOTREACHED */ 4689678Slinton } 4699678Slinton 4709678Slinton /* 4719678Slinton * Push the arguments on the process' stack. We do this by first 4729678Slinton * evaluating them on the "eval" stack, then copying into the process' 4739678Slinton * space. 4749678Slinton */ 4759678Slinton 4769678Slinton private Integer pushargs(proc, arglist) 4779678Slinton Symbol proc; 4789678Slinton Node arglist; 4799678Slinton { 4809678Slinton Stack *savesp; 4819678Slinton int argc, args_size; 4829678Slinton 4839678Slinton savesp = sp; 4849678Slinton argc = evalargs(proc, arglist); 4859678Slinton args_size = sp - savesp; 4869678Slinton setreg(STKP, reg(STKP) - args_size); 4879678Slinton dwrite(savesp, reg(STKP), args_size); 4889678Slinton sp = savesp; 4899678Slinton return argc; 4909678Slinton } 4919678Slinton 4929678Slinton /* 4939678Slinton * Evaluate arguments left-to-right. 4949678Slinton */ 4959678Slinton 4969678Slinton private Integer evalargs(proc, arglist) 4979678Slinton Symbol proc; 4989678Slinton Node arglist; 4999678Slinton { 5009678Slinton Node p, exp; 5019678Slinton Symbol arg; 5029678Slinton Stack *savesp; 5039678Slinton Address addr; 5049678Slinton Integer count; 5059678Slinton 5069678Slinton savesp = sp; 5079678Slinton count = 0; 5089678Slinton arg = proc->chain; 5099678Slinton for (p = arglist; p != nil; p = p->value.arg[1]) { 5109678Slinton if (p->op != O_COMMA) { 5119678Slinton panic("evalargs: arglist missing comma"); 5129678Slinton } 5139678Slinton if (arg == nil) { 5149678Slinton sp = savesp; 5159678Slinton error("too many parameters to %s", symname(proc)); 5169678Slinton } 5179678Slinton exp = p->value.arg[0]; 5189678Slinton if (not compatible(arg->type, exp->nodetype)) { 5199678Slinton sp = savesp; 5209678Slinton error("expression for parameter %s is of wrong type", symname(arg)); 5219678Slinton } 5229678Slinton if (arg->class == REF) { 5239678Slinton if (exp->op != O_RVAL) { 5249678Slinton sp = savesp; 5259678Slinton error("variable expected for parameter \"%s\"", symname(arg)); 5269678Slinton } 5279678Slinton addr = lval(exp->value.arg[0]); 5289678Slinton push(Address, addr); 5299678Slinton } else { 5309678Slinton eval(exp); 5319678Slinton } 5329678Slinton arg = arg->chain; 5339678Slinton ++count; 5349678Slinton } 5359678Slinton if (arg != nil) { 5369678Slinton sp = savesp; 5379678Slinton error("not enough parameters to %s", symname(proc)); 5389678Slinton } 5399678Slinton return count; 5409678Slinton } 5419678Slinton 5429678Slinton public procreturn(f) 5439678Slinton Symbol f; 5449678Slinton { 5459678Slinton flushoutput(); 5469678Slinton putchar('\n'); 5479678Slinton printname(stdout, f); 5489678Slinton printf(" returns successfully\n", symname(f)); 5499678Slinton popenv(); 5509678Slinton erecover(); 5519678Slinton } 5529678Slinton 5539678Slinton /* 5549678Slinton * Push the current environment. 5559678Slinton */ 5569678Slinton 5579678Slinton private pushenv() 5589678Slinton { 5599678Slinton push(Address, pc); 5609678Slinton push(Lineno, curline); 5619678Slinton push(String, cursource); 5629678Slinton push(Boolean, isstopped); 5639678Slinton push(Symbol, curfunc); 5649678Slinton push(Word, reg(PROGCTR)); 5659678Slinton push(Word, reg(STKP)); 5669678Slinton } 5679678Slinton 5689678Slinton /* 5699678Slinton * Pop back to the real world. 5709678Slinton */ 5719678Slinton 5729678Slinton public popenv() 5739678Slinton { 5749678Slinton register String filename; 5759678Slinton 5769678Slinton setreg(STKP, pop(Word)); 5779678Slinton setreg(PROGCTR, pop(Word)); 5789678Slinton curfunc = pop(Symbol); 5799678Slinton isstopped = pop(Boolean); 5809678Slinton filename = pop(String); 5819678Slinton curline = pop(Lineno); 5829678Slinton pc = pop(Address); 5839678Slinton setsource(filename); 5849678Slinton } 5859678Slinton 5869678Slinton /* 5879678Slinton * Flush the debuggee's standard output. 5889678Slinton * 5899678Slinton * This is VERY dependent on the use of stdio. 5909678Slinton */ 5919678Slinton 5929678Slinton public flushoutput() 5939678Slinton { 5949678Slinton register Symbol p, iob; 5959678Slinton register Stack *savesp; 5969678Slinton 5979678Slinton p = lookup(identname("fflush", true)); 5989678Slinton while (p != nil and not isblock(p)) { 5999678Slinton p = p->next_sym; 6009678Slinton } 6019678Slinton if (p != nil) { 6029678Slinton iob = lookup(identname("_iob", true)); 6039678Slinton if (iob != nil) { 6049678Slinton pushenv(); 6059678Slinton pc = codeloc(p); 6069678Slinton savesp = sp; 6079678Slinton push(long, address(iob, nil) + sizeof(struct _iobuf)); 6089678Slinton setreg(STKP, reg(STKP) - sizeof(long)); 6099678Slinton dwrite(savesp, reg(STKP), sizeof(long)); 6109678Slinton sp = savesp; 6119678Slinton beginproc(p, 1); 6129678Slinton stepto(return_addr()); 6139678Slinton popenv(); 6149678Slinton } 6159678Slinton } 6169678Slinton } 617