xref: /original-bsd/old/dbx/runtime.iris.c (revision 5540d668)
184a342e9Sdonn /*
2be26f981Sbostic  * Copyright (c) 1983 The Regents of the University of California.
3be26f981Sbostic  * All rights reserved.
4be26f981Sbostic  *
5*5540d668Sbostic  * %sccs.include.redist.c%
684a342e9Sdonn  */
784a342e9Sdonn 
884a342e9Sdonn #ifndef lint
9*5540d668Sbostic static char sccsid[] = "@(#)runtime.iris.c	5.3 (Berkeley) 06/01/90";
10be26f981Sbostic #endif /* not lint */
1184a342e9Sdonn 
1284a342e9Sdonn /*
1384a342e9Sdonn  * Runtime organization dependent routines, mostly dealing with
1484a342e9Sdonn  * activation records.
1584a342e9Sdonn  */
1684a342e9Sdonn 
1784a342e9Sdonn #include "defs.h"
1884a342e9Sdonn #include "runtime.h"
1984a342e9Sdonn #include "process.h"
2084a342e9Sdonn #include "machine.h"
2184a342e9Sdonn #include "events.h"
2284a342e9Sdonn #include "mappings.h"
2384a342e9Sdonn #include "symbols.h"
2484a342e9Sdonn #include "tree.h"
2584a342e9Sdonn #include "eval.h"
2684a342e9Sdonn #include "operators.h"
2784a342e9Sdonn #include "object.h"
2884a342e9Sdonn #include <sys/param.h>
2984a342e9Sdonn #include <signal.h>
3084a342e9Sdonn 
3184a342e9Sdonn #ifndef public
3284a342e9Sdonn typedef struct Frame *Frame;
3384a342e9Sdonn 
3484a342e9Sdonn #include "machine.h"
3584a342e9Sdonn #endif
3684a342e9Sdonn 
3784a342e9Sdonn #define NSAVEREG 14
3884a342e9Sdonn 
3984a342e9Sdonn struct Frame {
4084a342e9Sdonn     Address save_fp;		/* frame pointer */
4184a342e9Sdonn     Address save_pc;		/* program counter */
4284a342e9Sdonn     Word save_reg[NSAVEREG];	/* not necessarily there */
4384a342e9Sdonn     integer nargwords;		/* computed, not stored */
4484a342e9Sdonn };
4584a342e9Sdonn 
4684a342e9Sdonn private Frame curframe = nil;
4784a342e9Sdonn private struct Frame curframerec;
4884a342e9Sdonn private Boolean walkingstack = false;
4984a342e9Sdonn 
5084a342e9Sdonn #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp)
5184a342e9Sdonn 
inSignalHandler(addr)5284a342e9Sdonn private boolean inSignalHandler (addr)
5384a342e9Sdonn Address addr;
5484a342e9Sdonn {
5584a342e9Sdonn     Symbol f;
5684a342e9Sdonn 
5784a342e9Sdonn #ifdef IRIS
5884a342e9Sdonn     return false;
5984a342e9Sdonn #else /* sun */
6084a342e9Sdonn     f = whatblock(addr);
6184a342e9Sdonn     return (boolean) (f != nil and streq(symname(f), "_sigtramp"));
6284a342e9Sdonn #endif
6384a342e9Sdonn }
6484a342e9Sdonn 
6584a342e9Sdonn typedef struct {
6684a342e9Sdonn     Node callnode;
6784a342e9Sdonn     Node cmdnode;
6884a342e9Sdonn     boolean isfunc;
6984a342e9Sdonn } CallEnv;
7084a342e9Sdonn 
7184a342e9Sdonn private CallEnv endproc;
7284a342e9Sdonn 
7384a342e9Sdonn /*
7484a342e9Sdonn  * Set a frame to the current activation record.
7584a342e9Sdonn  */
7684a342e9Sdonn 
getcurframe(frp)7784a342e9Sdonn private getcurframe(frp)
7884a342e9Sdonn Frame frp;
7984a342e9Sdonn {
8084a342e9Sdonn     register int i;
8184a342e9Sdonn 
8284a342e9Sdonn     checkref(frp);
8384a342e9Sdonn     frp->save_fp = reg(FRP);
8484a342e9Sdonn     frp->save_pc = reg(PROGCTR);
8584a342e9Sdonn     for (i = 0; i < NSAVEREG; i++) {
8684a342e9Sdonn 	frp->save_reg[i] = reg(i);
8784a342e9Sdonn     }
8884a342e9Sdonn     if (frp->save_fp == nil) {
8984a342e9Sdonn 	frp->nargwords = 0;
9084a342e9Sdonn     } else {
9184a342e9Sdonn 	findnumargs(frp);
9284a342e9Sdonn     }
9384a342e9Sdonn }
9484a342e9Sdonn 
9584a342e9Sdonn /*
9684a342e9Sdonn  * Get the saved registers from one frame to another
9784a342e9Sdonn  * given mask specifying which registers were actually saved.
9884a342e9Sdonn  */
9984a342e9Sdonn 
10084a342e9Sdonn #define bis(b, n) ((b & (1 << (n))) != 0)
10184a342e9Sdonn 
getsaveregs(newfrp,frp,mask)10284a342e9Sdonn private getsaveregs (newfrp, frp, mask)
10384a342e9Sdonn Frame newfrp, frp;
10484a342e9Sdonn integer mask;
10584a342e9Sdonn {
10684a342e9Sdonn     integer i, j;
10784a342e9Sdonn 
10884a342e9Sdonn     j = 0;
10984a342e9Sdonn     for (i = 0; i < NSAVEREG; i++) {
11084a342e9Sdonn 	if (bis(mask, i)) {
11184a342e9Sdonn 	    newfrp->save_reg[i] = frp->save_reg[j];
11284a342e9Sdonn 	    ++j;
11384a342e9Sdonn 	}
11484a342e9Sdonn     }
11584a342e9Sdonn }
11684a342e9Sdonn 
11784a342e9Sdonn /*
11884a342e9Sdonn  * Return a pointer to the next activation record up the stack.
11984a342e9Sdonn  * Return nil if there is none.
12084a342e9Sdonn  * Writes over space pointed to by given argument.
12184a342e9Sdonn  */
12284a342e9Sdonn 
nextframe(frp)12384a342e9Sdonn private Frame nextframe(frp)
12484a342e9Sdonn Frame frp;
12584a342e9Sdonn {
12684a342e9Sdonn     Frame newfrp;
12784a342e9Sdonn     struct Frame frame;
12884a342e9Sdonn     integer mask;
12984a342e9Sdonn     Address prev_frame, callpc, higher_fp, higher_pc;
13084a342e9Sdonn     static integer ntramp = 0;
13184a342e9Sdonn 
13284a342e9Sdonn     newfrp = frp;
13384a342e9Sdonn     prev_frame = frp->save_fp;
13484a342e9Sdonn 
13584a342e9Sdonn /*
13684a342e9Sdonn  *  The check for interrupt generated frames is taken from adb with only
13784a342e9Sdonn  *  partial understanding.  If you're in "sub" and on a sigxxx "sigsub"
13884a342e9Sdonn  *  gets control, then the stack does NOT look like <main, sub, sigsub>.
13984a342e9Sdonn  *
14084a342e9Sdonn  *  As best I can make out it looks like:
14184a342e9Sdonn  *
14284a342e9Sdonn  *     <main, (machine check exception block + sub), sysframe, sigsub>.
14384a342e9Sdonn  *
14484a342e9Sdonn  *  When the signal occurs an exception block and a frame for the routine
14584a342e9Sdonn  *  in which it occured are pushed on the user stack.  Then another frame
14684a342e9Sdonn  *  is pushed corresponding to a call from the kernel to sigsub.
14784a342e9Sdonn  *
14884a342e9Sdonn  *  The addr in sub at which the exception occured is not in sub.save_pc
14984a342e9Sdonn  *  but in the machine check exception block.  It is at the magic address
15084a342e9Sdonn  *  fp + 84.
15184a342e9Sdonn  *
15284a342e9Sdonn  *  The current approach ignores the sys_frame (what adb reports as sigtramp)
15384a342e9Sdonn  *  and takes the pc for sub from the exception block.  This allows the
15484a342e9Sdonn  *  "where" command to report <main, sub, sigsub>, which seems reasonable.
15584a342e9Sdonn  */
15684a342e9Sdonn 
15784a342e9Sdonn nextf:
15884a342e9Sdonn     if (prev_frame + sizeof(struct Frame) <= USRSTACK) {
15984a342e9Sdonn 	dread(&frame, prev_frame, sizeof(struct Frame));
16084a342e9Sdonn     } else if (USRSTACK - prev_frame > 2 * sizeof(Word)) {
16184a342e9Sdonn 	dread(&frame, prev_frame, USRSTACK - prev_frame);
16284a342e9Sdonn     } else {
16384a342e9Sdonn 	frame.save_fp = nil;
16484a342e9Sdonn     }
16584a342e9Sdonn     if (ntramp == 1) {
16684a342e9Sdonn 	dread(&callpc, prev_frame + 92, sizeof(callpc));
16784a342e9Sdonn     } else {
16884a342e9Sdonn 	callpc = frame.save_pc;
16984a342e9Sdonn     }
17084a342e9Sdonn     if (frame.save_fp == nil or frame.save_pc == (Address) -1) {
17184a342e9Sdonn 	newfrp = nil;
17284a342e9Sdonn     } else {
17384a342e9Sdonn 	if (inSignalHandler(callpc)) {
17484a342e9Sdonn #	ifdef sun
17584a342e9Sdonn 	    Address scp;
17684a342e9Sdonn 
17784a342e9Sdonn 	    dread(&scp, prev_frame + 16, sizeof(scp));
17884a342e9Sdonn 	    dread(&callpc,
17984a342e9Sdonn 		&(((struct sigcontext *)scp)->sc_pc), sizeof(Word)
18084a342e9Sdonn 	    );
18184a342e9Sdonn #	endif /* sun */
18284a342e9Sdonn 	}
18384a342e9Sdonn 	frame.save_pc = callpc;
18484a342e9Sdonn         ntramp = 0;
18584a342e9Sdonn 	higher_fp = frp->save_fp;
18684a342e9Sdonn 	higher_pc = frp->save_pc;
18784a342e9Sdonn 	newfrp->save_fp = frame.save_fp;
18884a342e9Sdonn 	newfrp->save_pc = frame.save_pc;
18984a342e9Sdonn 	    findnumargs(newfrp);
19084a342e9Sdonn 	    findsavedregs(newfrp, higher_fp, higher_pc);
19184a342e9Sdonn     }
19284a342e9Sdonn     return newfrp;
19384a342e9Sdonn }
19484a342e9Sdonn 
19584a342e9Sdonn /*
19684a342e9Sdonn  * Finding the saved registers and number of arguments passed to
19784a342e9Sdonn  * the current procedure is painful for the 68000.
19884a342e9Sdonn  *
19984a342e9Sdonn  * This is a version of the way adb for the 68000 does this.
20084a342e9Sdonn  */
20184a342e9Sdonn 
20284a342e9Sdonn #define HIWORD	0xffff0000
20384a342e9Sdonn #define LOWORD	0x0000ffff
20484a342e9Sdonn #define LINKA6	0x4e560000	/* link a6,#x    */
20584a342e9Sdonn #define ADDLSP	0xdffc0000	/* addl #x,sp    */
20684a342e9Sdonn #define ADDWSP	0xdefc0000	/* addw #x,sp    */
20784a342e9Sdonn #define LEASP	0x4fef0000	/* lea	sp@(x),sp*/
20884a342e9Sdonn #define TSTBSP	0x4a2f0000	/* tstb sp@(x)   */
20984a342e9Sdonn #define INSMSK	0xfff80000
21084a342e9Sdonn #define MOVLSP	0x2e800000	/* movl dx,sp@   */
21184a342e9Sdonn #define MOVLD0	0x20000000	/* movl d0,dx	 */
21284a342e9Sdonn #define MOVLA0	0x20400000	/* movl d0,ax	 */
21384a342e9Sdonn #define MVLMSK	0xf1ff0000
21484a342e9Sdonn #define MOVEML	0x48d70000	/* moveml #x,sp@ */
21584a342e9Sdonn #define JSR	0x4eb80000	/* jsr x.[WL]    */
21684a342e9Sdonn #define JSRPC	0x4eba0000	/* jsr PC@( )    */
21784a342e9Sdonn #define LONGBIT 0x00010000
21884a342e9Sdonn #define BSR	0x61000000	/* bsr x	 */
21984a342e9Sdonn #define BYTE3	0x0000ff00
22084a342e9Sdonn #define LOBYTE	0x000000ff
22184a342e9Sdonn #define ADQMSK	0xf1ff0000
22284a342e9Sdonn #define ADDQSP	0x508f0000	/* addql #x,sp   */
22384a342e9Sdonn #define ADDQWSP	0x504f0000	/* addqw #x,sp   */
22484a342e9Sdonn 
22584a342e9Sdonn private int savedregsmask;
22684a342e9Sdonn private int savedregp;
22784a342e9Sdonn 
22884a342e9Sdonn /*
22984a342e9Sdonn  * Find out how many words of arguments were passed to
23084a342e9Sdonn  * the current procedure.
23184a342e9Sdonn  */
23284a342e9Sdonn 
findnumargs(newfrp)23384a342e9Sdonn private findnumargs (newfrp)
23484a342e9Sdonn Frame newfrp;
23584a342e9Sdonn {
23684a342e9Sdonn     integer val;
23784a342e9Sdonn     integer instruc;
23884a342e9Sdonn     Address addr;
23984a342e9Sdonn 
24084a342e9Sdonn     dread(&addr, newfrp->save_fp + sizeof(Address), sizeof(addr));
24184a342e9Sdonn     iread(&instruc, addr, sizeof(instruc));
24284a342e9Sdonn     if ((instruc&MVLMSK) == MOVLA0 or (instruc&MVLMSK) == MOVLD0) {
24384a342e9Sdonn 	addr += 2;
24484a342e9Sdonn 	iread(&instruc, addr, sizeof(instruc));
24584a342e9Sdonn     }
24684a342e9Sdonn     if ((instruc&ADQMSK) == ADDQSP or (instruc&ADQMSK) == ADDQWSP){
24784a342e9Sdonn 	val = (instruc >> (16+9)) & 07;
24884a342e9Sdonn 	if (val == 0) {
24984a342e9Sdonn 	    val = 8;
25084a342e9Sdonn 	}
25184a342e9Sdonn     } else if ((instruc&HIWORD) == ADDLSP){
25284a342e9Sdonn 	iread(&val, addr + 2, sizeof(val));
25384a342e9Sdonn     } else if ((instruc&HIWORD) == ADDWSP || (instruc&HIWORD) == LEASP){
25484a342e9Sdonn 	val = instruc&LOWORD;
25584a342e9Sdonn     } else {
25684a342e9Sdonn 	val = 0;
25784a342e9Sdonn     }
25884a342e9Sdonn     newfrp->nargwords = val / sizeof(Word);
25984a342e9Sdonn }
26084a342e9Sdonn 
26184a342e9Sdonn /*
26284a342e9Sdonn  * Get the saved registers for the given Frame.
26384a342e9Sdonn  */
26484a342e9Sdonn 
findsavedregs(newfrp,higher_fp,higher_pc)26584a342e9Sdonn private findsavedregs (newfrp, higher_fp, higher_pc)
26684a342e9Sdonn Frame newfrp;
26784a342e9Sdonn register Address higher_fp, higher_pc;
26884a342e9Sdonn {
26984a342e9Sdonn     int val, regp, i;
27084a342e9Sdonn     Address addr;
27184a342e9Sdonn     Symbol func;
27284a342e9Sdonn     Address calladdr;
27384a342e9Sdonn     int instruc;
27484a342e9Sdonn 
27584a342e9Sdonn     /*
27684a342e9Sdonn      * Find the entry point of the current procedure.
27784a342e9Sdonn      * This is done by finding the procedure for the higher frame's pc
27884a342e9Sdonn      * and taking its starting address.
27984a342e9Sdonn      */
28084a342e9Sdonn     func = whatblock(higher_pc, true);
28184a342e9Sdonn     calladdr = codeloc(func) - FUNCOFFSET;
28284a342e9Sdonn 
28384a342e9Sdonn     /*
28484a342e9Sdonn      * Look at the entry code for the current procedure
28584a342e9Sdonn      * to determine which registers were saved, and where they are.
28684a342e9Sdonn      *
28784a342e9Sdonn      * First find the size of the activation record.
28884a342e9Sdonn      */
28984a342e9Sdonn     addr = calladdr;
29084a342e9Sdonn     iread(&instruc, addr, sizeof(instruc));
29184a342e9Sdonn     if ((instruc&HIWORD) == LINKA6) {
29284a342e9Sdonn 	if ((instruc &= LOWORD) == 0) {
29384a342e9Sdonn 	    /* look for addl */
29484a342e9Sdonn 	    addr += 4;
29584a342e9Sdonn 	    iread(&instruc, addr, sizeof(instruc));
29684a342e9Sdonn 	    if ((instruc&HIWORD) == ADDLSP) {
29784a342e9Sdonn 		iread(&instruc, addr + 2, sizeof(instruc));
29884a342e9Sdonn 		addr += 6;
29984a342e9Sdonn 	    } else {
30084a342e9Sdonn 		instruc = 0;
30184a342e9Sdonn 	    }
30284a342e9Sdonn 	} else {
30384a342e9Sdonn 	    /* link offset was non-zero -- sign extend it */
30484a342e9Sdonn 	    instruc <<= 16;
30584a342e9Sdonn 	    instruc >>= 16;
30684a342e9Sdonn 	}
30784a342e9Sdonn 	/* we now have the negative frame size */
30884a342e9Sdonn 	regp = higher_fp + instruc;
30984a342e9Sdonn 	savedregp = regp;
31084a342e9Sdonn     }
31184a342e9Sdonn 
31284a342e9Sdonn     /*
31384a342e9Sdonn      * Now find which registers were saved.
31484a342e9Sdonn      * (expecting a probe instruction next)
31584a342e9Sdonn      */
31684a342e9Sdonn     iread(&instruc, addr, sizeof(instruc));
31784a342e9Sdonn     if ((instruc&HIWORD) == TSTBSP) {
31884a342e9Sdonn 	addr += 4;
31984a342e9Sdonn 	iread(&instruc, addr, sizeof(instruc));
32084a342e9Sdonn     }
32184a342e9Sdonn     /*
32284a342e9Sdonn      * expect either a moveml or a movl next
32384a342e9Sdonn      */
32484a342e9Sdonn     if ((instruc&INSMSK) == MOVLSP){
32584a342e9Sdonn 	/*
32684a342e9Sdonn 	 * Only one register saved.
32784a342e9Sdonn 	 */
32884a342e9Sdonn 	i = (instruc>>16) & 07;
32984a342e9Sdonn 	dread(&(newfrp->save_reg[i]), regp, sizeof(Word));
33084a342e9Sdonn 	savedregsmask = 1 << i;
33184a342e9Sdonn     } else if ((instruc&HIWORD) == MOVEML) {
33284a342e9Sdonn 	/*
33384a342e9Sdonn 	 * Saving multiple registers or unoptimized code
33484a342e9Sdonn 	 */
33584a342e9Sdonn 	val = instruc & LOWORD;
33684a342e9Sdonn 	savedregsmask = val;
33784a342e9Sdonn 	i = 0;
33884a342e9Sdonn 	while (val != 0) {
33984a342e9Sdonn 	    if (val&1) {
34084a342e9Sdonn 		dread(&(newfrp->save_reg[i]), regp, sizeof(Word));
34184a342e9Sdonn 		regp += sizeof(Word);
34284a342e9Sdonn 	    }
34384a342e9Sdonn 	    val >>= 1;
34484a342e9Sdonn 	    ++i;
34584a342e9Sdonn 	}
34684a342e9Sdonn     } else {
34784a342e9Sdonn 	savedregsmask = 0;
34884a342e9Sdonn     }
34984a342e9Sdonn }
35084a342e9Sdonn 
35184a342e9Sdonn /*
35284a342e9Sdonn  * Get the current frame information in the given Frame and store the
35384a342e9Sdonn  * associated function in the given value-result parameter.
35484a342e9Sdonn  */
35584a342e9Sdonn 
getcurfunc(frp,fp)35684a342e9Sdonn private getcurfunc (frp, fp)
35784a342e9Sdonn Frame frp;
35884a342e9Sdonn Symbol *fp;
35984a342e9Sdonn {
36084a342e9Sdonn     getcurframe(frp);
36184a342e9Sdonn     *fp = whatblock(frp->save_pc);
36284a342e9Sdonn }
36384a342e9Sdonn 
36484a342e9Sdonn /*
36584a342e9Sdonn  * Return the frame associated with the next function up the call stack, or
36684a342e9Sdonn  * nil if there is none.  The function is returned in a value-result parameter.
36784a342e9Sdonn  * For "inline" functions the statically outer function and same frame
36884a342e9Sdonn  * are returned.
36984a342e9Sdonn  */
37084a342e9Sdonn 
nextfunc(frp,fp)37184a342e9Sdonn public Frame nextfunc (frp, fp)
37284a342e9Sdonn Frame frp;
37384a342e9Sdonn Symbol *fp;
37484a342e9Sdonn {
37584a342e9Sdonn     Symbol t;
37684a342e9Sdonn     Frame nfrp;
37784a342e9Sdonn 
37884a342e9Sdonn     t = *fp;
37984a342e9Sdonn     checkref(t);
38084a342e9Sdonn     if (isinline(t)) {
38184a342e9Sdonn 	t = container(t);
38284a342e9Sdonn 	nfrp = frp;
38384a342e9Sdonn     } else {
38484a342e9Sdonn 	nfrp = nextframe(frp);
38584a342e9Sdonn 	if (nfrp == nil) {
38684a342e9Sdonn 	    t = nil;
38784a342e9Sdonn 	} else {
38884a342e9Sdonn 	    t = whatblock(nfrp->save_pc);
38984a342e9Sdonn 	}
39084a342e9Sdonn     }
39184a342e9Sdonn     *fp = t;
39284a342e9Sdonn     return nfrp;
39384a342e9Sdonn }
39484a342e9Sdonn 
39584a342e9Sdonn /*
39684a342e9Sdonn  * Return the frame associated with the given function.
39784a342e9Sdonn  * If the function is nil, return the most recently activated frame.
39884a342e9Sdonn  *
39984a342e9Sdonn  * Static allocation for the frame.
40084a342e9Sdonn  */
40184a342e9Sdonn 
findframe(f)40284a342e9Sdonn public Frame findframe(f)
40384a342e9Sdonn Symbol f;
40484a342e9Sdonn {
40584a342e9Sdonn     Frame frp;
40684a342e9Sdonn     static struct Frame frame;
40784a342e9Sdonn     Symbol p;
40884a342e9Sdonn     Boolean done;
40984a342e9Sdonn 
41084a342e9Sdonn     frp = &frame;
41184a342e9Sdonn     getcurframe(frp);
41284a342e9Sdonn     if (f != nil) {
41384a342e9Sdonn 	if (f == curfunc and curframe != nil) {
41484a342e9Sdonn 	    *frp = *curframe;
41584a342e9Sdonn 	} else {
41684a342e9Sdonn 	    done = false;
41784a342e9Sdonn 	    p = whatblock(frp->save_pc);
41884a342e9Sdonn 	    do {
41984a342e9Sdonn 		if (p == f) {
42084a342e9Sdonn 		    done = true;
42184a342e9Sdonn 		} else if (p == program) {
42284a342e9Sdonn 		    done = true;
42384a342e9Sdonn 		    frp = nil;
42484a342e9Sdonn 		} else {
42584a342e9Sdonn 		    frp = nextfunc(frp, &p);
42684a342e9Sdonn 		    if (frp == nil) {
42784a342e9Sdonn 			done = true;
42884a342e9Sdonn 		    }
42984a342e9Sdonn 		}
43084a342e9Sdonn 	    } while (not done);
43184a342e9Sdonn 	}
43284a342e9Sdonn     }
43384a342e9Sdonn     return frp;
43484a342e9Sdonn }
43584a342e9Sdonn 
43684a342e9Sdonn /*
43784a342e9Sdonn  * Set the registers according to the given frame pointer.
43884a342e9Sdonn  */
43984a342e9Sdonn 
getnewregs(addr)44084a342e9Sdonn public getnewregs (addr)
44184a342e9Sdonn Address addr;
44284a342e9Sdonn {
44384a342e9Sdonn     struct Frame frame;
44484a342e9Sdonn     integer i, j, mask;
44584a342e9Sdonn 
44684a342e9Sdonn     dread(&frame, addr, sizeof(frame));
44784a342e9Sdonn     setreg(FRP, frame.save_fp);
44884a342e9Sdonn     setreg(PROGCTR, frame.save_pc);
44984a342e9Sdonn     pc = frame.save_pc;
45084a342e9Sdonn     setcurfunc(whatblock(pc));
45184a342e9Sdonn }
45284a342e9Sdonn 
45384a342e9Sdonn /*
45484a342e9Sdonn  * Find the return address of the current procedure/function.
45584a342e9Sdonn  */
45684a342e9Sdonn 
return_addr()45784a342e9Sdonn public Address return_addr()
45884a342e9Sdonn {
45984a342e9Sdonn     Frame frp;
46084a342e9Sdonn     Address addr;
46184a342e9Sdonn     struct Frame frame;
46284a342e9Sdonn 
46384a342e9Sdonn     frp = &frame;
46484a342e9Sdonn     getcurframe(frp);
46584a342e9Sdonn     frp = nextframe(frp);
46684a342e9Sdonn     if (frp == nil) {
46784a342e9Sdonn 	addr = 0;
46884a342e9Sdonn     } else {
46984a342e9Sdonn 	addr = frp->save_pc;
47084a342e9Sdonn     }
47184a342e9Sdonn     return addr;
47284a342e9Sdonn }
47384a342e9Sdonn 
47484a342e9Sdonn /*
47584a342e9Sdonn  * Push the value associated with the current function.
47684a342e9Sdonn  */
47784a342e9Sdonn 
pushretval(len,isindirect)47884a342e9Sdonn public pushretval(len, isindirect)
47984a342e9Sdonn integer len;
48084a342e9Sdonn boolean isindirect;
48184a342e9Sdonn {
48284a342e9Sdonn     Word r0;
48384a342e9Sdonn 
48484a342e9Sdonn     r0 = reg(0);
48584a342e9Sdonn     if (isindirect) {
48684a342e9Sdonn 	rpush((Address) r0, len);
48784a342e9Sdonn     } else {
48884a342e9Sdonn 	switch (len) {
48984a342e9Sdonn 	    case sizeof(char):
49084a342e9Sdonn 		push(char, r0);
49184a342e9Sdonn 		break;
49284a342e9Sdonn 
49384a342e9Sdonn 	    case sizeof(short):
49484a342e9Sdonn 		push(short, r0);
49584a342e9Sdonn 		break;
49684a342e9Sdonn 
49784a342e9Sdonn 	    default:
49884a342e9Sdonn 		if (len == sizeof(Word)) {
49984a342e9Sdonn 		    push(Word, r0);
50084a342e9Sdonn 		} else if (len == 2*sizeof(Word)) {
50184a342e9Sdonn 		    push(Word, r0);
50284a342e9Sdonn 		    push(Word, reg(1));
50384a342e9Sdonn 		} else {
50484a342e9Sdonn 		    error("[internal error: bad size %d in pushretval]", len);
50584a342e9Sdonn 		}
50684a342e9Sdonn 		break;
50784a342e9Sdonn 	}
50884a342e9Sdonn     }
50984a342e9Sdonn }
51084a342e9Sdonn 
51184a342e9Sdonn /*
51284a342e9Sdonn  * Return the base address for locals in the given frame.
51384a342e9Sdonn  */
51484a342e9Sdonn 
locals_base(frp)51584a342e9Sdonn public Address locals_base(frp)
51684a342e9Sdonn Frame frp;
51784a342e9Sdonn {
51884a342e9Sdonn     return (frp == nil) ? reg(FRP) : frp->save_fp;
51984a342e9Sdonn }
52084a342e9Sdonn 
52184a342e9Sdonn /*
52284a342e9Sdonn  * Return the base address for arguments in the given frame.
52384a342e9Sdonn  */
52484a342e9Sdonn 
args_base(frp)52584a342e9Sdonn public Address args_base(frp)
52684a342e9Sdonn Frame frp;
52784a342e9Sdonn {
52884a342e9Sdonn     return (frp == nil) ? reg(FRP) : frp->save_fp;
52984a342e9Sdonn }
53084a342e9Sdonn 
53184a342e9Sdonn /*
53284a342e9Sdonn  * Return saved register n from the given frame.
53384a342e9Sdonn  */
53484a342e9Sdonn 
savereg(n,frp)53584a342e9Sdonn public Word savereg(n, frp)
53684a342e9Sdonn integer n;
53784a342e9Sdonn Frame frp;
53884a342e9Sdonn {
53984a342e9Sdonn     Word w;
54084a342e9Sdonn 
54184a342e9Sdonn     if (frp == nil) {
54284a342e9Sdonn 	w = reg(n);
54384a342e9Sdonn     } else {
54484a342e9Sdonn 	switch (n) {
54584a342e9Sdonn 	    case FRP:
54684a342e9Sdonn 		w = frp->save_fp;
54784a342e9Sdonn 		break;
54884a342e9Sdonn 
54984a342e9Sdonn 	    case STKP:
55084a342e9Sdonn 		w = reg(STKP);
55184a342e9Sdonn 		break;
55284a342e9Sdonn 
55384a342e9Sdonn 	    case PROGCTR:
55484a342e9Sdonn 		w = frp->save_pc;
55584a342e9Sdonn 		break;
55684a342e9Sdonn 
55784a342e9Sdonn 	    default:
55884a342e9Sdonn 		assert(n >= 0 and n < NSAVEREG);
55984a342e9Sdonn 		w = frp->save_reg[n];
56084a342e9Sdonn 		break;
56184a342e9Sdonn 	}
56284a342e9Sdonn     }
56384a342e9Sdonn     return w;
56484a342e9Sdonn }
56584a342e9Sdonn 
56684a342e9Sdonn /*
56784a342e9Sdonn  * Return the nth argument to the current procedure.
56884a342e9Sdonn  */
56984a342e9Sdonn 
argn(n,frp)57084a342e9Sdonn public Word argn(n, frp)
57184a342e9Sdonn integer n;
57284a342e9Sdonn Frame frp;
57384a342e9Sdonn {
57484a342e9Sdonn     Address argaddr;
57584a342e9Sdonn     Word w;
57684a342e9Sdonn 
57784a342e9Sdonn     argaddr = args_base(frp) + 4 + (n * sizeof(Word));
57884a342e9Sdonn     dread(&w, argaddr, sizeof(w));
57984a342e9Sdonn     return w;
58084a342e9Sdonn }
58184a342e9Sdonn 
58284a342e9Sdonn /*
58384a342e9Sdonn  * Return the number of words of arguments passed to the procedure
58484a342e9Sdonn  * associated with the given frame (it's a macro for the VAX).
58584a342e9Sdonn  */
58684a342e9Sdonn 
nargspassed(frp)58784a342e9Sdonn public integer nargspassed (frp)
58884a342e9Sdonn Frame frp;
58984a342e9Sdonn {
59084a342e9Sdonn     integer n;
59184a342e9Sdonn     struct Frame frame;
59284a342e9Sdonn 
59384a342e9Sdonn     if (frp == nil) {
59484a342e9Sdonn 	getcurframe(&frame);
59584a342e9Sdonn 	n = frame.nargwords;
59684a342e9Sdonn     } else {
59784a342e9Sdonn 	n = frp->nargwords;
59884a342e9Sdonn     }
59984a342e9Sdonn     return n;
60084a342e9Sdonn }
60184a342e9Sdonn 
60284a342e9Sdonn /*
60384a342e9Sdonn  * Print a list of currently active blocks starting with most recent.
60484a342e9Sdonn  */
60584a342e9Sdonn 
wherecmd()60684a342e9Sdonn public wherecmd()
60784a342e9Sdonn {
60884a342e9Sdonn     walkstack(false);
60984a342e9Sdonn }
61084a342e9Sdonn 
61184a342e9Sdonn /*
61284a342e9Sdonn  * Print the variables in the given frame or the current one if nil.
61384a342e9Sdonn  */
61484a342e9Sdonn 
dump(func)61584a342e9Sdonn public dump (func)
61684a342e9Sdonn Symbol func;
61784a342e9Sdonn {
61884a342e9Sdonn     Symbol f;
61984a342e9Sdonn     Frame frp;
62084a342e9Sdonn 
62184a342e9Sdonn     if (func == nil) {
62284a342e9Sdonn 	f = curfunc;
62384a342e9Sdonn 	if (curframe != nil) {
62484a342e9Sdonn 	    frp = curframe;
62584a342e9Sdonn 	} else {
62684a342e9Sdonn 	    frp = findframe(f);
62784a342e9Sdonn 	}
62884a342e9Sdonn     } else {
62984a342e9Sdonn 	f = func;
63084a342e9Sdonn 	frp = findframe(f);
63184a342e9Sdonn     }
63284a342e9Sdonn     showaggrs = true;
63384a342e9Sdonn     printcallinfo(f, frp);
63484a342e9Sdonn     dumpvars(f, frp);
63584a342e9Sdonn }
63684a342e9Sdonn 
63784a342e9Sdonn /*
63884a342e9Sdonn  * Dump all values.
63984a342e9Sdonn  */
64084a342e9Sdonn 
dumpall()64184a342e9Sdonn public dumpall ()
64284a342e9Sdonn {
64384a342e9Sdonn     walkstack(true);
64484a342e9Sdonn }
64584a342e9Sdonn 
64684a342e9Sdonn /*
64784a342e9Sdonn  * Walk the stack of active procedures printing information
64884a342e9Sdonn  * about each active procedure.
64984a342e9Sdonn  */
65084a342e9Sdonn 
walkstack(dumpvariables)65184a342e9Sdonn private walkstack(dumpvariables)
65284a342e9Sdonn Boolean dumpvariables;
65384a342e9Sdonn {
65484a342e9Sdonn     Frame frp;
65584a342e9Sdonn     boolean save;
65684a342e9Sdonn     Symbol f;
65784a342e9Sdonn     struct Frame frame;
65884a342e9Sdonn 
65984a342e9Sdonn     if (notstarted(process) or isfinished(process)) {
66084a342e9Sdonn 	error("program is not active");
66184a342e9Sdonn     } else {
66284a342e9Sdonn 	save = walkingstack;
66384a342e9Sdonn 	walkingstack = true;
66484a342e9Sdonn 	showaggrs = dumpvariables;
66584a342e9Sdonn 	frp = &frame;
66684a342e9Sdonn 	getcurfunc(frp, &f);
66784a342e9Sdonn 	for (;;) {
66884a342e9Sdonn 	    printcallinfo(f, frp);
66984a342e9Sdonn 	    if (dumpvariables) {
67084a342e9Sdonn 		dumpvars(f, frp);
67184a342e9Sdonn 		putchar('\n');
67284a342e9Sdonn 	    }
67384a342e9Sdonn 	    frp = nextfunc(frp, &f);
67484a342e9Sdonn 	    if (frp == nil or f == program) {
67584a342e9Sdonn 		break;
67684a342e9Sdonn 	    }
67784a342e9Sdonn 	}
67884a342e9Sdonn 	if (dumpvariables) {
67984a342e9Sdonn 	    printf("in \"%s\":\n", symname(program));
68084a342e9Sdonn 	    dumpvars(program, nil);
68184a342e9Sdonn 	    putchar('\n');
68284a342e9Sdonn 	}
68384a342e9Sdonn 	walkingstack = save;
68484a342e9Sdonn     }
68584a342e9Sdonn }
68684a342e9Sdonn 
68784a342e9Sdonn /*
68884a342e9Sdonn  * Print out the information about a call, i.e.,
68984a342e9Sdonn  * routine name, parameter values, and source location.
69084a342e9Sdonn  */
69184a342e9Sdonn 
printcallinfo(f,frp)69284a342e9Sdonn private printcallinfo (f, frp)
69384a342e9Sdonn Symbol f;
69484a342e9Sdonn Frame frp;
69584a342e9Sdonn {
69684a342e9Sdonn     Lineno line;
69784a342e9Sdonn     Address savepc;
69884a342e9Sdonn 
69984a342e9Sdonn     savepc = frp->save_pc;
70084a342e9Sdonn     if (frp->save_fp != reg(FRP)) {
70184a342e9Sdonn 	savepc -= 1;
70284a342e9Sdonn     }
70384a342e9Sdonn     printname(stdout, f);
70484a342e9Sdonn     if (not isinline(f)) {
70584a342e9Sdonn 	printparams(f, frp);
70684a342e9Sdonn     }
70784a342e9Sdonn     line = srcline(savepc);
70884a342e9Sdonn     if (line != 0) {
70984a342e9Sdonn 	printf(", line %d", line);
71084a342e9Sdonn 	printf(" in \"%s\"\n", srcfilename(savepc));
71184a342e9Sdonn     } else {
71284a342e9Sdonn 	printf(" at 0x%x\n", savepc);
71384a342e9Sdonn     }
71484a342e9Sdonn }
71584a342e9Sdonn 
71684a342e9Sdonn /*
71784a342e9Sdonn  * Set the current function to the given symbol.
71884a342e9Sdonn  * We must adjust "curframe" so that subsequent operations are
71984a342e9Sdonn  * not confused; for simplicity we simply clear it.
72084a342e9Sdonn  */
72184a342e9Sdonn 
setcurfunc(f)72284a342e9Sdonn public setcurfunc (f)
72384a342e9Sdonn Symbol f;
72484a342e9Sdonn {
72584a342e9Sdonn     curfunc = f;
72684a342e9Sdonn     curframe = nil;
72784a342e9Sdonn }
72884a342e9Sdonn 
72984a342e9Sdonn /*
73084a342e9Sdonn  * Return the frame for the current function.
73184a342e9Sdonn  * The space for the frame is allocated statically.
73284a342e9Sdonn  */
73384a342e9Sdonn 
curfuncframe()73484a342e9Sdonn public Frame curfuncframe ()
73584a342e9Sdonn {
73684a342e9Sdonn     static struct Frame frame;
73784a342e9Sdonn     Frame frp;
73884a342e9Sdonn 
73984a342e9Sdonn     if (curframe == nil) {
74084a342e9Sdonn 	frp = findframe(curfunc);
74184a342e9Sdonn 	curframe = &curframerec;
74284a342e9Sdonn 	*curframe = *frp;
74384a342e9Sdonn     } else {
74484a342e9Sdonn 	frp = &frame;
74584a342e9Sdonn 	*frp = *curframe;
74684a342e9Sdonn     }
74784a342e9Sdonn     return frp;
74884a342e9Sdonn }
74984a342e9Sdonn 
75084a342e9Sdonn /*
75184a342e9Sdonn  * Set curfunc to be N up/down the stack from its current value.
75284a342e9Sdonn  */
75384a342e9Sdonn 
up(n)75484a342e9Sdonn public up (n)
75584a342e9Sdonn integer n;
75684a342e9Sdonn {
75784a342e9Sdonn     integer i;
75884a342e9Sdonn     Symbol f;
75984a342e9Sdonn     Frame frp;
76084a342e9Sdonn     boolean done;
76184a342e9Sdonn 
76284a342e9Sdonn     if (not isactive(program)) {
76384a342e9Sdonn 	error("program is not active");
76484a342e9Sdonn     } else if (curfunc == nil) {
76584a342e9Sdonn 	error("no current function");
76684a342e9Sdonn     } else {
76784a342e9Sdonn 	i = 0;
76884a342e9Sdonn 	f = curfunc;
76984a342e9Sdonn 	frp = curfuncframe();
77084a342e9Sdonn 	done = false;
77184a342e9Sdonn 	do {
77284a342e9Sdonn 	    if (frp == nil) {
77384a342e9Sdonn 		done = true;
77484a342e9Sdonn 		error("not that many levels");
77584a342e9Sdonn 	    } else if (i >= n) {
77684a342e9Sdonn 		done = true;
77784a342e9Sdonn 		curfunc = f;
77884a342e9Sdonn 		curframe = &curframerec;
77984a342e9Sdonn 		*curframe = *frp;
78084a342e9Sdonn 		showaggrs = false;
78184a342e9Sdonn 		printcallinfo(curfunc, curframe);
78284a342e9Sdonn 	    } else if (f == program) {
78384a342e9Sdonn 		done = true;
78484a342e9Sdonn 		error("not that many levels");
78584a342e9Sdonn 	    } else {
78684a342e9Sdonn 		frp = nextfunc(frp, &f);
78784a342e9Sdonn 	    }
78884a342e9Sdonn 	    ++i;
78984a342e9Sdonn 	} while (not done);
79084a342e9Sdonn     }
79184a342e9Sdonn }
79284a342e9Sdonn 
down(n)79384a342e9Sdonn public down (n)
79484a342e9Sdonn integer n;
79584a342e9Sdonn {
79684a342e9Sdonn     integer i, depth;
79784a342e9Sdonn     Frame frp, curfrp;
79884a342e9Sdonn     Symbol f;
79984a342e9Sdonn     struct Frame frame;
80084a342e9Sdonn 
80184a342e9Sdonn     if (not isactive(program)) {
80284a342e9Sdonn 	error("program is not active");
80384a342e9Sdonn     } else if (curfunc == nil) {
80484a342e9Sdonn 	error("no current function");
80584a342e9Sdonn     } else {
80684a342e9Sdonn 	depth = 0;
80784a342e9Sdonn 	frp = &frame;
80884a342e9Sdonn 	getcurfunc(frp, &f);
80984a342e9Sdonn 	if (curframe == nil) {
81084a342e9Sdonn 	    curfrp = findframe(curfunc);
81184a342e9Sdonn 	    curframe = &curframerec;
81284a342e9Sdonn 	    *curframe = *curfrp;
81384a342e9Sdonn 	}
81484a342e9Sdonn 	while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) {
81584a342e9Sdonn 	    frp = nextfunc(frp, &f);
81684a342e9Sdonn 	    ++depth;
81784a342e9Sdonn 	}
81884a342e9Sdonn 	if (f == nil or n > depth) {
81984a342e9Sdonn 	    error("not that many levels");
82084a342e9Sdonn 	} else {
82184a342e9Sdonn 	    depth -= n;
82284a342e9Sdonn 	    frp = &frame;
82384a342e9Sdonn 	    getcurfunc(frp, &f);
82484a342e9Sdonn 	    for (i = 0; i < depth; i++) {
82584a342e9Sdonn 		frp = nextfunc(frp, &f);
82684a342e9Sdonn 		assert(frp != nil);
82784a342e9Sdonn 	    }
82884a342e9Sdonn 	    curfunc = f;
82984a342e9Sdonn 	    *curframe = *frp;
83084a342e9Sdonn 	    showaggrs = false;
83184a342e9Sdonn 	    printcallinfo(curfunc, curframe);
83284a342e9Sdonn 	}
83384a342e9Sdonn     }
83484a342e9Sdonn }
83584a342e9Sdonn 
83684a342e9Sdonn /*
83784a342e9Sdonn  * Find the entry point of a procedure or function.
83884a342e9Sdonn  */
83984a342e9Sdonn 
findbeginning(f)84084a342e9Sdonn public findbeginning (f)
84184a342e9Sdonn Symbol f;
84284a342e9Sdonn {
84384a342e9Sdonn     if (isinternal(f)) {
84484a342e9Sdonn 	f->symvalue.funcv.beginaddr += 18;	/* VAX only */
84584a342e9Sdonn     } else {
84684a342e9Sdonn 	/* on 68000's don't add for beginning of program */
84784a342e9Sdonn 	if (f->symvalue.funcv.beginaddr != CODESTART) {
84884a342e9Sdonn 	    f->symvalue.funcv.beginaddr += FUNCOFFSET;
84984a342e9Sdonn 	}
85084a342e9Sdonn     }
85184a342e9Sdonn }
85284a342e9Sdonn 
85384a342e9Sdonn /*
85484a342e9Sdonn  * Return the address corresponding to the first line in a function.
85584a342e9Sdonn  */
85684a342e9Sdonn 
firstline(f)85784a342e9Sdonn public Address firstline(f)
85884a342e9Sdonn Symbol f;
85984a342e9Sdonn {
86084a342e9Sdonn     Address addr;
86184a342e9Sdonn 
86284a342e9Sdonn     addr = codeloc(f);
86384a342e9Sdonn     while (linelookup(addr) == 0 and addr < objsize) {
86484a342e9Sdonn 	++addr;
86584a342e9Sdonn     }
86684a342e9Sdonn     if (addr == objsize) {
86784a342e9Sdonn 	addr = -1;
86884a342e9Sdonn     }
86984a342e9Sdonn     return addr;
87084a342e9Sdonn }
87184a342e9Sdonn 
87284a342e9Sdonn /*
87384a342e9Sdonn  * Catcher drops strike three ...
87484a342e9Sdonn  */
87584a342e9Sdonn 
runtofirst()87684a342e9Sdonn public runtofirst()
87784a342e9Sdonn {
87884a342e9Sdonn     Address addr, endaddr;
87984a342e9Sdonn 
88084a342e9Sdonn     addr = pc;
88184a342e9Sdonn     endaddr = objsize + CODESTART;
88284a342e9Sdonn     while (linelookup(addr) == 0 and addr < endaddr) {
88384a342e9Sdonn 	++addr;
88484a342e9Sdonn     }
88584a342e9Sdonn     if (addr < endaddr) {
88684a342e9Sdonn 	stepto(addr);
88784a342e9Sdonn     }
88884a342e9Sdonn }
88984a342e9Sdonn 
89084a342e9Sdonn /*
89184a342e9Sdonn  * Return the address corresponding to the end of the program.
89284a342e9Sdonn  *
89384a342e9Sdonn  * We look for the entry to "exit".
89484a342e9Sdonn  */
89584a342e9Sdonn 
lastaddr()89684a342e9Sdonn public Address lastaddr()
89784a342e9Sdonn {
89884a342e9Sdonn     Symbol s;
89984a342e9Sdonn 
90084a342e9Sdonn     s = lookup(identname("exit", true));
90184a342e9Sdonn     if (s == nil) {
90284a342e9Sdonn 	panic("can't find exit");
90384a342e9Sdonn     }
90484a342e9Sdonn     return codeloc(s);
90584a342e9Sdonn }
90684a342e9Sdonn 
90784a342e9Sdonn /*
90884a342e9Sdonn  * Decide if the given function is currently active.
90984a342e9Sdonn  *
91084a342e9Sdonn  * We avoid calls to "findframe" during a stack trace for efficiency.
91184a342e9Sdonn  * Presumably information evaluated while walking the stack is active.
91284a342e9Sdonn  */
91384a342e9Sdonn 
isactive(f)91484a342e9Sdonn public Boolean isactive (f)
91584a342e9Sdonn Symbol f;
91684a342e9Sdonn {
91784a342e9Sdonn     Boolean b;
91884a342e9Sdonn 
91984a342e9Sdonn     if (isfinished(process)) {
92084a342e9Sdonn 	b = false;
92184a342e9Sdonn     } else {
92284a342e9Sdonn 	if (walkingstack or f == program or f == nil or
92384a342e9Sdonn 	  (ismodule(f) and isactive(container(f)))) {
92484a342e9Sdonn 	    b = true;
92584a342e9Sdonn 	} else {
92684a342e9Sdonn 	    b = (Boolean) (findframe(f) != nil);
92784a342e9Sdonn 	}
92884a342e9Sdonn     }
92984a342e9Sdonn     return b;
93084a342e9Sdonn }
93184a342e9Sdonn 
93284a342e9Sdonn /*
93384a342e9Sdonn  * Evaluate a call to a procedure.
93484a342e9Sdonn  */
93584a342e9Sdonn 
callproc(exprnode,isfunc)93684a342e9Sdonn public callproc(exprnode, isfunc)
93784a342e9Sdonn Node exprnode;
93884a342e9Sdonn boolean isfunc;
93984a342e9Sdonn {
94084a342e9Sdonn     Node procnode, arglist;
94184a342e9Sdonn     Symbol proc;
94284a342e9Sdonn     integer argc;
94384a342e9Sdonn 
94484a342e9Sdonn     procnode = exprnode->value.arg[0];
94584a342e9Sdonn     arglist = exprnode->value.arg[1];
94684a342e9Sdonn     if (procnode->op != O_SYM) {
94784a342e9Sdonn 	beginerrmsg();
94884a342e9Sdonn 	fprintf(stderr, "can't call \"");
94984a342e9Sdonn 	prtree(stderr, procnode);
95084a342e9Sdonn 	fprintf(stderr, "\"");
95184a342e9Sdonn 	enderrmsg();
95284a342e9Sdonn     }
95384a342e9Sdonn     assert(procnode->op == O_SYM);
95484a342e9Sdonn     proc = procnode->value.sym;
95584a342e9Sdonn     if (not isblock(proc)) {
95684a342e9Sdonn 	error("\"%s\" is not a procedure or function", symname(proc));
95784a342e9Sdonn     }
95884a342e9Sdonn     endproc.isfunc = isfunc;
95984a342e9Sdonn     endproc.callnode = exprnode;
96084a342e9Sdonn     endproc.cmdnode = topnode;
96184a342e9Sdonn     pushenv();
96284a342e9Sdonn     pc = codeloc(proc);
96384a342e9Sdonn     argc = pushargs(proc, arglist);
96484a342e9Sdonn     setreg(FRP, 1);	/* have to ensure it's non-zero for return_addr() */
96584a342e9Sdonn     beginproc(proc, argc);
96684a342e9Sdonn     event_once(
96784a342e9Sdonn 	build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)),
96884a342e9Sdonn 	buildcmdlist(build(O_PROCRTN, proc))
96984a342e9Sdonn     );
97084a342e9Sdonn     isstopped = false;
97184a342e9Sdonn     if (not bpact()) {
97284a342e9Sdonn 	isstopped = true;
97384a342e9Sdonn 	cont(0);
97484a342e9Sdonn     }
97584a342e9Sdonn     /*
97684a342e9Sdonn      * bpact() won't return true, it will call printstatus() and go back
97784a342e9Sdonn      * to command input if a breakpoint is found.
97884a342e9Sdonn      */
97984a342e9Sdonn     /* NOTREACHED */
98084a342e9Sdonn }
98184a342e9Sdonn 
98284a342e9Sdonn /*
98384a342e9Sdonn  * Push the arguments on the process' stack.  We do this by first
98484a342e9Sdonn  * evaluating them on the "eval" stack, then copying into the process'
98584a342e9Sdonn  * space.
98684a342e9Sdonn  */
98784a342e9Sdonn 
pushargs(proc,arglist)98884a342e9Sdonn private integer pushargs(proc, arglist)
98984a342e9Sdonn Symbol proc;
99084a342e9Sdonn Node arglist;
99184a342e9Sdonn {
99284a342e9Sdonn     Stack *savesp;
99384a342e9Sdonn     int argc, args_size;
99484a342e9Sdonn 
99584a342e9Sdonn     savesp = sp;
99684a342e9Sdonn     if (varIsSet("$unsafecall")) {
99784a342e9Sdonn 	argc = unsafe_evalargs(proc, arglist);
99884a342e9Sdonn     } else {
99984a342e9Sdonn 	argc = evalargs(proc, arglist);
100084a342e9Sdonn     }
100184a342e9Sdonn     args_size = sp - savesp;
100284a342e9Sdonn     setreg(STKP, reg(STKP) - args_size);
100384a342e9Sdonn     dwrite(savesp, reg(STKP), args_size);
100484a342e9Sdonn     sp = savesp;
100584a342e9Sdonn     return argc;
100684a342e9Sdonn }
100784a342e9Sdonn 
100884a342e9Sdonn /*
100984a342e9Sdonn  * Check to see if an expression is correct for a given parameter.
101084a342e9Sdonn  * If the given parameter is false, don't worry about type inconsistencies.
101184a342e9Sdonn  *
101284a342e9Sdonn  * Return whether or not it is ok.
101384a342e9Sdonn  */
101484a342e9Sdonn 
chkparam(actual,formal,chk)101584a342e9Sdonn private boolean chkparam (actual, formal, chk)
101684a342e9Sdonn Node actual;
101784a342e9Sdonn Symbol formal;
101884a342e9Sdonn boolean chk;
101984a342e9Sdonn {
102084a342e9Sdonn     boolean b;
102184a342e9Sdonn 
102284a342e9Sdonn     b = true;
102384a342e9Sdonn     if (chk) {
102484a342e9Sdonn 	if (formal == nil) {
102584a342e9Sdonn 	    beginerrmsg();
102684a342e9Sdonn 	    fprintf(stderr, "too many parameters");
102784a342e9Sdonn 	    b = false;
102884a342e9Sdonn 	} else if (not compatible(formal->type, actual->nodetype)) {
102984a342e9Sdonn 	    beginerrmsg();
103084a342e9Sdonn 	    fprintf(stderr, "type mismatch for %s", symname(formal));
103184a342e9Sdonn 	    b = false;
103284a342e9Sdonn 	}
103384a342e9Sdonn     }
103484a342e9Sdonn     if (b and formal != nil and
103584a342e9Sdonn 	isvarparam(formal) and not isopenarray(formal->type) and
103684a342e9Sdonn 	not (
103784a342e9Sdonn 	    actual->op == O_RVAL or actual->nodetype == t_addr or
103884a342e9Sdonn 	    (
103984a342e9Sdonn 		actual->op == O_TYPERENAME and
104084a342e9Sdonn 		(
104184a342e9Sdonn 		    actual->value.arg[0]->op == O_RVAL or
104284a342e9Sdonn 		    actual->value.arg[0]->nodetype == t_addr
104384a342e9Sdonn 		)
104484a342e9Sdonn 	    )
104584a342e9Sdonn 	)
104684a342e9Sdonn     ) {
104784a342e9Sdonn 	beginerrmsg();
104884a342e9Sdonn 	fprintf(stderr, "expected variable, found \"");
104984a342e9Sdonn 	prtree(stderr, actual);
105084a342e9Sdonn 	fprintf(stderr, "\"");
105184a342e9Sdonn 	b = false;
105284a342e9Sdonn     }
105384a342e9Sdonn     return b;
105484a342e9Sdonn }
105584a342e9Sdonn 
105684a342e9Sdonn /*
105784a342e9Sdonn  * Pass an expression to a particular parameter.
105884a342e9Sdonn  *
105984a342e9Sdonn  * Normally we pass either the address or value, but in some cases
106084a342e9Sdonn  * (such as C strings) we want to copy the value onto the stack and
106184a342e9Sdonn  * pass its address.
106284a342e9Sdonn  *
106384a342e9Sdonn  * Another special case raised by strings is the possibility that
106484a342e9Sdonn  * the actual parameter will be larger than the formal, even with
106584a342e9Sdonn  * appropriate type-checking.  This occurs because we assume during
106684a342e9Sdonn  * evaluation that strings are null-terminated, whereas some languages,
106784a342e9Sdonn  * notably Pascal, do not work under that assumption.
106884a342e9Sdonn  */
106984a342e9Sdonn 
passparam(actual,formal)107084a342e9Sdonn private passparam (actual, formal)
107184a342e9Sdonn Node actual;
107284a342e9Sdonn Symbol formal;
107384a342e9Sdonn {
107484a342e9Sdonn     boolean b;
107584a342e9Sdonn     Address addr;
107684a342e9Sdonn     Stack *savesp;
107784a342e9Sdonn     integer actsize, formsize;
107884a342e9Sdonn 
107984a342e9Sdonn     if (formal != nil and isvarparam(formal) and
108084a342e9Sdonn 	(not isopenarray(formal->type))
108184a342e9Sdonn     ) {
108284a342e9Sdonn 	addr = lval(actual->value.arg[0]);
108384a342e9Sdonn 	push(Address, addr);
108484a342e9Sdonn     } else if (passaddr(formal, actual->nodetype)) {
108584a342e9Sdonn 	savesp = sp;
108684a342e9Sdonn 	eval(actual);
108784a342e9Sdonn 	actsize = sp - savesp;
108884a342e9Sdonn 	setreg(STKP,
108984a342e9Sdonn 	    reg(STKP) - ((actsize + sizeof(Word) - 1) & ~(sizeof(Word) - 1))
109084a342e9Sdonn 	);
109184a342e9Sdonn 	dwrite(savesp, reg(STKP), actsize);
109284a342e9Sdonn 	sp = savesp;
109384a342e9Sdonn 	push(Address, reg(STKP));
109484a342e9Sdonn 	if (formal != nil and isopenarray(formal->type)) {
109584a342e9Sdonn 	    push(integer, actsize div size(formal->type->type));
109684a342e9Sdonn 	}
109784a342e9Sdonn     } else if (formal != nil) {
109884a342e9Sdonn 	formsize = size(formal);
109984a342e9Sdonn 	savesp = sp;
110084a342e9Sdonn 	eval(actual);
110184a342e9Sdonn 	actsize = sp - savesp;
110284a342e9Sdonn 	if (actsize > formsize) {
110384a342e9Sdonn 	    sp -= (actsize - formsize);
110484a342e9Sdonn 	}
110584a342e9Sdonn     } else {
110684a342e9Sdonn 	eval(actual);
110784a342e9Sdonn     }
110884a342e9Sdonn }
110984a342e9Sdonn 
111084a342e9Sdonn /*
111184a342e9Sdonn  * Evaluate an argument list left-to-right.
111284a342e9Sdonn  */
111384a342e9Sdonn 
evalargs(proc,arglist)111484a342e9Sdonn private integer evalargs(proc, arglist)
111584a342e9Sdonn Symbol proc;
111684a342e9Sdonn Node arglist;
111784a342e9Sdonn {
111884a342e9Sdonn     Node p, actual;
111984a342e9Sdonn     Symbol formal;
112084a342e9Sdonn     Stack *savesp;
112184a342e9Sdonn     integer count;
112284a342e9Sdonn     boolean chk;
112384a342e9Sdonn 
112484a342e9Sdonn     savesp = sp;
112584a342e9Sdonn     count = 0;
112684a342e9Sdonn     formal = proc->chain;
112784a342e9Sdonn     chk = (boolean) (not nosource(proc));
112884a342e9Sdonn     for (p = arglist; p != nil; p = p->value.arg[1]) {
112984a342e9Sdonn 	assert(p->op == O_COMMA);
113084a342e9Sdonn 	actual = p->value.arg[0];
113184a342e9Sdonn 	if (not chkparam(actual, formal, chk)) {
113284a342e9Sdonn 	    fprintf(stderr, " in call to %s", symname(proc));
113384a342e9Sdonn 	    sp = savesp;
113484a342e9Sdonn 	    enderrmsg();
113584a342e9Sdonn 	}
113684a342e9Sdonn 	passparam(actual, formal);
113784a342e9Sdonn 	if (formal != nil) {
113884a342e9Sdonn 	    formal = formal->chain;
113984a342e9Sdonn 	}
114084a342e9Sdonn 	++count;
114184a342e9Sdonn     }
114284a342e9Sdonn     if (chk) {
114384a342e9Sdonn 	if (formal != nil) {
114484a342e9Sdonn 	    sp = savesp;
114584a342e9Sdonn 	    error("not enough parameters to %s", symname(proc));
114684a342e9Sdonn 	}
114784a342e9Sdonn     }
114884a342e9Sdonn     return count;
114984a342e9Sdonn }
115084a342e9Sdonn 
115184a342e9Sdonn /*
115284a342e9Sdonn  * Evaluate an argument list without any type checking.
115384a342e9Sdonn  * This is only useful for procedures with a varying number of
115484a342e9Sdonn  * arguments that are compiled -g.
115584a342e9Sdonn  */
115684a342e9Sdonn 
unsafe_evalargs(proc,arglist)115784a342e9Sdonn private integer unsafe_evalargs (proc, arglist)
115884a342e9Sdonn Symbol proc;
115984a342e9Sdonn Node arglist;
116084a342e9Sdonn {
116184a342e9Sdonn     Node p;
116284a342e9Sdonn     integer count;
116384a342e9Sdonn 
116484a342e9Sdonn     count = 0;
116584a342e9Sdonn     for (p = arglist; p != nil; p = p->value.arg[1]) {
116684a342e9Sdonn 	assert(p->op == O_COMMA);
116784a342e9Sdonn 	eval(p->value.arg[0]);
116884a342e9Sdonn 	++count;
116984a342e9Sdonn     }
117084a342e9Sdonn     return count;
117184a342e9Sdonn }
117284a342e9Sdonn 
procreturn(f)117384a342e9Sdonn public procreturn(f)
117484a342e9Sdonn Symbol f;
117584a342e9Sdonn {
117684a342e9Sdonn     integer retvalsize;
117784a342e9Sdonn     Node tmp;
117884a342e9Sdonn     char *copy;
117984a342e9Sdonn 
118084a342e9Sdonn     flushoutput();
118184a342e9Sdonn     popenv();
118284a342e9Sdonn     if (endproc.isfunc) {
118384a342e9Sdonn 	retvalsize = size(f->type);
118484a342e9Sdonn 	if (retvalsize > sizeof(long)) {
118584a342e9Sdonn 	    pushretval(retvalsize, true);
118684a342e9Sdonn 	    copy = newarr(char, retvalsize);
118784a342e9Sdonn 	    popn(retvalsize, copy);
118884a342e9Sdonn 	    tmp = build(O_SCON, copy);
118984a342e9Sdonn 	} else {
119084a342e9Sdonn 	    tmp = build(O_LCON, (long) (reg(0)));
119184a342e9Sdonn 	}
119284a342e9Sdonn 	tmp->nodetype = f->type;
119384a342e9Sdonn 	tfree(endproc.callnode);
119484a342e9Sdonn 	*(endproc.callnode) = *(tmp);
119584a342e9Sdonn 	dispose(tmp);
119684a342e9Sdonn 	eval(endproc.cmdnode);
119784a342e9Sdonn     } else {
119884a342e9Sdonn 	putchar('\n');
119984a342e9Sdonn 	printname(stdout, f);
120084a342e9Sdonn 	printf(" returns successfully\n");
120184a342e9Sdonn     }
120284a342e9Sdonn     erecover();
120384a342e9Sdonn }
120484a342e9Sdonn 
120584a342e9Sdonn /*
120684a342e9Sdonn  * Push the current environment.
120784a342e9Sdonn  */
120884a342e9Sdonn 
pushenv()120984a342e9Sdonn private pushenv()
121084a342e9Sdonn {
121184a342e9Sdonn     push(Address, pc);
121284a342e9Sdonn     push(Lineno, curline);
121384a342e9Sdonn     push(String, cursource);
121484a342e9Sdonn     push(Boolean, isstopped);
121584a342e9Sdonn     push(Symbol, curfunc);
121684a342e9Sdonn     push(Frame, curframe);
121784a342e9Sdonn     push(struct Frame, curframerec);
121884a342e9Sdonn     push(CallEnv, endproc);
121984a342e9Sdonn     push(Word, reg(PROGCTR));
122084a342e9Sdonn     push(Word, reg(STKP));
122184a342e9Sdonn     push(Word, reg(FRP));
122284a342e9Sdonn }
122384a342e9Sdonn 
122484a342e9Sdonn /*
122584a342e9Sdonn  * Pop back to the real world.
122684a342e9Sdonn  */
122784a342e9Sdonn 
popenv()122884a342e9Sdonn public popenv()
122984a342e9Sdonn {
123084a342e9Sdonn     String filename;
123184a342e9Sdonn 
123284a342e9Sdonn     setreg(FRP, pop(Word));
123384a342e9Sdonn     setreg(STKP, pop(Word));
123484a342e9Sdonn     setreg(PROGCTR, pop(Word));
123584a342e9Sdonn     endproc = pop(CallEnv);
123684a342e9Sdonn     curframerec = pop(struct Frame);
123784a342e9Sdonn     curframe = pop(Frame);
123884a342e9Sdonn     curfunc = pop(Symbol);
123984a342e9Sdonn     isstopped = pop(Boolean);
124084a342e9Sdonn     filename = pop(String);
124184a342e9Sdonn     curline = pop(Lineno);
124284a342e9Sdonn     pc = pop(Address);
124384a342e9Sdonn     setsource(filename);
124484a342e9Sdonn }
124584a342e9Sdonn 
124684a342e9Sdonn /*
124784a342e9Sdonn  * Flush the debuggee's standard output.
124884a342e9Sdonn  *
124984a342e9Sdonn  * This is VERY dependent on the use of stdio.
125084a342e9Sdonn  */
125184a342e9Sdonn 
flushoutput()125284a342e9Sdonn public flushoutput()
125384a342e9Sdonn {
125484a342e9Sdonn     Symbol p, iob;
125584a342e9Sdonn     Stack *savesp;
125684a342e9Sdonn 
125784a342e9Sdonn     p = lookup(identname("fflush", true));
125884a342e9Sdonn     while (p != nil and not isblock(p)) {
125984a342e9Sdonn 	p = p->next_sym;
126084a342e9Sdonn     }
126184a342e9Sdonn     if (p != nil) {
126284a342e9Sdonn 	iob = lookup(identname("_iob", true));
126384a342e9Sdonn 	if (iob != nil) {
126484a342e9Sdonn 	    pushenv();
126584a342e9Sdonn 	    pc = codeloc(p) - FUNCOFFSET;
126684a342e9Sdonn 	    savesp = sp;
126784a342e9Sdonn 	    push(long, address(iob, nil) + sizeof(*stdout));
126884a342e9Sdonn 	    setreg(STKP, reg(STKP) - sizeof(long));
126984a342e9Sdonn 	    dwrite(savesp, reg(STKP), sizeof(long));
127084a342e9Sdonn 	    sp = savesp;
127184a342e9Sdonn 	    beginproc(p, 1);
127284a342e9Sdonn 	    stepto(return_addr());
127384a342e9Sdonn 	    popenv();
127484a342e9Sdonn 	}
127584a342e9Sdonn     }
127684a342e9Sdonn }
1277