xref: /csrg-svn/old/dbx/runtime.vax.c (revision 42685)
121621Sdist /*
238105Sbostic  * Copyright (c) 1983 The Regents of the University of California.
338105Sbostic  * All rights reserved.
438105Sbostic  *
5*42685Sbostic  * %sccs.include.redist.c%
621621Sdist  */
79678Slinton 
821621Sdist #ifndef lint
9*42685Sbostic static char sccsid[] = "@(#)runtime.vax.c	5.5 (Berkeley) 06/01/90";
1038105Sbostic #endif /* not lint */
119678Slinton 
129678Slinton /*
139678Slinton  * Runtime organization dependent routines, mostly dealing with
149678Slinton  * activation records.
159678Slinton  */
169678Slinton 
179678Slinton #include "defs.h"
189678Slinton #include "runtime.h"
199678Slinton #include "process.h"
209678Slinton #include "machine.h"
219678Slinton #include "events.h"
229678Slinton #include "mappings.h"
239678Slinton #include "symbols.h"
249678Slinton #include "tree.h"
259678Slinton #include "eval.h"
269678Slinton #include "operators.h"
279678Slinton #include "object.h"
2812546Scsvaf #include <sys/param.h>
2933334Sdonn #include <signal.h>
309678Slinton 
319678Slinton #ifndef public
329678Slinton typedef struct Frame *Frame;
339678Slinton 
349678Slinton #include "machine.h"
359678Slinton #endif
369678Slinton 
379678Slinton #define NSAVEREG 12
389678Slinton 
399678Slinton struct Frame {
4018231Slinton     integer condition_handler;
4118231Slinton     integer mask;
429678Slinton     Address save_ap;		/* argument pointer */
439678Slinton     Address save_fp;		/* frame pointer */
449678Slinton     Address save_pc;		/* program counter */
459678Slinton     Word save_reg[NSAVEREG];	/* not necessarily there */
469678Slinton };
479678Slinton 
4816618Ssam private Frame curframe = nil;
4916618Ssam private struct Frame curframerec;
509678Slinton private Boolean walkingstack = false;
519678Slinton 
5216618Ssam #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp)
5316618Ssam 
5433334Sdonn #define inSignalHandler(addr) \
5533334Sdonn     (((addr) < 0x80000000) and ((addr) > 0x80000000 - ctob(UPAGES)))
5618231Slinton 
5718231Slinton typedef struct {
5818231Slinton     Node callnode;
5918231Slinton     Node cmdnode;
6018231Slinton     boolean isfunc;
6118231Slinton } CallEnv;
6218231Slinton 
6318231Slinton private CallEnv endproc;
6418231Slinton 
659678Slinton /*
669678Slinton  * Set a frame to the current activation record.
679678Slinton  */
689678Slinton 
699678Slinton private getcurframe(frp)
7018231Slinton Frame frp;
719678Slinton {
729678Slinton     register int i;
739678Slinton 
749678Slinton     checkref(frp);
759678Slinton     frp->mask = reg(NREG);
769678Slinton     frp->save_ap = reg(ARGP);
779678Slinton     frp->save_fp = reg(FRP);
7818231Slinton     frp->save_pc = reg(PROGCTR);
799678Slinton     for (i = 0; i < NSAVEREG; i++) {
809678Slinton 	frp->save_reg[i] = reg(i);
819678Slinton     }
829678Slinton }
839678Slinton 
849678Slinton /*
8518231Slinton  * Get the saved registers from one frame to another
8618231Slinton  * given mask specifying which registers were actually saved.
8718231Slinton  */
8818231Slinton 
8918231Slinton #define bis(b, n) ((b & (1 << (n))) != 0)
9018231Slinton 
9118231Slinton private getsaveregs (newfrp, frp, mask)
9218231Slinton Frame newfrp, frp;
9318231Slinton integer mask;
9418231Slinton {
9518231Slinton     integer i, j;
9618231Slinton 
9718231Slinton     j = 0;
9818231Slinton     for (i = 0; i < NSAVEREG; i++) {
9918231Slinton 	if (bis(mask, i)) {
10018231Slinton 	    newfrp->save_reg[i] = frp->save_reg[j];
10118231Slinton 	    ++j;
10218231Slinton 	}
10318231Slinton     }
10418231Slinton }
10518231Slinton 
10618231Slinton /*
1079678Slinton  * Return a pointer to the next activation record up the stack.
1089678Slinton  * Return nil if there is none.
1099678Slinton  * Writes over space pointed to by given argument.
1109678Slinton  */
1119678Slinton 
1129678Slinton private Frame nextframe(frp)
1139678Slinton Frame frp;
1149678Slinton {
11518231Slinton     Frame newfrp;
1169678Slinton     struct Frame frame;
11718231Slinton     integer mask;
11833334Sdonn     Address prev_frame, callpc;
11918231Slinton     static integer ntramp = 0;
1209678Slinton 
1219678Slinton     newfrp = frp;
12212546Scsvaf     prev_frame = frp->save_fp;
12312546Scsvaf 
12413937Slinton /*
12513937Slinton  *  The check for interrupt generated frames is taken from adb with only
12613937Slinton  *  partial understanding.  If you're in "sub" and on a sigxxx "sigsub"
12713937Slinton  *  gets control, then the stack does NOT look like <main, sub, sigsub>.
12812546Scsvaf  *
12912546Scsvaf  *  As best I can make out it looks like:
13012546Scsvaf  *
13113937Slinton  *     <main, (machine check exception block + sub), sysframe, sigsub>.
13213937Slinton  *
13313937Slinton  *  When the signal occurs an exception block and a frame for the routine
13413937Slinton  *  in which it occured are pushed on the user stack.  Then another frame
13513937Slinton  *  is pushed corresponding to a call from the kernel to sigsub.
13613937Slinton  *
13712546Scsvaf  *  The addr in sub at which the exception occured is not in sub.save_pc
13813937Slinton  *  but in the machine check exception block.  It is at the magic address
13914620Ssam  *  fp + 84.
14012546Scsvaf  *
14112546Scsvaf  *  The current approach ignores the sys_frame (what adb reports as sigtramp)
14213937Slinton  *  and takes the pc for sub from the exception block.  This allows the
14313937Slinton  *  "where" command to report <main, sub, sigsub>, which seems reasonable.
14412546Scsvaf  */
14512546Scsvaf 
14613937Slinton nextf:
14733334Sdonn     if (prev_frame + sizeof(struct Frame) <= USRSTACK) {
14833334Sdonn 	dread(&frame, prev_frame, sizeof(struct Frame));
14933334Sdonn     } else if (USRSTACK - prev_frame > 2 * sizeof(Word)) {
15033334Sdonn 	dread(&frame, prev_frame, USRSTACK - prev_frame);
15133334Sdonn     } else {
15233334Sdonn 	frame.save_fp = nil;
15333334Sdonn     }
15413937Slinton     if (ntramp == 1) {
15533334Sdonn 	dread(&callpc, prev_frame + 92, sizeof(callpc));
15613937Slinton     } else {
15713937Slinton 	callpc = frame.save_pc;
15813937Slinton     }
15918231Slinton     if (frame.save_fp == nil or frame.save_pc == (Address) -1) {
1609678Slinton 	newfrp = nil;
16113937Slinton     } else {
16233334Sdonn 	if (inSignalHandler(callpc)) {
16333334Sdonn 	    ntramp++;
16433334Sdonn 	    prev_frame = frame.save_fp;
16533334Sdonn 	    goto nextf;
16633334Sdonn 	}
16712546Scsvaf 	frame.save_pc = callpc;
16813937Slinton         ntramp = 0;
16933334Sdonn 	newfrp->save_fp = frame.save_fp;
17033334Sdonn 	newfrp->save_pc = frame.save_pc;
1719678Slinton 	mask = ((frame.mask >> 16) & 0x0fff);
17218231Slinton 	getsaveregs(newfrp, &frame, mask);
1739678Slinton 	newfrp->condition_handler = frame.condition_handler;
1749678Slinton 	newfrp->mask = mask;
1759678Slinton 	newfrp->save_ap = frame.save_ap;
1769678Slinton     }
1779678Slinton     return newfrp;
1789678Slinton }
1799678Slinton 
1809678Slinton /*
18116618Ssam  * Get the current frame information in the given Frame and store the
18216618Ssam  * associated function in the given value-result parameter.
18316618Ssam  */
18416618Ssam 
18516618Ssam private getcurfunc (frp, fp)
18616618Ssam Frame frp;
18716618Ssam Symbol *fp;
18816618Ssam {
18916618Ssam     getcurframe(frp);
19016618Ssam     *fp = whatblock(frp->save_pc);
19116618Ssam }
19216618Ssam 
19316618Ssam /*
19416618Ssam  * Return the frame associated with the next function up the call stack, or
19516618Ssam  * nil if there is none.  The function is returned in a value-result parameter.
19616618Ssam  * For "inline" functions the statically outer function and same frame
19716618Ssam  * are returned.
19816618Ssam  */
19916618Ssam 
20018231Slinton public Frame nextfunc (frp, fp)
20116618Ssam Frame frp;
20216618Ssam Symbol *fp;
20316618Ssam {
20416618Ssam     Symbol t;
20516618Ssam     Frame nfrp;
20616618Ssam 
20716618Ssam     t = *fp;
20816618Ssam     checkref(t);
20916618Ssam     if (isinline(t)) {
21016618Ssam 	t = container(t);
21116618Ssam 	nfrp = frp;
21216618Ssam     } else {
21316618Ssam 	nfrp = nextframe(frp);
21416618Ssam 	if (nfrp == nil) {
21516618Ssam 	    t = nil;
21616618Ssam 	} else {
21716618Ssam 	    t = whatblock(nfrp->save_pc);
21816618Ssam 	}
21916618Ssam     }
22016618Ssam     *fp = t;
22116618Ssam     return nfrp;
22216618Ssam }
22316618Ssam 
22416618Ssam /*
2259678Slinton  * Return the frame associated with the given function.
2269678Slinton  * If the function is nil, return the most recently activated frame.
2279678Slinton  *
2289678Slinton  * Static allocation for the frame.
2299678Slinton  */
2309678Slinton 
2319678Slinton public Frame findframe(f)
2329678Slinton Symbol f;
2339678Slinton {
23418231Slinton     Frame frp;
2359678Slinton     static struct Frame frame;
23611866Slinton     Symbol p;
23718231Slinton     Boolean done;
2389678Slinton 
2399678Slinton     frp = &frame;
2409678Slinton     getcurframe(frp);
24118231Slinton     if (f != nil) {
24218231Slinton 	if (f == curfunc and curframe != nil) {
24318231Slinton 	    *frp = *curframe;
24418231Slinton 	} else {
24518231Slinton 	    done = false;
24618231Slinton 	    p = whatblock(frp->save_pc);
24718231Slinton 	    do {
24818231Slinton 		if (p == f) {
24918231Slinton 		    done = true;
25018231Slinton 		} else if (p == program) {
25118231Slinton 		    done = true;
25218231Slinton 		    frp = nil;
25318231Slinton 		} else {
25418231Slinton 		    frp = nextfunc(frp, &p);
25518231Slinton 		    if (frp == nil) {
25618231Slinton 			done = true;
25718231Slinton 		    }
25818231Slinton 		}
25918231Slinton 	    } while (not done);
26015784Ssam 	}
26118231Slinton     }
26218231Slinton     return frp;
26318231Slinton }
26418231Slinton 
26518231Slinton /*
26618231Slinton  * Set the registers according to the given frame pointer.
26718231Slinton  */
26818231Slinton 
26918231Slinton public getnewregs (addr)
27018231Slinton Address addr;
27118231Slinton {
27218231Slinton     struct Frame frame;
27318231Slinton     integer i, j, mask;
27418231Slinton 
27518231Slinton     dread(&frame, addr, sizeof(frame));
27618231Slinton     setreg(FRP, frame.save_fp);
27718231Slinton     setreg(PROGCTR, frame.save_pc);
27833334Sdonn     setreg(ARGP, frame.save_ap);
27918231Slinton     mask = ((frame.mask >> 16) & 0x0fff);
28018231Slinton     j = 0;
28118231Slinton     for (i = 0; i < NSAVEREG; i++) {
28218231Slinton 	if (bis(mask, i)) {
28333334Sdonn 	setreg(i, frame.save_reg[j]);
28433334Sdonn 	++j;
28516636Ssam 	}
2869678Slinton     }
28718231Slinton     pc = frame.save_pc;
28818231Slinton     setcurfunc(whatblock(pc));
2899678Slinton }
2909678Slinton 
2919678Slinton /*
2929678Slinton  * Find the return address of the current procedure/function.
2939678Slinton  */
2949678Slinton 
2959678Slinton public Address return_addr()
2969678Slinton {
2979678Slinton     Frame frp;
2989678Slinton     Address addr;
2999678Slinton     struct Frame frame;
3009678Slinton 
3019678Slinton     frp = &frame;
3029678Slinton     getcurframe(frp);
3039678Slinton     frp = nextframe(frp);
3049678Slinton     if (frp == nil) {
3059678Slinton 	addr = 0;
3069678Slinton     } else {
3079678Slinton 	addr = frp->save_pc;
3089678Slinton     }
3099678Slinton     return addr;
3109678Slinton }
3119678Slinton 
3129678Slinton /*
3139678Slinton  * Push the value associated with the current function.
3149678Slinton  */
3159678Slinton 
3169678Slinton public pushretval(len, isindirect)
31718231Slinton integer len;
31818231Slinton boolean isindirect;
3199678Slinton {
3209678Slinton     Word r0;
3219678Slinton 
3229678Slinton     r0 = reg(0);
3239678Slinton     if (isindirect) {
3249678Slinton 	rpush((Address) r0, len);
3259678Slinton     } else {
3269678Slinton 	switch (len) {
3279678Slinton 	    case sizeof(char):
3289678Slinton 		push(char, r0);
3299678Slinton 		break;
3309678Slinton 
3319678Slinton 	    case sizeof(short):
3329678Slinton 		push(short, r0);
3339678Slinton 		break;
3349678Slinton 
3359678Slinton 	    default:
3369678Slinton 		if (len == sizeof(Word)) {
3379678Slinton 		    push(Word, r0);
3389678Slinton 		} else if (len == 2*sizeof(Word)) {
3399678Slinton 		    push(Word, r0);
3409678Slinton 		    push(Word, reg(1));
3419678Slinton 		} else {
34218231Slinton 		    error("[internal error: bad size %d in pushretval]", len);
3439678Slinton 		}
3449678Slinton 		break;
3459678Slinton 	}
3469678Slinton     }
3479678Slinton }
3489678Slinton 
3499678Slinton /*
3509678Slinton  * Return the base address for locals in the given frame.
3519678Slinton  */
3529678Slinton 
3539678Slinton public Address locals_base(frp)
35418231Slinton Frame frp;
3559678Slinton {
3569678Slinton     return (frp == nil) ? reg(FRP) : frp->save_fp;
3579678Slinton }
3589678Slinton 
3599678Slinton /*
3609678Slinton  * Return the base address for arguments in the given frame.
3619678Slinton  */
3629678Slinton 
3639678Slinton public Address args_base(frp)
36418231Slinton Frame frp;
3659678Slinton {
3669678Slinton     return (frp == nil) ? reg(ARGP) : frp->save_ap;
3679678Slinton }
3689678Slinton 
3699678Slinton /*
3709678Slinton  * Return saved register n from the given frame.
3719678Slinton  */
3729678Slinton 
3739678Slinton public Word savereg(n, frp)
37418231Slinton integer n;
37518231Slinton Frame frp;
3769678Slinton {
37718231Slinton     Word w;
3789678Slinton 
3799678Slinton     if (frp == nil) {
3809678Slinton 	w = reg(n);
3819678Slinton     } else {
3829678Slinton 	switch (n) {
3839678Slinton 	    case ARGP:
3849678Slinton 		w = frp->save_ap;
3859678Slinton 		break;
3869678Slinton 
3879678Slinton 	    case FRP:
3889678Slinton 		w = frp->save_fp;
3899678Slinton 		break;
3909678Slinton 
3919678Slinton 	    case STKP:
3929678Slinton 		w = reg(STKP);
3939678Slinton 		break;
3949678Slinton 
3959678Slinton 	    case PROGCTR:
3969678Slinton 		w = frp->save_pc;
3979678Slinton 		break;
3989678Slinton 
3999678Slinton 	    default:
4009678Slinton 		assert(n >= 0 and n < NSAVEREG);
4019678Slinton 		w = frp->save_reg[n];
4029678Slinton 		break;
4039678Slinton 	}
4049678Slinton     }
4059678Slinton     return w;
4069678Slinton }
4079678Slinton 
4089678Slinton /*
4099678Slinton  * Return the nth argument to the current procedure.
4109678Slinton  */
4119678Slinton 
4129678Slinton public Word argn(n, frp)
41318231Slinton integer n;
4149678Slinton Frame frp;
4159678Slinton {
41633334Sdonn     Address argaddr;
4179678Slinton     Word w;
4189678Slinton 
41933334Sdonn     argaddr = args_base(frp) + (n * sizeof(Word));
42033334Sdonn     dread(&w, argaddr, sizeof(w));
4219678Slinton     return w;
4229678Slinton }
4239678Slinton 
4249678Slinton /*
42518231Slinton  * Print a list of currently active blocks starting with most recent.
4269678Slinton  */
4279678Slinton 
42818231Slinton public wherecmd()
4299678Slinton {
43018231Slinton     walkstack(false);
4319678Slinton }
4329678Slinton 
4339678Slinton /*
43418231Slinton  * Print the variables in the given frame or the current one if nil.
4359678Slinton  */
4369678Slinton 
43718231Slinton public dump (func)
43818231Slinton Symbol func;
4399678Slinton {
44018231Slinton     Symbol f;
44118231Slinton     Frame frp;
44218231Slinton 
44318231Slinton     if (func == nil) {
44418231Slinton 	f = curfunc;
44518231Slinton 	if (curframe != nil) {
44618231Slinton 	    frp = curframe;
44718231Slinton 	} else {
44818231Slinton 	    frp = findframe(f);
44918231Slinton 	}
45018231Slinton     } else {
45118231Slinton 	f = func;
45218231Slinton 	frp = findframe(f);
45318231Slinton     }
45418231Slinton     showaggrs = true;
45518231Slinton     printcallinfo(f, frp);
45618231Slinton     dumpvars(f, frp);
4579678Slinton }
4589678Slinton 
4599678Slinton /*
46018231Slinton  * Dump all values.
4619678Slinton  */
4629678Slinton 
46318231Slinton public dumpall ()
4649678Slinton {
4659678Slinton     walkstack(true);
4669678Slinton }
4679678Slinton 
4689678Slinton /*
4699678Slinton  * Walk the stack of active procedures printing information
4709678Slinton  * about each active procedure.
4719678Slinton  */
4729678Slinton 
4739678Slinton private walkstack(dumpvariables)
4749678Slinton Boolean dumpvariables;
4759678Slinton {
47618231Slinton     Frame frp;
47718231Slinton     boolean save;
47816618Ssam     Symbol f;
4799678Slinton     struct Frame frame;
4809678Slinton 
48118231Slinton     if (notstarted(process) or isfinished(process)) {
4829678Slinton 	error("program is not active");
4839678Slinton     } else {
4849678Slinton 	save = walkingstack;
4859678Slinton 	walkingstack = true;
48618231Slinton 	showaggrs = dumpvariables;
4879678Slinton 	frp = &frame;
48816618Ssam 	getcurfunc(frp, &f);
48918231Slinton 	for (;;) {
49018231Slinton 	    printcallinfo(f, frp);
4919678Slinton 	    if (dumpvariables) {
4929678Slinton 		dumpvars(f, frp);
4939678Slinton 		putchar('\n');
4949678Slinton 	    }
49516618Ssam 	    frp = nextfunc(frp, &f);
49618231Slinton 	    if (frp == nil or f == program) {
49718231Slinton 		break;
49818231Slinton 	    }
49918231Slinton 	}
5009678Slinton 	if (dumpvariables) {
5019678Slinton 	    printf("in \"%s\":\n", symname(program));
5029678Slinton 	    dumpvars(program, nil);
5039678Slinton 	    putchar('\n');
5049678Slinton 	}
5059678Slinton 	walkingstack = save;
5069678Slinton     }
5079678Slinton }
5089678Slinton 
5099678Slinton /*
51018231Slinton  * Print out the information about a call, i.e.,
51118231Slinton  * routine name, parameter values, and source location.
51218231Slinton  */
51318231Slinton 
51418231Slinton private printcallinfo (f, frp)
51518231Slinton Symbol f;
51618231Slinton Frame frp;
51718231Slinton {
51818231Slinton     Lineno line;
51918231Slinton     Address savepc;
52018231Slinton 
52118231Slinton     savepc = frp->save_pc;
52218231Slinton     if (frp->save_fp != reg(FRP)) {
52318231Slinton 	savepc -= 1;
52418231Slinton     }
52518231Slinton     printname(stdout, f);
52618231Slinton     if (not isinline(f)) {
52718231Slinton 	printparams(f, frp);
52818231Slinton     }
52918231Slinton     line = srcline(savepc);
53018231Slinton     if (line != 0) {
53118231Slinton 	printf(", line %d", line);
53218231Slinton 	printf(" in \"%s\"\n", srcfilename(savepc));
53318231Slinton     } else {
53418231Slinton 	printf(" at 0x%x\n", savepc);
53518231Slinton     }
53618231Slinton }
53718231Slinton 
53818231Slinton /*
53916618Ssam  * Set the current function to the given symbol.
54016618Ssam  * We must adjust "curframe" so that subsequent operations are
54116618Ssam  * not confused; for simplicity we simply clear it.
54216618Ssam  */
54316618Ssam 
54416618Ssam public setcurfunc (f)
54516618Ssam Symbol f;
54616618Ssam {
54716618Ssam     curfunc = f;
54816618Ssam     curframe = nil;
54916618Ssam }
55016618Ssam 
55116618Ssam /*
55218231Slinton  * Return the frame for the current function.
55318231Slinton  * The space for the frame is allocated statically.
55418231Slinton  */
55518231Slinton 
55618231Slinton public Frame curfuncframe ()
55718231Slinton {
55818231Slinton     static struct Frame frame;
55918231Slinton     Frame frp;
56018231Slinton 
56118231Slinton     if (curframe == nil) {
56218231Slinton 	frp = findframe(curfunc);
56318231Slinton 	curframe = &curframerec;
56418231Slinton 	*curframe = *frp;
56518231Slinton     } else {
56618231Slinton 	frp = &frame;
56718231Slinton 	*frp = *curframe;
56818231Slinton     }
56918231Slinton     return frp;
57018231Slinton }
57118231Slinton 
57218231Slinton /*
57316618Ssam  * Set curfunc to be N up/down the stack from its current value.
57416618Ssam  */
57516618Ssam 
57616618Ssam public up (n)
57716618Ssam integer n;
57816618Ssam {
57916618Ssam     integer i;
58016618Ssam     Symbol f;
58116618Ssam     Frame frp;
58216618Ssam     boolean done;
58316618Ssam 
58416618Ssam     if (not isactive(program)) {
58516618Ssam 	error("program is not active");
58616618Ssam     } else if (curfunc == nil) {
58716618Ssam 	error("no current function");
58816618Ssam     } else {
58916618Ssam 	i = 0;
59016618Ssam 	f = curfunc;
59118231Slinton 	frp = curfuncframe();
59216618Ssam 	done = false;
59316618Ssam 	do {
59416618Ssam 	    if (frp == nil) {
59516618Ssam 		done = true;
59616618Ssam 		error("not that many levels");
59716618Ssam 	    } else if (i >= n) {
59816618Ssam 		done = true;
59916618Ssam 		curfunc = f;
60016618Ssam 		curframe = &curframerec;
60116618Ssam 		*curframe = *frp;
60218231Slinton 		showaggrs = false;
60318231Slinton 		printcallinfo(curfunc, curframe);
60416618Ssam 	    } else if (f == program) {
60516618Ssam 		done = true;
60616618Ssam 		error("not that many levels");
60716618Ssam 	    } else {
60816618Ssam 		frp = nextfunc(frp, &f);
60916618Ssam 	    }
61016618Ssam 	    ++i;
61116618Ssam 	} while (not done);
61216618Ssam     }
61316618Ssam }
61416618Ssam 
61516618Ssam public down (n)
61616618Ssam integer n;
61716618Ssam {
61816618Ssam     integer i, depth;
61918231Slinton     Frame frp, curfrp;
62016618Ssam     Symbol f;
62116618Ssam     struct Frame frame;
62216618Ssam 
62316618Ssam     if (not isactive(program)) {
62416618Ssam 	error("program is not active");
62516618Ssam     } else if (curfunc == nil) {
62616618Ssam 	error("no current function");
62716618Ssam     } else {
62816618Ssam 	depth = 0;
62916618Ssam 	frp = &frame;
63016618Ssam 	getcurfunc(frp, &f);
63116618Ssam 	if (curframe == nil) {
63218231Slinton 	    curfrp = findframe(curfunc);
63316618Ssam 	    curframe = &curframerec;
63418231Slinton 	    *curframe = *curfrp;
63516618Ssam 	}
63616618Ssam 	while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) {
63716618Ssam 	    frp = nextfunc(frp, &f);
63816618Ssam 	    ++depth;
63916618Ssam 	}
64016618Ssam 	if (f == nil or n > depth) {
64116618Ssam 	    error("not that many levels");
64216618Ssam 	} else {
64316618Ssam 	    depth -= n;
64416618Ssam 	    frp = &frame;
64516618Ssam 	    getcurfunc(frp, &f);
64616618Ssam 	    for (i = 0; i < depth; i++) {
64716618Ssam 		frp = nextfunc(frp, &f);
64816618Ssam 		assert(frp != nil);
64916618Ssam 	    }
65016618Ssam 	    curfunc = f;
65116618Ssam 	    *curframe = *frp;
65218231Slinton 	    showaggrs = false;
65318231Slinton 	    printcallinfo(curfunc, curframe);
65416618Ssam 	}
65516618Ssam     }
65616618Ssam }
65716618Ssam 
65816618Ssam /*
6599678Slinton  * Find the entry point of a procedure or function.
66033334Sdonn  *
66133334Sdonn  * On the VAX we add the size of the register mask (FUNCOFFSET) or
66233334Sdonn  * the size of the Modula-2 internal entry sequence, on other machines
66333334Sdonn  * (68000's) we add the entry sequence size (FUNCOFFSET) unless
66433334Sdonn  * we're right at the beginning of the program.
6659678Slinton  */
6669678Slinton 
66718231Slinton public findbeginning (f)
6689678Slinton Symbol f;
6699678Slinton {
67016618Ssam     if (isinternal(f)) {
67133334Sdonn 	f->symvalue.funcv.beginaddr += 18;	/* VAX only */
67216618Ssam     } else {
67333334Sdonn 	f->symvalue.funcv.beginaddr += FUNCOFFSET;
67416618Ssam     }
6759678Slinton }
6769678Slinton 
6779678Slinton /*
6789678Slinton  * Return the address corresponding to the first line in a function.
6799678Slinton  */
6809678Slinton 
6819678Slinton public Address firstline(f)
6829678Slinton Symbol f;
6839678Slinton {
6849678Slinton     Address addr;
6859678Slinton 
6869678Slinton     addr = codeloc(f);
6879678Slinton     while (linelookup(addr) == 0 and addr < objsize) {
6889678Slinton 	++addr;
6899678Slinton     }
6909678Slinton     if (addr == objsize) {
6919678Slinton 	addr = -1;
6929678Slinton     }
6939678Slinton     return addr;
6949678Slinton }
6959678Slinton 
6969678Slinton /*
6979678Slinton  * Catcher drops strike three ...
6989678Slinton  */
6999678Slinton 
7009678Slinton public runtofirst()
7019678Slinton {
70233334Sdonn     Address addr, endaddr;
7039678Slinton 
7049678Slinton     addr = pc;
70533334Sdonn     endaddr = objsize + CODESTART;
70633334Sdonn     while (linelookup(addr) == 0 and addr < endaddr) {
7079678Slinton 	++addr;
7089678Slinton     }
70933334Sdonn     if (addr < endaddr) {
7109678Slinton 	stepto(addr);
7119678Slinton     }
7129678Slinton }
7139678Slinton 
7149678Slinton /*
7159678Slinton  * Return the address corresponding to the end of the program.
7169678Slinton  *
7179678Slinton  * We look for the entry to "exit".
7189678Slinton  */
7199678Slinton 
7209678Slinton public Address lastaddr()
7219678Slinton {
72218231Slinton     Symbol s;
7239678Slinton 
7249678Slinton     s = lookup(identname("exit", true));
7259678Slinton     if (s == nil) {
7269678Slinton 	panic("can't find exit");
7279678Slinton     }
7289678Slinton     return codeloc(s);
7299678Slinton }
7309678Slinton 
7319678Slinton /*
7329678Slinton  * Decide if the given function is currently active.
7339678Slinton  *
7349678Slinton  * We avoid calls to "findframe" during a stack trace for efficiency.
7359678Slinton  * Presumably information evaluated while walking the stack is active.
7369678Slinton  */
7379678Slinton 
73833334Sdonn public Boolean isactive (f)
7399678Slinton Symbol f;
7409678Slinton {
74118231Slinton     Boolean b;
7429678Slinton 
7439678Slinton     if (isfinished(process)) {
7449678Slinton 	b = false;
7459678Slinton     } else {
74633334Sdonn 	if (walkingstack or f == program or f == nil or
7479678Slinton 	  (ismodule(f) and isactive(container(f)))) {
7489678Slinton 	    b = true;
7499678Slinton 	} else {
7509678Slinton 	    b = (Boolean) (findframe(f) != nil);
7519678Slinton 	}
7529678Slinton     }
7539678Slinton     return b;
7549678Slinton }
7559678Slinton 
7569678Slinton /*
7579678Slinton  * Evaluate a call to a procedure.
7589678Slinton  */
7599678Slinton 
76018231Slinton public callproc(exprnode, isfunc)
76118231Slinton Node exprnode;
76218231Slinton boolean isfunc;
7639678Slinton {
76418231Slinton     Node procnode, arglist;
7659678Slinton     Symbol proc;
76618231Slinton     integer argc;
7679678Slinton 
76818231Slinton     procnode = exprnode->value.arg[0];
76918231Slinton     arglist = exprnode->value.arg[1];
7709678Slinton     if (procnode->op != O_SYM) {
7719678Slinton 	beginerrmsg();
7729678Slinton 	fprintf(stderr, "can't call \"");
7739678Slinton 	prtree(stderr, procnode);
7749678Slinton 	fprintf(stderr, "\"");
7759678Slinton 	enderrmsg();
7769678Slinton     }
7779678Slinton     assert(procnode->op == O_SYM);
7789678Slinton     proc = procnode->value.sym;
7799678Slinton     if (not isblock(proc)) {
7809678Slinton 	error("\"%s\" is not a procedure or function", symname(proc));
7819678Slinton     }
78218231Slinton     endproc.isfunc = isfunc;
78318231Slinton     endproc.callnode = exprnode;
78418231Slinton     endproc.cmdnode = topnode;
7859678Slinton     pushenv();
7869678Slinton     pc = codeloc(proc);
7879678Slinton     argc = pushargs(proc, arglist);
78833334Sdonn     setreg(FRP, 1);	/* have to ensure it's non-zero for return_addr() */
7899678Slinton     beginproc(proc, argc);
79018231Slinton     event_once(
79118231Slinton 	build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)),
79218231Slinton 	buildcmdlist(build(O_PROCRTN, proc))
79318231Slinton     );
79418231Slinton     isstopped = false;
79518231Slinton     if (not bpact()) {
79618231Slinton 	isstopped = true;
79718231Slinton 	cont(0);
79818231Slinton     }
79918231Slinton     /*
80018231Slinton      * bpact() won't return true, it will call printstatus() and go back
80118231Slinton      * to command input if a breakpoint is found.
80218231Slinton      */
8039678Slinton     /* NOTREACHED */
8049678Slinton }
8059678Slinton 
8069678Slinton /*
8079678Slinton  * Push the arguments on the process' stack.  We do this by first
8089678Slinton  * evaluating them on the "eval" stack, then copying into the process'
8099678Slinton  * space.
8109678Slinton  */
8119678Slinton 
81218231Slinton private integer pushargs(proc, arglist)
8139678Slinton Symbol proc;
8149678Slinton Node arglist;
8159678Slinton {
8169678Slinton     Stack *savesp;
8179678Slinton     int argc, args_size;
8189678Slinton 
8199678Slinton     savesp = sp;
82026324Ssam     if (varIsSet("$unsafecall")) {
82126324Ssam 	argc = unsafe_evalargs(proc, arglist);
82226324Ssam     } else {
82326324Ssam 	argc = evalargs(proc, arglist);
82426324Ssam     }
8259678Slinton     args_size = sp - savesp;
8269678Slinton     setreg(STKP, reg(STKP) - args_size);
8279678Slinton     dwrite(savesp, reg(STKP), args_size);
8289678Slinton     sp = savesp;
8299678Slinton     return argc;
8309678Slinton }
8319678Slinton 
8329678Slinton /*
83316618Ssam  * Check to see if an expression is correct for a given parameter.
83416618Ssam  * If the given parameter is false, don't worry about type inconsistencies.
83516618Ssam  *
83616618Ssam  * Return whether or not it is ok.
8379678Slinton  */
8389678Slinton 
83916618Ssam private boolean chkparam (actual, formal, chk)
84016618Ssam Node actual;
84116618Ssam Symbol formal;
84216618Ssam boolean chk;
84316618Ssam {
84416618Ssam     boolean b;
84516618Ssam 
84616618Ssam     b = true;
84716618Ssam     if (chk) {
84816618Ssam 	if (formal == nil) {
84916618Ssam 	    beginerrmsg();
85016618Ssam 	    fprintf(stderr, "too many parameters");
85116618Ssam 	    b = false;
85216618Ssam 	} else if (not compatible(formal->type, actual->nodetype)) {
85316618Ssam 	    beginerrmsg();
85416618Ssam 	    fprintf(stderr, "type mismatch for %s", symname(formal));
85516618Ssam 	    b = false;
85616618Ssam 	}
85716618Ssam     }
85818231Slinton     if (b and formal != nil and
85918231Slinton 	isvarparam(formal) and not isopenarray(formal->type) and
86018231Slinton 	not (
86118231Slinton 	    actual->op == O_RVAL or actual->nodetype == t_addr or
86218231Slinton 	    (
86318231Slinton 		actual->op == O_TYPERENAME and
86418231Slinton 		(
86518231Slinton 		    actual->value.arg[0]->op == O_RVAL or
86618231Slinton 		    actual->value.arg[0]->nodetype == t_addr
86718231Slinton 		)
86818231Slinton 	    )
86918231Slinton 	)
87018231Slinton     ) {
87116618Ssam 	beginerrmsg();
87216618Ssam 	fprintf(stderr, "expected variable, found \"");
87316618Ssam 	prtree(stderr, actual);
87416618Ssam 	fprintf(stderr, "\"");
87516618Ssam 	b = false;
87616618Ssam     }
87716618Ssam     return b;
87816618Ssam }
87916618Ssam 
88016618Ssam /*
88116618Ssam  * Pass an expression to a particular parameter.
88216618Ssam  *
88316618Ssam  * Normally we pass either the address or value, but in some cases
88416618Ssam  * (such as C strings) we want to copy the value onto the stack and
88516618Ssam  * pass its address.
88618231Slinton  *
88718231Slinton  * Another special case raised by strings is the possibility that
88818231Slinton  * the actual parameter will be larger than the formal, even with
88918231Slinton  * appropriate type-checking.  This occurs because we assume during
89018231Slinton  * evaluation that strings are null-terminated, whereas some languages,
89118231Slinton  * notably Pascal, do not work under that assumption.
89216618Ssam  */
89316618Ssam 
89416618Ssam private passparam (actual, formal)
89516618Ssam Node actual;
89616618Ssam Symbol formal;
89716618Ssam {
89816618Ssam     boolean b;
89916618Ssam     Address addr;
90016618Ssam     Stack *savesp;
90118231Slinton     integer actsize, formsize;
90216618Ssam 
90318231Slinton     if (formal != nil and isvarparam(formal) and
90418231Slinton 	(not isopenarray(formal->type))
90518231Slinton     ) {
90616618Ssam 	addr = lval(actual->value.arg[0]);
90716618Ssam 	push(Address, addr);
90816618Ssam     } else if (passaddr(formal, actual->nodetype)) {
90916618Ssam 	savesp = sp;
91016618Ssam 	eval(actual);
91118231Slinton 	actsize = sp - savesp;
91218231Slinton 	setreg(STKP,
91318231Slinton 	    reg(STKP) - ((actsize + sizeof(Word) - 1) & ~(sizeof(Word) - 1))
91418231Slinton 	);
91518231Slinton 	dwrite(savesp, reg(STKP), actsize);
91616618Ssam 	sp = savesp;
91716618Ssam 	push(Address, reg(STKP));
91816618Ssam 	if (formal != nil and isopenarray(formal->type)) {
91918231Slinton 	    push(integer, actsize div size(formal->type->type));
92016618Ssam 	}
92118231Slinton     } else if (formal != nil) {
92218231Slinton 	formsize = size(formal);
92318231Slinton 	savesp = sp;
92418231Slinton 	eval(actual);
92518231Slinton 	actsize = sp - savesp;
92618231Slinton 	if (actsize > formsize) {
92718231Slinton 	    sp -= (actsize - formsize);
92818231Slinton 	}
92916618Ssam     } else {
93016618Ssam 	eval(actual);
93116618Ssam     }
93216618Ssam }
93316618Ssam 
93416618Ssam /*
93516618Ssam  * Evaluate an argument list left-to-right.
93616618Ssam  */
93716618Ssam 
93818231Slinton private integer evalargs(proc, arglist)
9399678Slinton Symbol proc;
9409678Slinton Node arglist;
9419678Slinton {
94216618Ssam     Node p, actual;
94316618Ssam     Symbol formal;
9449678Slinton     Stack *savesp;
94518231Slinton     integer count;
94616618Ssam     boolean chk;
9479678Slinton 
9489678Slinton     savesp = sp;
9499678Slinton     count = 0;
95016618Ssam     formal = proc->chain;
95116618Ssam     chk = (boolean) (not nosource(proc));
9529678Slinton     for (p = arglist; p != nil; p = p->value.arg[1]) {
95316618Ssam 	assert(p->op == O_COMMA);
95416618Ssam 	actual = p->value.arg[0];
95516618Ssam 	if (not chkparam(actual, formal, chk)) {
95616618Ssam 	    fprintf(stderr, " in call to %s", symname(proc));
9579678Slinton 	    sp = savesp;
95816618Ssam 	    enderrmsg();
9599678Slinton 	}
96016618Ssam 	passparam(actual, formal);
96116618Ssam 	if (formal != nil) {
96216618Ssam 	    formal = formal->chain;
9639678Slinton 	}
9649678Slinton 	++count;
9659678Slinton     }
96616618Ssam     if (chk) {
96716618Ssam 	if (formal != nil) {
96816618Ssam 	    sp = savesp;
96916618Ssam 	    error("not enough parameters to %s", symname(proc));
97016618Ssam 	}
9719678Slinton     }
9729678Slinton     return count;
9739678Slinton }
9749678Slinton 
97526324Ssam /*
97633334Sdonn  * Evaluate an argument list without any type checking.
97733334Sdonn  * This is only useful for procedures with a varying number of
97833334Sdonn  * arguments that are compiled -g.
97926324Ssam  */
98026324Ssam 
98133334Sdonn private integer unsafe_evalargs (proc, arglist)
98226324Ssam Symbol proc;
98326324Ssam Node arglist;
98426324Ssam {
98526324Ssam     Node p;
98633334Sdonn     integer count;
98726324Ssam 
98826324Ssam     count = 0;
98926324Ssam     for (p = arglist; p != nil; p = p->value.arg[1]) {
99026324Ssam 	assert(p->op == O_COMMA);
99126324Ssam 	eval(p->value.arg[0]);
99226324Ssam 	++count;
99326324Ssam     }
99426324Ssam     return count;
99526324Ssam }
99626324Ssam 
9979678Slinton public procreturn(f)
9989678Slinton Symbol f;
9999678Slinton {
100018231Slinton     integer retvalsize;
100118231Slinton     Node tmp;
100218231Slinton     char *copy;
100318231Slinton 
10049678Slinton     flushoutput();
10059678Slinton     popenv();
100618231Slinton     if (endproc.isfunc) {
100718231Slinton 	retvalsize = size(f->type);
100818231Slinton 	if (retvalsize > sizeof(long)) {
100918231Slinton 	    pushretval(retvalsize, true);
101018231Slinton 	    copy = newarr(char, retvalsize);
101118231Slinton 	    popn(retvalsize, copy);
101218231Slinton 	    tmp = build(O_SCON, copy);
101318231Slinton 	} else {
101418231Slinton 	    tmp = build(O_LCON, (long) (reg(0)));
101518231Slinton 	}
101618231Slinton 	tmp->nodetype = f->type;
101718231Slinton 	tfree(endproc.callnode);
101818231Slinton 	*(endproc.callnode) = *(tmp);
101918231Slinton 	dispose(tmp);
102018231Slinton 	eval(endproc.cmdnode);
102118231Slinton     } else {
102218231Slinton 	putchar('\n');
102318231Slinton 	printname(stdout, f);
102433334Sdonn 	printf(" returns successfully\n");
102518231Slinton     }
10269678Slinton     erecover();
10279678Slinton }
10289678Slinton 
10299678Slinton /*
10309678Slinton  * Push the current environment.
10319678Slinton  */
10329678Slinton 
10339678Slinton private pushenv()
10349678Slinton {
10359678Slinton     push(Address, pc);
10369678Slinton     push(Lineno, curline);
10379678Slinton     push(String, cursource);
10389678Slinton     push(Boolean, isstopped);
10399678Slinton     push(Symbol, curfunc);
104016618Ssam     push(Frame, curframe);
104116618Ssam     push(struct Frame, curframerec);
104218231Slinton     push(CallEnv, endproc);
10439678Slinton     push(Word, reg(PROGCTR));
10449678Slinton     push(Word, reg(STKP));
104533334Sdonn     push(Word, reg(FRP));
10469678Slinton }
10479678Slinton 
10489678Slinton /*
10499678Slinton  * Pop back to the real world.
10509678Slinton  */
10519678Slinton 
10529678Slinton public popenv()
10539678Slinton {
105418231Slinton     String filename;
10559678Slinton 
105633334Sdonn     setreg(FRP, pop(Word));
10579678Slinton     setreg(STKP, pop(Word));
10589678Slinton     setreg(PROGCTR, pop(Word));
105918231Slinton     endproc = pop(CallEnv);
106016618Ssam     curframerec = pop(struct Frame);
106116618Ssam     curframe = pop(Frame);
10629678Slinton     curfunc = pop(Symbol);
10639678Slinton     isstopped = pop(Boolean);
10649678Slinton     filename = pop(String);
10659678Slinton     curline = pop(Lineno);
10669678Slinton     pc = pop(Address);
10679678Slinton     setsource(filename);
10689678Slinton }
10699678Slinton 
10709678Slinton /*
10719678Slinton  * Flush the debuggee's standard output.
10729678Slinton  *
10739678Slinton  * This is VERY dependent on the use of stdio.
10749678Slinton  */
10759678Slinton 
10769678Slinton public flushoutput()
10779678Slinton {
107818231Slinton     Symbol p, iob;
107918231Slinton     Stack *savesp;
10809678Slinton 
10819678Slinton     p = lookup(identname("fflush", true));
10829678Slinton     while (p != nil and not isblock(p)) {
10839678Slinton 	p = p->next_sym;
10849678Slinton     }
10859678Slinton     if (p != nil) {
10869678Slinton 	iob = lookup(identname("_iob", true));
10879678Slinton 	if (iob != nil) {
10889678Slinton 	    pushenv();
108933334Sdonn 	    pc = codeloc(p) - FUNCOFFSET;
10909678Slinton 	    savesp = sp;
109133334Sdonn 	    push(long, address(iob, nil) + sizeof(*stdout));
10929678Slinton 	    setreg(STKP, reg(STKP) - sizeof(long));
10939678Slinton 	    dwrite(savesp, reg(STKP), sizeof(long));
10949678Slinton 	    sp = savesp;
10959678Slinton 	    beginproc(p, 1);
10969678Slinton 	    stepto(return_addr());
10979678Slinton 	    popenv();
10989678Slinton 	}
10999678Slinton     }
11009678Slinton }
1101