xref: /csrg-svn/old/dbx/runtime.c (revision 11866)
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