xref: /csrg-svn/old/dbx/runtime.iris.c (revision 42684)
133332Sdonn /*
238105Sbostic  * Copyright (c) 1983 The Regents of the University of California.
338105Sbostic  * All rights reserved.
438105Sbostic  *
5*42684Sbostic  * %sccs.include.redist.c%
633332Sdonn  */
733332Sdonn 
833332Sdonn #ifndef lint
9*42684Sbostic static char sccsid[] = "@(#)runtime.iris.c	5.3 (Berkeley) 06/01/90";
1038105Sbostic #endif /* not lint */
1133332Sdonn 
1233332Sdonn /*
1333332Sdonn  * Runtime organization dependent routines, mostly dealing with
1433332Sdonn  * activation records.
1533332Sdonn  */
1633332Sdonn 
1733332Sdonn #include "defs.h"
1833332Sdonn #include "runtime.h"
1933332Sdonn #include "process.h"
2033332Sdonn #include "machine.h"
2133332Sdonn #include "events.h"
2233332Sdonn #include "mappings.h"
2333332Sdonn #include "symbols.h"
2433332Sdonn #include "tree.h"
2533332Sdonn #include "eval.h"
2633332Sdonn #include "operators.h"
2733332Sdonn #include "object.h"
2833332Sdonn #include <sys/param.h>
2933332Sdonn #include <signal.h>
3033332Sdonn 
3133332Sdonn #ifndef public
3233332Sdonn typedef struct Frame *Frame;
3333332Sdonn 
3433332Sdonn #include "machine.h"
3533332Sdonn #endif
3633332Sdonn 
3733332Sdonn #define NSAVEREG 14
3833332Sdonn 
3933332Sdonn struct Frame {
4033332Sdonn     Address save_fp;		/* frame pointer */
4133332Sdonn     Address save_pc;		/* program counter */
4233332Sdonn     Word save_reg[NSAVEREG];	/* not necessarily there */
4333332Sdonn     integer nargwords;		/* computed, not stored */
4433332Sdonn };
4533332Sdonn 
4633332Sdonn private Frame curframe = nil;
4733332Sdonn private struct Frame curframerec;
4833332Sdonn private Boolean walkingstack = false;
4933332Sdonn 
5033332Sdonn #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp)
5133332Sdonn 
inSignalHandler(addr)5233332Sdonn private boolean inSignalHandler (addr)
5333332Sdonn Address addr;
5433332Sdonn {
5533332Sdonn     Symbol f;
5633332Sdonn 
5733332Sdonn #ifdef IRIS
5833332Sdonn     return false;
5933332Sdonn #else /* sun */
6033332Sdonn     f = whatblock(addr);
6133332Sdonn     return (boolean) (f != nil and streq(symname(f), "_sigtramp"));
6233332Sdonn #endif
6333332Sdonn }
6433332Sdonn 
6533332Sdonn typedef struct {
6633332Sdonn     Node callnode;
6733332Sdonn     Node cmdnode;
6833332Sdonn     boolean isfunc;
6933332Sdonn } CallEnv;
7033332Sdonn 
7133332Sdonn private CallEnv endproc;
7233332Sdonn 
7333332Sdonn /*
7433332Sdonn  * Set a frame to the current activation record.
7533332Sdonn  */
7633332Sdonn 
getcurframe(frp)7733332Sdonn private getcurframe(frp)
7833332Sdonn Frame frp;
7933332Sdonn {
8033332Sdonn     register int i;
8133332Sdonn 
8233332Sdonn     checkref(frp);
8333332Sdonn     frp->save_fp = reg(FRP);
8433332Sdonn     frp->save_pc = reg(PROGCTR);
8533332Sdonn     for (i = 0; i < NSAVEREG; i++) {
8633332Sdonn 	frp->save_reg[i] = reg(i);
8733332Sdonn     }
8833332Sdonn     if (frp->save_fp == nil) {
8933332Sdonn 	frp->nargwords = 0;
9033332Sdonn     } else {
9133332Sdonn 	findnumargs(frp);
9233332Sdonn     }
9333332Sdonn }
9433332Sdonn 
9533332Sdonn /*
9633332Sdonn  * Get the saved registers from one frame to another
9733332Sdonn  * given mask specifying which registers were actually saved.
9833332Sdonn  */
9933332Sdonn 
10033332Sdonn #define bis(b, n) ((b & (1 << (n))) != 0)
10133332Sdonn 
getsaveregs(newfrp,frp,mask)10233332Sdonn private getsaveregs (newfrp, frp, mask)
10333332Sdonn Frame newfrp, frp;
10433332Sdonn integer mask;
10533332Sdonn {
10633332Sdonn     integer i, j;
10733332Sdonn 
10833332Sdonn     j = 0;
10933332Sdonn     for (i = 0; i < NSAVEREG; i++) {
11033332Sdonn 	if (bis(mask, i)) {
11133332Sdonn 	    newfrp->save_reg[i] = frp->save_reg[j];
11233332Sdonn 	    ++j;
11333332Sdonn 	}
11433332Sdonn     }
11533332Sdonn }
11633332Sdonn 
11733332Sdonn /*
11833332Sdonn  * Return a pointer to the next activation record up the stack.
11933332Sdonn  * Return nil if there is none.
12033332Sdonn  * Writes over space pointed to by given argument.
12133332Sdonn  */
12233332Sdonn 
nextframe(frp)12333332Sdonn private Frame nextframe(frp)
12433332Sdonn Frame frp;
12533332Sdonn {
12633332Sdonn     Frame newfrp;
12733332Sdonn     struct Frame frame;
12833332Sdonn     integer mask;
12933332Sdonn     Address prev_frame, callpc, higher_fp, higher_pc;
13033332Sdonn     static integer ntramp = 0;
13133332Sdonn 
13233332Sdonn     newfrp = frp;
13333332Sdonn     prev_frame = frp->save_fp;
13433332Sdonn 
13533332Sdonn /*
13633332Sdonn  *  The check for interrupt generated frames is taken from adb with only
13733332Sdonn  *  partial understanding.  If you're in "sub" and on a sigxxx "sigsub"
13833332Sdonn  *  gets control, then the stack does NOT look like <main, sub, sigsub>.
13933332Sdonn  *
14033332Sdonn  *  As best I can make out it looks like:
14133332Sdonn  *
14233332Sdonn  *     <main, (machine check exception block + sub), sysframe, sigsub>.
14333332Sdonn  *
14433332Sdonn  *  When the signal occurs an exception block and a frame for the routine
14533332Sdonn  *  in which it occured are pushed on the user stack.  Then another frame
14633332Sdonn  *  is pushed corresponding to a call from the kernel to sigsub.
14733332Sdonn  *
14833332Sdonn  *  The addr in sub at which the exception occured is not in sub.save_pc
14933332Sdonn  *  but in the machine check exception block.  It is at the magic address
15033332Sdonn  *  fp + 84.
15133332Sdonn  *
15233332Sdonn  *  The current approach ignores the sys_frame (what adb reports as sigtramp)
15333332Sdonn  *  and takes the pc for sub from the exception block.  This allows the
15433332Sdonn  *  "where" command to report <main, sub, sigsub>, which seems reasonable.
15533332Sdonn  */
15633332Sdonn 
15733332Sdonn nextf:
15833332Sdonn     if (prev_frame + sizeof(struct Frame) <= USRSTACK) {
15933332Sdonn 	dread(&frame, prev_frame, sizeof(struct Frame));
16033332Sdonn     } else if (USRSTACK - prev_frame > 2 * sizeof(Word)) {
16133332Sdonn 	dread(&frame, prev_frame, USRSTACK - prev_frame);
16233332Sdonn     } else {
16333332Sdonn 	frame.save_fp = nil;
16433332Sdonn     }
16533332Sdonn     if (ntramp == 1) {
16633332Sdonn 	dread(&callpc, prev_frame + 92, sizeof(callpc));
16733332Sdonn     } else {
16833332Sdonn 	callpc = frame.save_pc;
16933332Sdonn     }
17033332Sdonn     if (frame.save_fp == nil or frame.save_pc == (Address) -1) {
17133332Sdonn 	newfrp = nil;
17233332Sdonn     } else {
17333332Sdonn 	if (inSignalHandler(callpc)) {
17433332Sdonn #	ifdef sun
17533332Sdonn 	    Address scp;
17633332Sdonn 
17733332Sdonn 	    dread(&scp, prev_frame + 16, sizeof(scp));
17833332Sdonn 	    dread(&callpc,
17933332Sdonn 		&(((struct sigcontext *)scp)->sc_pc), sizeof(Word)
18033332Sdonn 	    );
18133332Sdonn #	endif /* sun */
18233332Sdonn 	}
18333332Sdonn 	frame.save_pc = callpc;
18433332Sdonn         ntramp = 0;
18533332Sdonn 	higher_fp = frp->save_fp;
18633332Sdonn 	higher_pc = frp->save_pc;
18733332Sdonn 	newfrp->save_fp = frame.save_fp;
18833332Sdonn 	newfrp->save_pc = frame.save_pc;
18933332Sdonn 	    findnumargs(newfrp);
19033332Sdonn 	    findsavedregs(newfrp, higher_fp, higher_pc);
19133332Sdonn     }
19233332Sdonn     return newfrp;
19333332Sdonn }
19433332Sdonn 
19533332Sdonn /*
19633332Sdonn  * Finding the saved registers and number of arguments passed to
19733332Sdonn  * the current procedure is painful for the 68000.
19833332Sdonn  *
19933332Sdonn  * This is a version of the way adb for the 68000 does this.
20033332Sdonn  */
20133332Sdonn 
20233332Sdonn #define HIWORD	0xffff0000
20333332Sdonn #define LOWORD	0x0000ffff
20433332Sdonn #define LINKA6	0x4e560000	/* link a6,#x    */
20533332Sdonn #define ADDLSP	0xdffc0000	/* addl #x,sp    */
20633332Sdonn #define ADDWSP	0xdefc0000	/* addw #x,sp    */
20733332Sdonn #define LEASP	0x4fef0000	/* lea	sp@(x),sp*/
20833332Sdonn #define TSTBSP	0x4a2f0000	/* tstb sp@(x)   */
20933332Sdonn #define INSMSK	0xfff80000
21033332Sdonn #define MOVLSP	0x2e800000	/* movl dx,sp@   */
21133332Sdonn #define MOVLD0	0x20000000	/* movl d0,dx	 */
21233332Sdonn #define MOVLA0	0x20400000	/* movl d0,ax	 */
21333332Sdonn #define MVLMSK	0xf1ff0000
21433332Sdonn #define MOVEML	0x48d70000	/* moveml #x,sp@ */
21533332Sdonn #define JSR	0x4eb80000	/* jsr x.[WL]    */
21633332Sdonn #define JSRPC	0x4eba0000	/* jsr PC@( )    */
21733332Sdonn #define LONGBIT 0x00010000
21833332Sdonn #define BSR	0x61000000	/* bsr x	 */
21933332Sdonn #define BYTE3	0x0000ff00
22033332Sdonn #define LOBYTE	0x000000ff
22133332Sdonn #define ADQMSK	0xf1ff0000
22233332Sdonn #define ADDQSP	0x508f0000	/* addql #x,sp   */
22333332Sdonn #define ADDQWSP	0x504f0000	/* addqw #x,sp   */
22433332Sdonn 
22533332Sdonn private int savedregsmask;
22633332Sdonn private int savedregp;
22733332Sdonn 
22833332Sdonn /*
22933332Sdonn  * Find out how many words of arguments were passed to
23033332Sdonn  * the current procedure.
23133332Sdonn  */
23233332Sdonn 
findnumargs(newfrp)23333332Sdonn private findnumargs (newfrp)
23433332Sdonn Frame newfrp;
23533332Sdonn {
23633332Sdonn     integer val;
23733332Sdonn     integer instruc;
23833332Sdonn     Address addr;
23933332Sdonn 
24033332Sdonn     dread(&addr, newfrp->save_fp + sizeof(Address), sizeof(addr));
24133332Sdonn     iread(&instruc, addr, sizeof(instruc));
24233332Sdonn     if ((instruc&MVLMSK) == MOVLA0 or (instruc&MVLMSK) == MOVLD0) {
24333332Sdonn 	addr += 2;
24433332Sdonn 	iread(&instruc, addr, sizeof(instruc));
24533332Sdonn     }
24633332Sdonn     if ((instruc&ADQMSK) == ADDQSP or (instruc&ADQMSK) == ADDQWSP){
24733332Sdonn 	val = (instruc >> (16+9)) & 07;
24833332Sdonn 	if (val == 0) {
24933332Sdonn 	    val = 8;
25033332Sdonn 	}
25133332Sdonn     } else if ((instruc&HIWORD) == ADDLSP){
25233332Sdonn 	iread(&val, addr + 2, sizeof(val));
25333332Sdonn     } else if ((instruc&HIWORD) == ADDWSP || (instruc&HIWORD) == LEASP){
25433332Sdonn 	val = instruc&LOWORD;
25533332Sdonn     } else {
25633332Sdonn 	val = 0;
25733332Sdonn     }
25833332Sdonn     newfrp->nargwords = val / sizeof(Word);
25933332Sdonn }
26033332Sdonn 
26133332Sdonn /*
26233332Sdonn  * Get the saved registers for the given Frame.
26333332Sdonn  */
26433332Sdonn 
findsavedregs(newfrp,higher_fp,higher_pc)26533332Sdonn private findsavedregs (newfrp, higher_fp, higher_pc)
26633332Sdonn Frame newfrp;
26733332Sdonn register Address higher_fp, higher_pc;
26833332Sdonn {
26933332Sdonn     int val, regp, i;
27033332Sdonn     Address addr;
27133332Sdonn     Symbol func;
27233332Sdonn     Address calladdr;
27333332Sdonn     int instruc;
27433332Sdonn 
27533332Sdonn     /*
27633332Sdonn      * Find the entry point of the current procedure.
27733332Sdonn      * This is done by finding the procedure for the higher frame's pc
27833332Sdonn      * and taking its starting address.
27933332Sdonn      */
28033332Sdonn     func = whatblock(higher_pc, true);
28133332Sdonn     calladdr = codeloc(func) - FUNCOFFSET;
28233332Sdonn 
28333332Sdonn     /*
28433332Sdonn      * Look at the entry code for the current procedure
28533332Sdonn      * to determine which registers were saved, and where they are.
28633332Sdonn      *
28733332Sdonn      * First find the size of the activation record.
28833332Sdonn      */
28933332Sdonn     addr = calladdr;
29033332Sdonn     iread(&instruc, addr, sizeof(instruc));
29133332Sdonn     if ((instruc&HIWORD) == LINKA6) {
29233332Sdonn 	if ((instruc &= LOWORD) == 0) {
29333332Sdonn 	    /* look for addl */
29433332Sdonn 	    addr += 4;
29533332Sdonn 	    iread(&instruc, addr, sizeof(instruc));
29633332Sdonn 	    if ((instruc&HIWORD) == ADDLSP) {
29733332Sdonn 		iread(&instruc, addr + 2, sizeof(instruc));
29833332Sdonn 		addr += 6;
29933332Sdonn 	    } else {
30033332Sdonn 		instruc = 0;
30133332Sdonn 	    }
30233332Sdonn 	} else {
30333332Sdonn 	    /* link offset was non-zero -- sign extend it */
30433332Sdonn 	    instruc <<= 16;
30533332Sdonn 	    instruc >>= 16;
30633332Sdonn 	}
30733332Sdonn 	/* we now have the negative frame size */
30833332Sdonn 	regp = higher_fp + instruc;
30933332Sdonn 	savedregp = regp;
31033332Sdonn     }
31133332Sdonn 
31233332Sdonn     /*
31333332Sdonn      * Now find which registers were saved.
31433332Sdonn      * (expecting a probe instruction next)
31533332Sdonn      */
31633332Sdonn     iread(&instruc, addr, sizeof(instruc));
31733332Sdonn     if ((instruc&HIWORD) == TSTBSP) {
31833332Sdonn 	addr += 4;
31933332Sdonn 	iread(&instruc, addr, sizeof(instruc));
32033332Sdonn     }
32133332Sdonn     /*
32233332Sdonn      * expect either a moveml or a movl next
32333332Sdonn      */
32433332Sdonn     if ((instruc&INSMSK) == MOVLSP){
32533332Sdonn 	/*
32633332Sdonn 	 * Only one register saved.
32733332Sdonn 	 */
32833332Sdonn 	i = (instruc>>16) & 07;
32933332Sdonn 	dread(&(newfrp->save_reg[i]), regp, sizeof(Word));
33033332Sdonn 	savedregsmask = 1 << i;
33133332Sdonn     } else if ((instruc&HIWORD) == MOVEML) {
33233332Sdonn 	/*
33333332Sdonn 	 * Saving multiple registers or unoptimized code
33433332Sdonn 	 */
33533332Sdonn 	val = instruc & LOWORD;
33633332Sdonn 	savedregsmask = val;
33733332Sdonn 	i = 0;
33833332Sdonn 	while (val != 0) {
33933332Sdonn 	    if (val&1) {
34033332Sdonn 		dread(&(newfrp->save_reg[i]), regp, sizeof(Word));
34133332Sdonn 		regp += sizeof(Word);
34233332Sdonn 	    }
34333332Sdonn 	    val >>= 1;
34433332Sdonn 	    ++i;
34533332Sdonn 	}
34633332Sdonn     } else {
34733332Sdonn 	savedregsmask = 0;
34833332Sdonn     }
34933332Sdonn }
35033332Sdonn 
35133332Sdonn /*
35233332Sdonn  * Get the current frame information in the given Frame and store the
35333332Sdonn  * associated function in the given value-result parameter.
35433332Sdonn  */
35533332Sdonn 
getcurfunc(frp,fp)35633332Sdonn private getcurfunc (frp, fp)
35733332Sdonn Frame frp;
35833332Sdonn Symbol *fp;
35933332Sdonn {
36033332Sdonn     getcurframe(frp);
36133332Sdonn     *fp = whatblock(frp->save_pc);
36233332Sdonn }
36333332Sdonn 
36433332Sdonn /*
36533332Sdonn  * Return the frame associated with the next function up the call stack, or
36633332Sdonn  * nil if there is none.  The function is returned in a value-result parameter.
36733332Sdonn  * For "inline" functions the statically outer function and same frame
36833332Sdonn  * are returned.
36933332Sdonn  */
37033332Sdonn 
nextfunc(frp,fp)37133332Sdonn public Frame nextfunc (frp, fp)
37233332Sdonn Frame frp;
37333332Sdonn Symbol *fp;
37433332Sdonn {
37533332Sdonn     Symbol t;
37633332Sdonn     Frame nfrp;
37733332Sdonn 
37833332Sdonn     t = *fp;
37933332Sdonn     checkref(t);
38033332Sdonn     if (isinline(t)) {
38133332Sdonn 	t = container(t);
38233332Sdonn 	nfrp = frp;
38333332Sdonn     } else {
38433332Sdonn 	nfrp = nextframe(frp);
38533332Sdonn 	if (nfrp == nil) {
38633332Sdonn 	    t = nil;
38733332Sdonn 	} else {
38833332Sdonn 	    t = whatblock(nfrp->save_pc);
38933332Sdonn 	}
39033332Sdonn     }
39133332Sdonn     *fp = t;
39233332Sdonn     return nfrp;
39333332Sdonn }
39433332Sdonn 
39533332Sdonn /*
39633332Sdonn  * Return the frame associated with the given function.
39733332Sdonn  * If the function is nil, return the most recently activated frame.
39833332Sdonn  *
39933332Sdonn  * Static allocation for the frame.
40033332Sdonn  */
40133332Sdonn 
findframe(f)40233332Sdonn public Frame findframe(f)
40333332Sdonn Symbol f;
40433332Sdonn {
40533332Sdonn     Frame frp;
40633332Sdonn     static struct Frame frame;
40733332Sdonn     Symbol p;
40833332Sdonn     Boolean done;
40933332Sdonn 
41033332Sdonn     frp = &frame;
41133332Sdonn     getcurframe(frp);
41233332Sdonn     if (f != nil) {
41333332Sdonn 	if (f == curfunc and curframe != nil) {
41433332Sdonn 	    *frp = *curframe;
41533332Sdonn 	} else {
41633332Sdonn 	    done = false;
41733332Sdonn 	    p = whatblock(frp->save_pc);
41833332Sdonn 	    do {
41933332Sdonn 		if (p == f) {
42033332Sdonn 		    done = true;
42133332Sdonn 		} else if (p == program) {
42233332Sdonn 		    done = true;
42333332Sdonn 		    frp = nil;
42433332Sdonn 		} else {
42533332Sdonn 		    frp = nextfunc(frp, &p);
42633332Sdonn 		    if (frp == nil) {
42733332Sdonn 			done = true;
42833332Sdonn 		    }
42933332Sdonn 		}
43033332Sdonn 	    } while (not done);
43133332Sdonn 	}
43233332Sdonn     }
43333332Sdonn     return frp;
43433332Sdonn }
43533332Sdonn 
43633332Sdonn /*
43733332Sdonn  * Set the registers according to the given frame pointer.
43833332Sdonn  */
43933332Sdonn 
getnewregs(addr)44033332Sdonn public getnewregs (addr)
44133332Sdonn Address addr;
44233332Sdonn {
44333332Sdonn     struct Frame frame;
44433332Sdonn     integer i, j, mask;
44533332Sdonn 
44633332Sdonn     dread(&frame, addr, sizeof(frame));
44733332Sdonn     setreg(FRP, frame.save_fp);
44833332Sdonn     setreg(PROGCTR, frame.save_pc);
44933332Sdonn     pc = frame.save_pc;
45033332Sdonn     setcurfunc(whatblock(pc));
45133332Sdonn }
45233332Sdonn 
45333332Sdonn /*
45433332Sdonn  * Find the return address of the current procedure/function.
45533332Sdonn  */
45633332Sdonn 
return_addr()45733332Sdonn public Address return_addr()
45833332Sdonn {
45933332Sdonn     Frame frp;
46033332Sdonn     Address addr;
46133332Sdonn     struct Frame frame;
46233332Sdonn 
46333332Sdonn     frp = &frame;
46433332Sdonn     getcurframe(frp);
46533332Sdonn     frp = nextframe(frp);
46633332Sdonn     if (frp == nil) {
46733332Sdonn 	addr = 0;
46833332Sdonn     } else {
46933332Sdonn 	addr = frp->save_pc;
47033332Sdonn     }
47133332Sdonn     return addr;
47233332Sdonn }
47333332Sdonn 
47433332Sdonn /*
47533332Sdonn  * Push the value associated with the current function.
47633332Sdonn  */
47733332Sdonn 
pushretval(len,isindirect)47833332Sdonn public pushretval(len, isindirect)
47933332Sdonn integer len;
48033332Sdonn boolean isindirect;
48133332Sdonn {
48233332Sdonn     Word r0;
48333332Sdonn 
48433332Sdonn     r0 = reg(0);
48533332Sdonn     if (isindirect) {
48633332Sdonn 	rpush((Address) r0, len);
48733332Sdonn     } else {
48833332Sdonn 	switch (len) {
48933332Sdonn 	    case sizeof(char):
49033332Sdonn 		push(char, r0);
49133332Sdonn 		break;
49233332Sdonn 
49333332Sdonn 	    case sizeof(short):
49433332Sdonn 		push(short, r0);
49533332Sdonn 		break;
49633332Sdonn 
49733332Sdonn 	    default:
49833332Sdonn 		if (len == sizeof(Word)) {
49933332Sdonn 		    push(Word, r0);
50033332Sdonn 		} else if (len == 2*sizeof(Word)) {
50133332Sdonn 		    push(Word, r0);
50233332Sdonn 		    push(Word, reg(1));
50333332Sdonn 		} else {
50433332Sdonn 		    error("[internal error: bad size %d in pushretval]", len);
50533332Sdonn 		}
50633332Sdonn 		break;
50733332Sdonn 	}
50833332Sdonn     }
50933332Sdonn }
51033332Sdonn 
51133332Sdonn /*
51233332Sdonn  * Return the base address for locals in the given frame.
51333332Sdonn  */
51433332Sdonn 
locals_base(frp)51533332Sdonn public Address locals_base(frp)
51633332Sdonn Frame frp;
51733332Sdonn {
51833332Sdonn     return (frp == nil) ? reg(FRP) : frp->save_fp;
51933332Sdonn }
52033332Sdonn 
52133332Sdonn /*
52233332Sdonn  * Return the base address for arguments in the given frame.
52333332Sdonn  */
52433332Sdonn 
args_base(frp)52533332Sdonn public Address args_base(frp)
52633332Sdonn Frame frp;
52733332Sdonn {
52833332Sdonn     return (frp == nil) ? reg(FRP) : frp->save_fp;
52933332Sdonn }
53033332Sdonn 
53133332Sdonn /*
53233332Sdonn  * Return saved register n from the given frame.
53333332Sdonn  */
53433332Sdonn 
savereg(n,frp)53533332Sdonn public Word savereg(n, frp)
53633332Sdonn integer n;
53733332Sdonn Frame frp;
53833332Sdonn {
53933332Sdonn     Word w;
54033332Sdonn 
54133332Sdonn     if (frp == nil) {
54233332Sdonn 	w = reg(n);
54333332Sdonn     } else {
54433332Sdonn 	switch (n) {
54533332Sdonn 	    case FRP:
54633332Sdonn 		w = frp->save_fp;
54733332Sdonn 		break;
54833332Sdonn 
54933332Sdonn 	    case STKP:
55033332Sdonn 		w = reg(STKP);
55133332Sdonn 		break;
55233332Sdonn 
55333332Sdonn 	    case PROGCTR:
55433332Sdonn 		w = frp->save_pc;
55533332Sdonn 		break;
55633332Sdonn 
55733332Sdonn 	    default:
55833332Sdonn 		assert(n >= 0 and n < NSAVEREG);
55933332Sdonn 		w = frp->save_reg[n];
56033332Sdonn 		break;
56133332Sdonn 	}
56233332Sdonn     }
56333332Sdonn     return w;
56433332Sdonn }
56533332Sdonn 
56633332Sdonn /*
56733332Sdonn  * Return the nth argument to the current procedure.
56833332Sdonn  */
56933332Sdonn 
argn(n,frp)57033332Sdonn public Word argn(n, frp)
57133332Sdonn integer n;
57233332Sdonn Frame frp;
57333332Sdonn {
57433332Sdonn     Address argaddr;
57533332Sdonn     Word w;
57633332Sdonn 
57733332Sdonn     argaddr = args_base(frp) + 4 + (n * sizeof(Word));
57833332Sdonn     dread(&w, argaddr, sizeof(w));
57933332Sdonn     return w;
58033332Sdonn }
58133332Sdonn 
58233332Sdonn /*
58333332Sdonn  * Return the number of words of arguments passed to the procedure
58433332Sdonn  * associated with the given frame (it's a macro for the VAX).
58533332Sdonn  */
58633332Sdonn 
nargspassed(frp)58733332Sdonn public integer nargspassed (frp)
58833332Sdonn Frame frp;
58933332Sdonn {
59033332Sdonn     integer n;
59133332Sdonn     struct Frame frame;
59233332Sdonn 
59333332Sdonn     if (frp == nil) {
59433332Sdonn 	getcurframe(&frame);
59533332Sdonn 	n = frame.nargwords;
59633332Sdonn     } else {
59733332Sdonn 	n = frp->nargwords;
59833332Sdonn     }
59933332Sdonn     return n;
60033332Sdonn }
60133332Sdonn 
60233332Sdonn /*
60333332Sdonn  * Print a list of currently active blocks starting with most recent.
60433332Sdonn  */
60533332Sdonn 
wherecmd()60633332Sdonn public wherecmd()
60733332Sdonn {
60833332Sdonn     walkstack(false);
60933332Sdonn }
61033332Sdonn 
61133332Sdonn /*
61233332Sdonn  * Print the variables in the given frame or the current one if nil.
61333332Sdonn  */
61433332Sdonn 
dump(func)61533332Sdonn public dump (func)
61633332Sdonn Symbol func;
61733332Sdonn {
61833332Sdonn     Symbol f;
61933332Sdonn     Frame frp;
62033332Sdonn 
62133332Sdonn     if (func == nil) {
62233332Sdonn 	f = curfunc;
62333332Sdonn 	if (curframe != nil) {
62433332Sdonn 	    frp = curframe;
62533332Sdonn 	} else {
62633332Sdonn 	    frp = findframe(f);
62733332Sdonn 	}
62833332Sdonn     } else {
62933332Sdonn 	f = func;
63033332Sdonn 	frp = findframe(f);
63133332Sdonn     }
63233332Sdonn     showaggrs = true;
63333332Sdonn     printcallinfo(f, frp);
63433332Sdonn     dumpvars(f, frp);
63533332Sdonn }
63633332Sdonn 
63733332Sdonn /*
63833332Sdonn  * Dump all values.
63933332Sdonn  */
64033332Sdonn 
dumpall()64133332Sdonn public dumpall ()
64233332Sdonn {
64333332Sdonn     walkstack(true);
64433332Sdonn }
64533332Sdonn 
64633332Sdonn /*
64733332Sdonn  * Walk the stack of active procedures printing information
64833332Sdonn  * about each active procedure.
64933332Sdonn  */
65033332Sdonn 
walkstack(dumpvariables)65133332Sdonn private walkstack(dumpvariables)
65233332Sdonn Boolean dumpvariables;
65333332Sdonn {
65433332Sdonn     Frame frp;
65533332Sdonn     boolean save;
65633332Sdonn     Symbol f;
65733332Sdonn     struct Frame frame;
65833332Sdonn 
65933332Sdonn     if (notstarted(process) or isfinished(process)) {
66033332Sdonn 	error("program is not active");
66133332Sdonn     } else {
66233332Sdonn 	save = walkingstack;
66333332Sdonn 	walkingstack = true;
66433332Sdonn 	showaggrs = dumpvariables;
66533332Sdonn 	frp = &frame;
66633332Sdonn 	getcurfunc(frp, &f);
66733332Sdonn 	for (;;) {
66833332Sdonn 	    printcallinfo(f, frp);
66933332Sdonn 	    if (dumpvariables) {
67033332Sdonn 		dumpvars(f, frp);
67133332Sdonn 		putchar('\n');
67233332Sdonn 	    }
67333332Sdonn 	    frp = nextfunc(frp, &f);
67433332Sdonn 	    if (frp == nil or f == program) {
67533332Sdonn 		break;
67633332Sdonn 	    }
67733332Sdonn 	}
67833332Sdonn 	if (dumpvariables) {
67933332Sdonn 	    printf("in \"%s\":\n", symname(program));
68033332Sdonn 	    dumpvars(program, nil);
68133332Sdonn 	    putchar('\n');
68233332Sdonn 	}
68333332Sdonn 	walkingstack = save;
68433332Sdonn     }
68533332Sdonn }
68633332Sdonn 
68733332Sdonn /*
68833332Sdonn  * Print out the information about a call, i.e.,
68933332Sdonn  * routine name, parameter values, and source location.
69033332Sdonn  */
69133332Sdonn 
printcallinfo(f,frp)69233332Sdonn private printcallinfo (f, frp)
69333332Sdonn Symbol f;
69433332Sdonn Frame frp;
69533332Sdonn {
69633332Sdonn     Lineno line;
69733332Sdonn     Address savepc;
69833332Sdonn 
69933332Sdonn     savepc = frp->save_pc;
70033332Sdonn     if (frp->save_fp != reg(FRP)) {
70133332Sdonn 	savepc -= 1;
70233332Sdonn     }
70333332Sdonn     printname(stdout, f);
70433332Sdonn     if (not isinline(f)) {
70533332Sdonn 	printparams(f, frp);
70633332Sdonn     }
70733332Sdonn     line = srcline(savepc);
70833332Sdonn     if (line != 0) {
70933332Sdonn 	printf(", line %d", line);
71033332Sdonn 	printf(" in \"%s\"\n", srcfilename(savepc));
71133332Sdonn     } else {
71233332Sdonn 	printf(" at 0x%x\n", savepc);
71333332Sdonn     }
71433332Sdonn }
71533332Sdonn 
71633332Sdonn /*
71733332Sdonn  * Set the current function to the given symbol.
71833332Sdonn  * We must adjust "curframe" so that subsequent operations are
71933332Sdonn  * not confused; for simplicity we simply clear it.
72033332Sdonn  */
72133332Sdonn 
setcurfunc(f)72233332Sdonn public setcurfunc (f)
72333332Sdonn Symbol f;
72433332Sdonn {
72533332Sdonn     curfunc = f;
72633332Sdonn     curframe = nil;
72733332Sdonn }
72833332Sdonn 
72933332Sdonn /*
73033332Sdonn  * Return the frame for the current function.
73133332Sdonn  * The space for the frame is allocated statically.
73233332Sdonn  */
73333332Sdonn 
curfuncframe()73433332Sdonn public Frame curfuncframe ()
73533332Sdonn {
73633332Sdonn     static struct Frame frame;
73733332Sdonn     Frame frp;
73833332Sdonn 
73933332Sdonn     if (curframe == nil) {
74033332Sdonn 	frp = findframe(curfunc);
74133332Sdonn 	curframe = &curframerec;
74233332Sdonn 	*curframe = *frp;
74333332Sdonn     } else {
74433332Sdonn 	frp = &frame;
74533332Sdonn 	*frp = *curframe;
74633332Sdonn     }
74733332Sdonn     return frp;
74833332Sdonn }
74933332Sdonn 
75033332Sdonn /*
75133332Sdonn  * Set curfunc to be N up/down the stack from its current value.
75233332Sdonn  */
75333332Sdonn 
up(n)75433332Sdonn public up (n)
75533332Sdonn integer n;
75633332Sdonn {
75733332Sdonn     integer i;
75833332Sdonn     Symbol f;
75933332Sdonn     Frame frp;
76033332Sdonn     boolean done;
76133332Sdonn 
76233332Sdonn     if (not isactive(program)) {
76333332Sdonn 	error("program is not active");
76433332Sdonn     } else if (curfunc == nil) {
76533332Sdonn 	error("no current function");
76633332Sdonn     } else {
76733332Sdonn 	i = 0;
76833332Sdonn 	f = curfunc;
76933332Sdonn 	frp = curfuncframe();
77033332Sdonn 	done = false;
77133332Sdonn 	do {
77233332Sdonn 	    if (frp == nil) {
77333332Sdonn 		done = true;
77433332Sdonn 		error("not that many levels");
77533332Sdonn 	    } else if (i >= n) {
77633332Sdonn 		done = true;
77733332Sdonn 		curfunc = f;
77833332Sdonn 		curframe = &curframerec;
77933332Sdonn 		*curframe = *frp;
78033332Sdonn 		showaggrs = false;
78133332Sdonn 		printcallinfo(curfunc, curframe);
78233332Sdonn 	    } else if (f == program) {
78333332Sdonn 		done = true;
78433332Sdonn 		error("not that many levels");
78533332Sdonn 	    } else {
78633332Sdonn 		frp = nextfunc(frp, &f);
78733332Sdonn 	    }
78833332Sdonn 	    ++i;
78933332Sdonn 	} while (not done);
79033332Sdonn     }
79133332Sdonn }
79233332Sdonn 
down(n)79333332Sdonn public down (n)
79433332Sdonn integer n;
79533332Sdonn {
79633332Sdonn     integer i, depth;
79733332Sdonn     Frame frp, curfrp;
79833332Sdonn     Symbol f;
79933332Sdonn     struct Frame frame;
80033332Sdonn 
80133332Sdonn     if (not isactive(program)) {
80233332Sdonn 	error("program is not active");
80333332Sdonn     } else if (curfunc == nil) {
80433332Sdonn 	error("no current function");
80533332Sdonn     } else {
80633332Sdonn 	depth = 0;
80733332Sdonn 	frp = &frame;
80833332Sdonn 	getcurfunc(frp, &f);
80933332Sdonn 	if (curframe == nil) {
81033332Sdonn 	    curfrp = findframe(curfunc);
81133332Sdonn 	    curframe = &curframerec;
81233332Sdonn 	    *curframe = *curfrp;
81333332Sdonn 	}
81433332Sdonn 	while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) {
81533332Sdonn 	    frp = nextfunc(frp, &f);
81633332Sdonn 	    ++depth;
81733332Sdonn 	}
81833332Sdonn 	if (f == nil or n > depth) {
81933332Sdonn 	    error("not that many levels");
82033332Sdonn 	} else {
82133332Sdonn 	    depth -= n;
82233332Sdonn 	    frp = &frame;
82333332Sdonn 	    getcurfunc(frp, &f);
82433332Sdonn 	    for (i = 0; i < depth; i++) {
82533332Sdonn 		frp = nextfunc(frp, &f);
82633332Sdonn 		assert(frp != nil);
82733332Sdonn 	    }
82833332Sdonn 	    curfunc = f;
82933332Sdonn 	    *curframe = *frp;
83033332Sdonn 	    showaggrs = false;
83133332Sdonn 	    printcallinfo(curfunc, curframe);
83233332Sdonn 	}
83333332Sdonn     }
83433332Sdonn }
83533332Sdonn 
83633332Sdonn /*
83733332Sdonn  * Find the entry point of a procedure or function.
83833332Sdonn  */
83933332Sdonn 
findbeginning(f)84033332Sdonn public findbeginning (f)
84133332Sdonn Symbol f;
84233332Sdonn {
84333332Sdonn     if (isinternal(f)) {
84433332Sdonn 	f->symvalue.funcv.beginaddr += 18;	/* VAX only */
84533332Sdonn     } else {
84633332Sdonn 	/* on 68000's don't add for beginning of program */
84733332Sdonn 	if (f->symvalue.funcv.beginaddr != CODESTART) {
84833332Sdonn 	    f->symvalue.funcv.beginaddr += FUNCOFFSET;
84933332Sdonn 	}
85033332Sdonn     }
85133332Sdonn }
85233332Sdonn 
85333332Sdonn /*
85433332Sdonn  * Return the address corresponding to the first line in a function.
85533332Sdonn  */
85633332Sdonn 
firstline(f)85733332Sdonn public Address firstline(f)
85833332Sdonn Symbol f;
85933332Sdonn {
86033332Sdonn     Address addr;
86133332Sdonn 
86233332Sdonn     addr = codeloc(f);
86333332Sdonn     while (linelookup(addr) == 0 and addr < objsize) {
86433332Sdonn 	++addr;
86533332Sdonn     }
86633332Sdonn     if (addr == objsize) {
86733332Sdonn 	addr = -1;
86833332Sdonn     }
86933332Sdonn     return addr;
87033332Sdonn }
87133332Sdonn 
87233332Sdonn /*
87333332Sdonn  * Catcher drops strike three ...
87433332Sdonn  */
87533332Sdonn 
runtofirst()87633332Sdonn public runtofirst()
87733332Sdonn {
87833332Sdonn     Address addr, endaddr;
87933332Sdonn 
88033332Sdonn     addr = pc;
88133332Sdonn     endaddr = objsize + CODESTART;
88233332Sdonn     while (linelookup(addr) == 0 and addr < endaddr) {
88333332Sdonn 	++addr;
88433332Sdonn     }
88533332Sdonn     if (addr < endaddr) {
88633332Sdonn 	stepto(addr);
88733332Sdonn     }
88833332Sdonn }
88933332Sdonn 
89033332Sdonn /*
89133332Sdonn  * Return the address corresponding to the end of the program.
89233332Sdonn  *
89333332Sdonn  * We look for the entry to "exit".
89433332Sdonn  */
89533332Sdonn 
lastaddr()89633332Sdonn public Address lastaddr()
89733332Sdonn {
89833332Sdonn     Symbol s;
89933332Sdonn 
90033332Sdonn     s = lookup(identname("exit", true));
90133332Sdonn     if (s == nil) {
90233332Sdonn 	panic("can't find exit");
90333332Sdonn     }
90433332Sdonn     return codeloc(s);
90533332Sdonn }
90633332Sdonn 
90733332Sdonn /*
90833332Sdonn  * Decide if the given function is currently active.
90933332Sdonn  *
91033332Sdonn  * We avoid calls to "findframe" during a stack trace for efficiency.
91133332Sdonn  * Presumably information evaluated while walking the stack is active.
91233332Sdonn  */
91333332Sdonn 
isactive(f)91433332Sdonn public Boolean isactive (f)
91533332Sdonn Symbol f;
91633332Sdonn {
91733332Sdonn     Boolean b;
91833332Sdonn 
91933332Sdonn     if (isfinished(process)) {
92033332Sdonn 	b = false;
92133332Sdonn     } else {
92233332Sdonn 	if (walkingstack or f == program or f == nil or
92333332Sdonn 	  (ismodule(f) and isactive(container(f)))) {
92433332Sdonn 	    b = true;
92533332Sdonn 	} else {
92633332Sdonn 	    b = (Boolean) (findframe(f) != nil);
92733332Sdonn 	}
92833332Sdonn     }
92933332Sdonn     return b;
93033332Sdonn }
93133332Sdonn 
93233332Sdonn /*
93333332Sdonn  * Evaluate a call to a procedure.
93433332Sdonn  */
93533332Sdonn 
callproc(exprnode,isfunc)93633332Sdonn public callproc(exprnode, isfunc)
93733332Sdonn Node exprnode;
93833332Sdonn boolean isfunc;
93933332Sdonn {
94033332Sdonn     Node procnode, arglist;
94133332Sdonn     Symbol proc;
94233332Sdonn     integer argc;
94333332Sdonn 
94433332Sdonn     procnode = exprnode->value.arg[0];
94533332Sdonn     arglist = exprnode->value.arg[1];
94633332Sdonn     if (procnode->op != O_SYM) {
94733332Sdonn 	beginerrmsg();
94833332Sdonn 	fprintf(stderr, "can't call \"");
94933332Sdonn 	prtree(stderr, procnode);
95033332Sdonn 	fprintf(stderr, "\"");
95133332Sdonn 	enderrmsg();
95233332Sdonn     }
95333332Sdonn     assert(procnode->op == O_SYM);
95433332Sdonn     proc = procnode->value.sym;
95533332Sdonn     if (not isblock(proc)) {
95633332Sdonn 	error("\"%s\" is not a procedure or function", symname(proc));
95733332Sdonn     }
95833332Sdonn     endproc.isfunc = isfunc;
95933332Sdonn     endproc.callnode = exprnode;
96033332Sdonn     endproc.cmdnode = topnode;
96133332Sdonn     pushenv();
96233332Sdonn     pc = codeloc(proc);
96333332Sdonn     argc = pushargs(proc, arglist);
96433332Sdonn     setreg(FRP, 1);	/* have to ensure it's non-zero for return_addr() */
96533332Sdonn     beginproc(proc, argc);
96633332Sdonn     event_once(
96733332Sdonn 	build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)),
96833332Sdonn 	buildcmdlist(build(O_PROCRTN, proc))
96933332Sdonn     );
97033332Sdonn     isstopped = false;
97133332Sdonn     if (not bpact()) {
97233332Sdonn 	isstopped = true;
97333332Sdonn 	cont(0);
97433332Sdonn     }
97533332Sdonn     /*
97633332Sdonn      * bpact() won't return true, it will call printstatus() and go back
97733332Sdonn      * to command input if a breakpoint is found.
97833332Sdonn      */
97933332Sdonn     /* NOTREACHED */
98033332Sdonn }
98133332Sdonn 
98233332Sdonn /*
98333332Sdonn  * Push the arguments on the process' stack.  We do this by first
98433332Sdonn  * evaluating them on the "eval" stack, then copying into the process'
98533332Sdonn  * space.
98633332Sdonn  */
98733332Sdonn 
pushargs(proc,arglist)98833332Sdonn private integer pushargs(proc, arglist)
98933332Sdonn Symbol proc;
99033332Sdonn Node arglist;
99133332Sdonn {
99233332Sdonn     Stack *savesp;
99333332Sdonn     int argc, args_size;
99433332Sdonn 
99533332Sdonn     savesp = sp;
99633332Sdonn     if (varIsSet("$unsafecall")) {
99733332Sdonn 	argc = unsafe_evalargs(proc, arglist);
99833332Sdonn     } else {
99933332Sdonn 	argc = evalargs(proc, arglist);
100033332Sdonn     }
100133332Sdonn     args_size = sp - savesp;
100233332Sdonn     setreg(STKP, reg(STKP) - args_size);
100333332Sdonn     dwrite(savesp, reg(STKP), args_size);
100433332Sdonn     sp = savesp;
100533332Sdonn     return argc;
100633332Sdonn }
100733332Sdonn 
100833332Sdonn /*
100933332Sdonn  * Check to see if an expression is correct for a given parameter.
101033332Sdonn  * If the given parameter is false, don't worry about type inconsistencies.
101133332Sdonn  *
101233332Sdonn  * Return whether or not it is ok.
101333332Sdonn  */
101433332Sdonn 
chkparam(actual,formal,chk)101533332Sdonn private boolean chkparam (actual, formal, chk)
101633332Sdonn Node actual;
101733332Sdonn Symbol formal;
101833332Sdonn boolean chk;
101933332Sdonn {
102033332Sdonn     boolean b;
102133332Sdonn 
102233332Sdonn     b = true;
102333332Sdonn     if (chk) {
102433332Sdonn 	if (formal == nil) {
102533332Sdonn 	    beginerrmsg();
102633332Sdonn 	    fprintf(stderr, "too many parameters");
102733332Sdonn 	    b = false;
102833332Sdonn 	} else if (not compatible(formal->type, actual->nodetype)) {
102933332Sdonn 	    beginerrmsg();
103033332Sdonn 	    fprintf(stderr, "type mismatch for %s", symname(formal));
103133332Sdonn 	    b = false;
103233332Sdonn 	}
103333332Sdonn     }
103433332Sdonn     if (b and formal != nil and
103533332Sdonn 	isvarparam(formal) and not isopenarray(formal->type) and
103633332Sdonn 	not (
103733332Sdonn 	    actual->op == O_RVAL or actual->nodetype == t_addr or
103833332Sdonn 	    (
103933332Sdonn 		actual->op == O_TYPERENAME and
104033332Sdonn 		(
104133332Sdonn 		    actual->value.arg[0]->op == O_RVAL or
104233332Sdonn 		    actual->value.arg[0]->nodetype == t_addr
104333332Sdonn 		)
104433332Sdonn 	    )
104533332Sdonn 	)
104633332Sdonn     ) {
104733332Sdonn 	beginerrmsg();
104833332Sdonn 	fprintf(stderr, "expected variable, found \"");
104933332Sdonn 	prtree(stderr, actual);
105033332Sdonn 	fprintf(stderr, "\"");
105133332Sdonn 	b = false;
105233332Sdonn     }
105333332Sdonn     return b;
105433332Sdonn }
105533332Sdonn 
105633332Sdonn /*
105733332Sdonn  * Pass an expression to a particular parameter.
105833332Sdonn  *
105933332Sdonn  * Normally we pass either the address or value, but in some cases
106033332Sdonn  * (such as C strings) we want to copy the value onto the stack and
106133332Sdonn  * pass its address.
106233332Sdonn  *
106333332Sdonn  * Another special case raised by strings is the possibility that
106433332Sdonn  * the actual parameter will be larger than the formal, even with
106533332Sdonn  * appropriate type-checking.  This occurs because we assume during
106633332Sdonn  * evaluation that strings are null-terminated, whereas some languages,
106733332Sdonn  * notably Pascal, do not work under that assumption.
106833332Sdonn  */
106933332Sdonn 
passparam(actual,formal)107033332Sdonn private passparam (actual, formal)
107133332Sdonn Node actual;
107233332Sdonn Symbol formal;
107333332Sdonn {
107433332Sdonn     boolean b;
107533332Sdonn     Address addr;
107633332Sdonn     Stack *savesp;
107733332Sdonn     integer actsize, formsize;
107833332Sdonn 
107933332Sdonn     if (formal != nil and isvarparam(formal) and
108033332Sdonn 	(not isopenarray(formal->type))
108133332Sdonn     ) {
108233332Sdonn 	addr = lval(actual->value.arg[0]);
108333332Sdonn 	push(Address, addr);
108433332Sdonn     } else if (passaddr(formal, actual->nodetype)) {
108533332Sdonn 	savesp = sp;
108633332Sdonn 	eval(actual);
108733332Sdonn 	actsize = sp - savesp;
108833332Sdonn 	setreg(STKP,
108933332Sdonn 	    reg(STKP) - ((actsize + sizeof(Word) - 1) & ~(sizeof(Word) - 1))
109033332Sdonn 	);
109133332Sdonn 	dwrite(savesp, reg(STKP), actsize);
109233332Sdonn 	sp = savesp;
109333332Sdonn 	push(Address, reg(STKP));
109433332Sdonn 	if (formal != nil and isopenarray(formal->type)) {
109533332Sdonn 	    push(integer, actsize div size(formal->type->type));
109633332Sdonn 	}
109733332Sdonn     } else if (formal != nil) {
109833332Sdonn 	formsize = size(formal);
109933332Sdonn 	savesp = sp;
110033332Sdonn 	eval(actual);
110133332Sdonn 	actsize = sp - savesp;
110233332Sdonn 	if (actsize > formsize) {
110333332Sdonn 	    sp -= (actsize - formsize);
110433332Sdonn 	}
110533332Sdonn     } else {
110633332Sdonn 	eval(actual);
110733332Sdonn     }
110833332Sdonn }
110933332Sdonn 
111033332Sdonn /*
111133332Sdonn  * Evaluate an argument list left-to-right.
111233332Sdonn  */
111333332Sdonn 
evalargs(proc,arglist)111433332Sdonn private integer evalargs(proc, arglist)
111533332Sdonn Symbol proc;
111633332Sdonn Node arglist;
111733332Sdonn {
111833332Sdonn     Node p, actual;
111933332Sdonn     Symbol formal;
112033332Sdonn     Stack *savesp;
112133332Sdonn     integer count;
112233332Sdonn     boolean chk;
112333332Sdonn 
112433332Sdonn     savesp = sp;
112533332Sdonn     count = 0;
112633332Sdonn     formal = proc->chain;
112733332Sdonn     chk = (boolean) (not nosource(proc));
112833332Sdonn     for (p = arglist; p != nil; p = p->value.arg[1]) {
112933332Sdonn 	assert(p->op == O_COMMA);
113033332Sdonn 	actual = p->value.arg[0];
113133332Sdonn 	if (not chkparam(actual, formal, chk)) {
113233332Sdonn 	    fprintf(stderr, " in call to %s", symname(proc));
113333332Sdonn 	    sp = savesp;
113433332Sdonn 	    enderrmsg();
113533332Sdonn 	}
113633332Sdonn 	passparam(actual, formal);
113733332Sdonn 	if (formal != nil) {
113833332Sdonn 	    formal = formal->chain;
113933332Sdonn 	}
114033332Sdonn 	++count;
114133332Sdonn     }
114233332Sdonn     if (chk) {
114333332Sdonn 	if (formal != nil) {
114433332Sdonn 	    sp = savesp;
114533332Sdonn 	    error("not enough parameters to %s", symname(proc));
114633332Sdonn 	}
114733332Sdonn     }
114833332Sdonn     return count;
114933332Sdonn }
115033332Sdonn 
115133332Sdonn /*
115233332Sdonn  * Evaluate an argument list without any type checking.
115333332Sdonn  * This is only useful for procedures with a varying number of
115433332Sdonn  * arguments that are compiled -g.
115533332Sdonn  */
115633332Sdonn 
unsafe_evalargs(proc,arglist)115733332Sdonn private integer unsafe_evalargs (proc, arglist)
115833332Sdonn Symbol proc;
115933332Sdonn Node arglist;
116033332Sdonn {
116133332Sdonn     Node p;
116233332Sdonn     integer count;
116333332Sdonn 
116433332Sdonn     count = 0;
116533332Sdonn     for (p = arglist; p != nil; p = p->value.arg[1]) {
116633332Sdonn 	assert(p->op == O_COMMA);
116733332Sdonn 	eval(p->value.arg[0]);
116833332Sdonn 	++count;
116933332Sdonn     }
117033332Sdonn     return count;
117133332Sdonn }
117233332Sdonn 
procreturn(f)117333332Sdonn public procreturn(f)
117433332Sdonn Symbol f;
117533332Sdonn {
117633332Sdonn     integer retvalsize;
117733332Sdonn     Node tmp;
117833332Sdonn     char *copy;
117933332Sdonn 
118033332Sdonn     flushoutput();
118133332Sdonn     popenv();
118233332Sdonn     if (endproc.isfunc) {
118333332Sdonn 	retvalsize = size(f->type);
118433332Sdonn 	if (retvalsize > sizeof(long)) {
118533332Sdonn 	    pushretval(retvalsize, true);
118633332Sdonn 	    copy = newarr(char, retvalsize);
118733332Sdonn 	    popn(retvalsize, copy);
118833332Sdonn 	    tmp = build(O_SCON, copy);
118933332Sdonn 	} else {
119033332Sdonn 	    tmp = build(O_LCON, (long) (reg(0)));
119133332Sdonn 	}
119233332Sdonn 	tmp->nodetype = f->type;
119333332Sdonn 	tfree(endproc.callnode);
119433332Sdonn 	*(endproc.callnode) = *(tmp);
119533332Sdonn 	dispose(tmp);
119633332Sdonn 	eval(endproc.cmdnode);
119733332Sdonn     } else {
119833332Sdonn 	putchar('\n');
119933332Sdonn 	printname(stdout, f);
120033332Sdonn 	printf(" returns successfully\n");
120133332Sdonn     }
120233332Sdonn     erecover();
120333332Sdonn }
120433332Sdonn 
120533332Sdonn /*
120633332Sdonn  * Push the current environment.
120733332Sdonn  */
120833332Sdonn 
pushenv()120933332Sdonn private pushenv()
121033332Sdonn {
121133332Sdonn     push(Address, pc);
121233332Sdonn     push(Lineno, curline);
121333332Sdonn     push(String, cursource);
121433332Sdonn     push(Boolean, isstopped);
121533332Sdonn     push(Symbol, curfunc);
121633332Sdonn     push(Frame, curframe);
121733332Sdonn     push(struct Frame, curframerec);
121833332Sdonn     push(CallEnv, endproc);
121933332Sdonn     push(Word, reg(PROGCTR));
122033332Sdonn     push(Word, reg(STKP));
122133332Sdonn     push(Word, reg(FRP));
122233332Sdonn }
122333332Sdonn 
122433332Sdonn /*
122533332Sdonn  * Pop back to the real world.
122633332Sdonn  */
122733332Sdonn 
popenv()122833332Sdonn public popenv()
122933332Sdonn {
123033332Sdonn     String filename;
123133332Sdonn 
123233332Sdonn     setreg(FRP, pop(Word));
123333332Sdonn     setreg(STKP, pop(Word));
123433332Sdonn     setreg(PROGCTR, pop(Word));
123533332Sdonn     endproc = pop(CallEnv);
123633332Sdonn     curframerec = pop(struct Frame);
123733332Sdonn     curframe = pop(Frame);
123833332Sdonn     curfunc = pop(Symbol);
123933332Sdonn     isstopped = pop(Boolean);
124033332Sdonn     filename = pop(String);
124133332Sdonn     curline = pop(Lineno);
124233332Sdonn     pc = pop(Address);
124333332Sdonn     setsource(filename);
124433332Sdonn }
124533332Sdonn 
124633332Sdonn /*
124733332Sdonn  * Flush the debuggee's standard output.
124833332Sdonn  *
124933332Sdonn  * This is VERY dependent on the use of stdio.
125033332Sdonn  */
125133332Sdonn 
flushoutput()125233332Sdonn public flushoutput()
125333332Sdonn {
125433332Sdonn     Symbol p, iob;
125533332Sdonn     Stack *savesp;
125633332Sdonn 
125733332Sdonn     p = lookup(identname("fflush", true));
125833332Sdonn     while (p != nil and not isblock(p)) {
125933332Sdonn 	p = p->next_sym;
126033332Sdonn     }
126133332Sdonn     if (p != nil) {
126233332Sdonn 	iob = lookup(identname("_iob", true));
126333332Sdonn 	if (iob != nil) {
126433332Sdonn 	    pushenv();
126533332Sdonn 	    pc = codeloc(p) - FUNCOFFSET;
126633332Sdonn 	    savesp = sp;
126733332Sdonn 	    push(long, address(iob, nil) + sizeof(*stdout));
126833332Sdonn 	    setreg(STKP, reg(STKP) - sizeof(long));
126933332Sdonn 	    dwrite(savesp, reg(STKP), sizeof(long));
127033332Sdonn 	    sp = savesp;
127133332Sdonn 	    beginproc(p, 1);
127233332Sdonn 	    stepto(return_addr());
127333332Sdonn 	    popenv();
127433332Sdonn 	}
127533332Sdonn     }
127633332Sdonn }
1277