xref: /csrg-svn/old/dbx/runtime.vax.c (revision 9841)
19678Slinton /* Copyright (c) 1982 Regents of the University of California */
29678Slinton 
3*9841Slinton static char sccsid[] = "@(#)runtime.vax.c 1.3 12/18/82";
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;
1099678Slinton 
1109678Slinton     frp = &frame;
1119678Slinton     getcurframe(frp);
1129678Slinton     if (f != nil) {
1139678Slinton 	while (frp != nil and whatblock(frp->save_pc) != f) {
1149678Slinton 	    frp = nextframe(frp);
1159678Slinton 	}
1169678Slinton     }
1179678Slinton     return frp;
1189678Slinton }
1199678Slinton 
1209678Slinton /*
1219678Slinton  * Find the return address of the current procedure/function.
1229678Slinton  */
1239678Slinton 
1249678Slinton public Address return_addr()
1259678Slinton {
1269678Slinton     Frame frp;
1279678Slinton     Address addr;
1289678Slinton     struct Frame frame;
1299678Slinton 
1309678Slinton     frp = &frame;
1319678Slinton     getcurframe(frp);
1329678Slinton     frp = nextframe(frp);
1339678Slinton     if (frp == nil) {
1349678Slinton 	addr = 0;
1359678Slinton     } else {
1369678Slinton 	addr = frp->save_pc;
1379678Slinton     }
1389678Slinton     return addr;
1399678Slinton }
1409678Slinton 
1419678Slinton /*
1429678Slinton  * Push the value associated with the current function.
1439678Slinton  */
1449678Slinton 
1459678Slinton public pushretval(len, isindirect)
1469678Slinton Integer len;
1479678Slinton Boolean isindirect;
1489678Slinton {
1499678Slinton     Word r0;
1509678Slinton 
1519678Slinton     r0 = reg(0);
1529678Slinton     if (isindirect) {
1539678Slinton 	rpush((Address) r0, len);
1549678Slinton     } else {
1559678Slinton 	switch (len) {
1569678Slinton 	    case sizeof(char):
1579678Slinton 		push(char, r0);
1589678Slinton 		break;
1599678Slinton 
1609678Slinton 	    case sizeof(short):
1619678Slinton 		push(short, r0);
1629678Slinton 		break;
1639678Slinton 
1649678Slinton 	    default:
1659678Slinton 		if (len == sizeof(Word)) {
1669678Slinton 		    push(Word, r0);
1679678Slinton 		} else if (len == 2*sizeof(Word)) {
1689678Slinton 		    push(Word, r0);
1699678Slinton 		    push(Word, reg(1));
1709678Slinton 		} else {
1719678Slinton 		    panic("not indirect in pushretval?");
1729678Slinton 		}
1739678Slinton 		break;
1749678Slinton 	}
1759678Slinton     }
1769678Slinton }
1779678Slinton 
1789678Slinton /*
1799678Slinton  * Return the base address for locals in the given frame.
1809678Slinton  */
1819678Slinton 
1829678Slinton public Address locals_base(frp)
1839678Slinton register Frame frp;
1849678Slinton {
1859678Slinton     return (frp == nil) ? reg(FRP) : frp->save_fp;
1869678Slinton }
1879678Slinton 
1889678Slinton /*
1899678Slinton  * Return the base address for arguments in the given frame.
1909678Slinton  */
1919678Slinton 
1929678Slinton public Address args_base(frp)
1939678Slinton register Frame frp;
1949678Slinton {
1959678Slinton     return (frp == nil) ? reg(ARGP) : frp->save_ap;
1969678Slinton }
1979678Slinton 
1989678Slinton /*
1999678Slinton  * Return saved register n from the given frame.
2009678Slinton  */
2019678Slinton 
2029678Slinton public Word savereg(n, frp)
2039678Slinton register Integer n;
2049678Slinton register Frame frp;
2059678Slinton {
2069678Slinton     register Word w;
2079678Slinton 
2089678Slinton     if (frp == nil) {
2099678Slinton 	w = reg(n);
2109678Slinton     } else {
2119678Slinton 	switch (n) {
2129678Slinton 	    case ARGP:
2139678Slinton 		w = frp->save_ap;
2149678Slinton 		break;
2159678Slinton 
2169678Slinton 	    case FRP:
2179678Slinton 		w = frp->save_fp;
2189678Slinton 		break;
2199678Slinton 
2209678Slinton 	    case STKP:
2219678Slinton 		w = reg(STKP);
2229678Slinton 		break;
2239678Slinton 
2249678Slinton 	    case PROGCTR:
2259678Slinton 		w = frp->save_pc;
2269678Slinton 		break;
2279678Slinton 
2289678Slinton 	    default:
2299678Slinton 		assert(n >= 0 and n < NSAVEREG);
2309678Slinton 		w = frp->save_reg[n];
2319678Slinton 		break;
2329678Slinton 	}
2339678Slinton     }
2349678Slinton     return w;
2359678Slinton }
2369678Slinton 
2379678Slinton /*
2389678Slinton  * Return the nth argument to the current procedure.
2399678Slinton  */
2409678Slinton 
2419678Slinton public Word argn(n, frp)
2429678Slinton Integer n;
2439678Slinton Frame frp;
2449678Slinton {
2459678Slinton     Word w;
2469678Slinton 
2479678Slinton     dread(&w, args_base(frp) + (n * sizeof(Word)), sizeof(w));
2489678Slinton     return w;
2499678Slinton }
2509678Slinton 
2519678Slinton /*
2529678Slinton  * Calculate the entry address for a procedure or function parameter,
2539678Slinton  * given the address of the descriptor.
2549678Slinton  */
2559678Slinton 
2569678Slinton public Address fparamaddr(a)
2579678Slinton Address a;
2589678Slinton {
2599678Slinton     Address r;
2609678Slinton 
2619678Slinton     dread(&r, a, sizeof(r));
2629678Slinton     return r;
2639678Slinton }
2649678Slinton 
2659678Slinton /*
2669678Slinton  * Print a list of currently active blocks starting with most recent.
2679678Slinton  */
2689678Slinton 
2699678Slinton public wherecmd()
2709678Slinton {
2719678Slinton     walkstack(false);
2729678Slinton }
2739678Slinton 
2749678Slinton /*
2759678Slinton  * Dump the world to the given file.
2769678Slinton  * Like "where", but variables are dumped also.
2779678Slinton  */
2789678Slinton 
2799678Slinton public dump()
2809678Slinton {
2819678Slinton     walkstack(true);
2829678Slinton }
2839678Slinton 
2849678Slinton /*
2859678Slinton  * Walk the stack of active procedures printing information
2869678Slinton  * about each active procedure.
2879678Slinton  */
2889678Slinton 
2899678Slinton #define lastfunc(f)     (f == program)
2909678Slinton 
2919678Slinton private walkstack(dumpvariables)
2929678Slinton Boolean dumpvariables;
2939678Slinton {
2949678Slinton     register Frame frp;
2959678Slinton     register Symbol f;
2969678Slinton     register Boolean save;
2979678Slinton     register Lineno line;
2989678Slinton     struct Frame frame;
2999678Slinton 
3009678Slinton     if (notstarted(process)) {
3019678Slinton 	error("program is not active");
3029678Slinton     } else {
3039678Slinton 	save = walkingstack;
3049678Slinton 	walkingstack = true;
3059678Slinton 	frp = &frame;
3069678Slinton 	getcurframe(frp);
3079678Slinton 	f = whatblock(frp->save_pc);
3089678Slinton 	do {
3099678Slinton 	    printf("%s", symname(f));
3109678Slinton 	    printparams(f, frp);
311*9841Slinton 	    line = srcline(frp->save_pc - 1);
3129678Slinton 	    if (line != 0) {
3139678Slinton 		printf(", line %d", line);
314*9841Slinton 		printf(" in \"%s\"\n", srcfilename(frp->save_pc - 1));
3159678Slinton 	    } else {
3169678Slinton 		printf(" at 0x%x\n", frp->save_pc);
3179678Slinton 	    }
3189678Slinton 	    if (dumpvariables) {
3199678Slinton 		dumpvars(f, frp);
3209678Slinton 		putchar('\n');
3219678Slinton 	    }
3229678Slinton 	    frp = nextframe(frp);
3239678Slinton 	    if (frp != nil) {
3249678Slinton 		f = whatblock(frp->save_pc);
3259678Slinton 	    }
3269678Slinton 	} while (frp != nil and not lastfunc(f));
3279678Slinton 	if (dumpvariables) {
3289678Slinton 	    printf("in \"%s\":\n", symname(program));
3299678Slinton 	    dumpvars(program, nil);
3309678Slinton 	    putchar('\n');
3319678Slinton 	}
3329678Slinton 	walkingstack = save;
3339678Slinton     }
3349678Slinton }
3359678Slinton 
3369678Slinton /*
3379678Slinton  * Find the entry point of a procedure or function.
3389678Slinton  */
3399678Slinton 
3409678Slinton public findbeginning(f)
3419678Slinton Symbol f;
3429678Slinton {
3439678Slinton     f->symvalue.funcv.beginaddr += 2;
3449678Slinton }
3459678Slinton 
3469678Slinton /*
3479678Slinton  * Return the address corresponding to the first line in a function.
3489678Slinton  */
3499678Slinton 
3509678Slinton public Address firstline(f)
3519678Slinton Symbol f;
3529678Slinton {
3539678Slinton     Address addr;
3549678Slinton 
3559678Slinton     addr = codeloc(f);
3569678Slinton     while (linelookup(addr) == 0 and addr < objsize) {
3579678Slinton 	++addr;
3589678Slinton     }
3599678Slinton     if (addr == objsize) {
3609678Slinton 	addr = -1;
3619678Slinton     }
3629678Slinton     return addr;
3639678Slinton }
3649678Slinton 
3659678Slinton /*
3669678Slinton  * Catcher drops strike three ...
3679678Slinton  */
3689678Slinton 
3699678Slinton public runtofirst()
3709678Slinton {
3719678Slinton     Address addr;
3729678Slinton 
3739678Slinton     addr = pc;
3749678Slinton     while (linelookup(addr) == 0 and addr < objsize) {
3759678Slinton 	++addr;
3769678Slinton     }
3779678Slinton     if (addr < objsize) {
3789678Slinton 	stepto(addr);
3799678Slinton     }
3809678Slinton }
3819678Slinton 
3829678Slinton /*
3839678Slinton  * Return the address corresponding to the end of the program.
3849678Slinton  *
3859678Slinton  * We look for the entry to "exit".
3869678Slinton  */
3879678Slinton 
3889678Slinton public Address lastaddr()
3899678Slinton {
3909678Slinton     register Symbol s;
3919678Slinton 
3929678Slinton     s = lookup(identname("exit", true));
3939678Slinton     if (s == nil) {
3949678Slinton 	panic("can't find exit");
3959678Slinton     }
3969678Slinton     return codeloc(s);
3979678Slinton }
3989678Slinton 
3999678Slinton /*
4009678Slinton  * Decide if the given function is currently active.
4019678Slinton  *
4029678Slinton  * We avoid calls to "findframe" during a stack trace for efficiency.
4039678Slinton  * Presumably information evaluated while walking the stack is active.
4049678Slinton  */
4059678Slinton 
4069678Slinton public Boolean isactive(f)
4079678Slinton Symbol f;
4089678Slinton {
4099678Slinton     register Boolean b;
4109678Slinton 
4119678Slinton     if (isfinished(process)) {
4129678Slinton 	b = false;
4139678Slinton     } else {
4149678Slinton 	if (walkingstack or f == program or
4159678Slinton 	  (ismodule(f) and isactive(container(f)))) {
4169678Slinton 	    b = true;
4179678Slinton 	} else {
4189678Slinton 	    b = (Boolean) (findframe(f) != nil);
4199678Slinton 	}
4209678Slinton     }
4219678Slinton     return b;
4229678Slinton }
4239678Slinton 
4249678Slinton /*
4259678Slinton  * Evaluate a call to a procedure.
4269678Slinton  */
4279678Slinton 
4289678Slinton public callproc(procnode, arglist)
4299678Slinton Node procnode;
4309678Slinton Node arglist;
4319678Slinton {
4329678Slinton     Symbol proc;
4339678Slinton     Integer argc;
4349678Slinton 
4359678Slinton     if (procnode->op != O_SYM) {
4369678Slinton 	beginerrmsg();
4379678Slinton 	fprintf(stderr, "can't call \"");
4389678Slinton 	prtree(stderr, procnode);
4399678Slinton 	fprintf(stderr, "\"");
4409678Slinton 	enderrmsg();
4419678Slinton     }
4429678Slinton     assert(procnode->op == O_SYM);
4439678Slinton     proc = procnode->value.sym;
4449678Slinton     if (not isblock(proc)) {
4459678Slinton 	error("\"%s\" is not a procedure or function", symname(proc));
4469678Slinton     }
4479678Slinton     pushenv();
4489678Slinton     pc = codeloc(proc);
4499678Slinton     argc = pushargs(proc, arglist);
4509678Slinton     beginproc(proc, argc);
4519678Slinton     isstopped = true;
4529678Slinton     event_once(build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)),
4539678Slinton 	buildcmdlist(build(O_PROCRTN, proc)));
4549678Slinton     cont();
4559678Slinton     /* NOTREACHED */
4569678Slinton }
4579678Slinton 
4589678Slinton /*
4599678Slinton  * Push the arguments on the process' stack.  We do this by first
4609678Slinton  * evaluating them on the "eval" stack, then copying into the process'
4619678Slinton  * space.
4629678Slinton  */
4639678Slinton 
4649678Slinton private Integer pushargs(proc, arglist)
4659678Slinton Symbol proc;
4669678Slinton Node arglist;
4679678Slinton {
4689678Slinton     Stack *savesp;
4699678Slinton     int argc, args_size;
4709678Slinton 
4719678Slinton     savesp = sp;
4729678Slinton     argc = evalargs(proc, arglist);
4739678Slinton     args_size = sp - savesp;
4749678Slinton     setreg(STKP, reg(STKP) - args_size);
4759678Slinton     dwrite(savesp, reg(STKP), args_size);
4769678Slinton     sp = savesp;
4779678Slinton     return argc;
4789678Slinton }
4799678Slinton 
4809678Slinton /*
4819678Slinton  * Evaluate arguments left-to-right.
4829678Slinton  */
4839678Slinton 
4849678Slinton private Integer evalargs(proc, arglist)
4859678Slinton Symbol proc;
4869678Slinton Node arglist;
4879678Slinton {
4889678Slinton     Node p, exp;
4899678Slinton     Symbol arg;
4909678Slinton     Stack *savesp;
4919678Slinton     Address addr;
4929678Slinton     Integer count;
4939678Slinton 
4949678Slinton     savesp = sp;
4959678Slinton     count = 0;
4969678Slinton     arg = proc->chain;
4979678Slinton     for (p = arglist; p != nil; p = p->value.arg[1]) {
4989678Slinton 	if (p->op != O_COMMA) {
4999678Slinton 	    panic("evalargs: arglist missing comma");
5009678Slinton 	}
5019678Slinton 	if (arg == nil) {
5029678Slinton 	    sp = savesp;
5039678Slinton 	    error("too many parameters to %s", symname(proc));
5049678Slinton 	}
5059678Slinton 	exp = p->value.arg[0];
5069678Slinton 	if (not compatible(arg->type, exp->nodetype)) {
5079678Slinton 	    sp = savesp;
5089678Slinton 	    error("expression for parameter %s is of wrong type", symname(arg));
5099678Slinton 	}
5109678Slinton 	if (arg->class == REF) {
5119678Slinton 	    if (exp->op != O_RVAL) {
5129678Slinton 		sp = savesp;
5139678Slinton 		error("variable expected for parameter \"%s\"", symname(arg));
5149678Slinton 	    }
5159678Slinton 	    addr = lval(exp->value.arg[0]);
5169678Slinton 	    push(Address, addr);
5179678Slinton 	} else {
5189678Slinton 	    eval(exp);
5199678Slinton 	}
5209678Slinton 	arg = arg->chain;
5219678Slinton 	++count;
5229678Slinton     }
5239678Slinton     if (arg != nil) {
5249678Slinton 	sp = savesp;
5259678Slinton 	error("not enough parameters to %s", symname(proc));
5269678Slinton     }
5279678Slinton     return count;
5289678Slinton }
5299678Slinton 
5309678Slinton public procreturn(f)
5319678Slinton Symbol f;
5329678Slinton {
5339678Slinton     flushoutput();
5349678Slinton     putchar('\n');
5359678Slinton     printname(stdout, f);
5369678Slinton     printf(" returns successfully\n", symname(f));
5379678Slinton     popenv();
5389678Slinton     erecover();
5399678Slinton }
5409678Slinton 
5419678Slinton /*
5429678Slinton  * Push the current environment.
5439678Slinton  */
5449678Slinton 
5459678Slinton private pushenv()
5469678Slinton {
5479678Slinton     push(Address, pc);
5489678Slinton     push(Lineno, curline);
5499678Slinton     push(String, cursource);
5509678Slinton     push(Boolean, isstopped);
5519678Slinton     push(Symbol, curfunc);
5529678Slinton     push(Word, reg(PROGCTR));
5539678Slinton     push(Word, reg(STKP));
5549678Slinton }
5559678Slinton 
5569678Slinton /*
5579678Slinton  * Pop back to the real world.
5589678Slinton  */
5599678Slinton 
5609678Slinton public popenv()
5619678Slinton {
5629678Slinton     register String filename;
5639678Slinton 
5649678Slinton     setreg(STKP, pop(Word));
5659678Slinton     setreg(PROGCTR, pop(Word));
5669678Slinton     curfunc = pop(Symbol);
5679678Slinton     isstopped = pop(Boolean);
5689678Slinton     filename = pop(String);
5699678Slinton     curline = pop(Lineno);
5709678Slinton     pc = pop(Address);
5719678Slinton     setsource(filename);
5729678Slinton }
5739678Slinton 
5749678Slinton /*
5759678Slinton  * Flush the debuggee's standard output.
5769678Slinton  *
5779678Slinton  * This is VERY dependent on the use of stdio.
5789678Slinton  */
5799678Slinton 
5809678Slinton public flushoutput()
5819678Slinton {
5829678Slinton     register Symbol p, iob;
5839678Slinton     register Stack *savesp;
5849678Slinton 
5859678Slinton     p = lookup(identname("fflush", true));
5869678Slinton     while (p != nil and not isblock(p)) {
5879678Slinton 	p = p->next_sym;
5889678Slinton     }
5899678Slinton     if (p != nil) {
5909678Slinton 	iob = lookup(identname("_iob", true));
5919678Slinton 	if (iob != nil) {
5929678Slinton 	    pushenv();
5939678Slinton 	    pc = codeloc(p);
5949678Slinton 	    savesp = sp;
5959678Slinton 	    push(long, address(iob, nil) + sizeof(struct _iobuf));
5969678Slinton 	    setreg(STKP, reg(STKP) - sizeof(long));
5979678Slinton 	    dwrite(savesp, reg(STKP), sizeof(long));
5989678Slinton 	    sp = savesp;
5999678Slinton 	    beginproc(p, 1);
6009678Slinton 	    stepto(return_addr());
6019678Slinton 	    popenv();
6029678Slinton 	}
6039678Slinton     }
6049678Slinton }
605