xref: /csrg-svn/old/dbx/runtime.sun.c (revision 42685)
138104Sbostic /*
238104Sbostic  * Copyright (c) 1983 The Regents of the University of California.
338104Sbostic  * All rights reserved.
438104Sbostic  *
5*42685Sbostic  * %sccs.include.redist.c%
638104Sbostic  */
738104Sbostic 
838104Sbostic #ifndef lint
9*42685Sbostic static char sccsid[] = "@(#)runtime.sun.c	5.2 (Berkeley) 06/01/90";
1038104Sbostic #endif /* not lint */
1138104Sbostic 
1238104Sbostic /*
1338104Sbostic  * Runtime organization dependent routines, mostly dealing with
1438104Sbostic  * activation records.
1538104Sbostic  */
1638104Sbostic 
1738104Sbostic #include "defs.h"
1838104Sbostic #include "runtime.h"
1938104Sbostic #include "process.h"
2038104Sbostic #include "machine.h"
2138104Sbostic #include "events.h"
2238104Sbostic #include "mappings.h"
2338104Sbostic #include "symbols.h"
2438104Sbostic #include "tree.h"
2538104Sbostic #include "eval.h"
2638104Sbostic #include "operators.h"
2738104Sbostic #include "object.h"
2838104Sbostic #include <sys/param.h>
2938104Sbostic #include <signal.h>
3038104Sbostic 
3138104Sbostic #ifndef public
3238104Sbostic typedef struct Frame *Frame;
3338104Sbostic 
3438104Sbostic #include "machine.h"
3538104Sbostic #endif
3638104Sbostic 
3738104Sbostic #define NSAVEREG 14
3838104Sbostic 
3938104Sbostic struct Frame {
4038104Sbostic     Address save_fp;		/* frame pointer */
4138104Sbostic     Address save_pc;		/* program counter */
4238104Sbostic     Word save_reg[NSAVEREG];	/* not necessarily there */
4338104Sbostic     integer nargwords;		/* computed, not stored */
4438104Sbostic };
4538104Sbostic 
4638104Sbostic private Frame curframe = nil;
4738104Sbostic private struct Frame curframerec;
4838104Sbostic private Boolean walkingstack = false;
4938104Sbostic 
5038104Sbostic #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp)
5138104Sbostic 
inSignalHandler(addr)5238104Sbostic private boolean inSignalHandler (addr)
5338104Sbostic Address addr;
5438104Sbostic {
5538104Sbostic     Symbol f;
5638104Sbostic 
5738104Sbostic #ifdef IRIS
5838104Sbostic     return false;
5938104Sbostic #else /* sun */
6038104Sbostic     f = whatblock(addr);
6138104Sbostic     return (boolean) (f != nil and streq(symname(f), "_sigtramp"));
6238104Sbostic #endif
6338104Sbostic }
6438104Sbostic 
6538104Sbostic typedef struct {
6638104Sbostic     Node callnode;
6738104Sbostic     Node cmdnode;
6838104Sbostic     boolean isfunc;
6938104Sbostic } CallEnv;
7038104Sbostic 
7138104Sbostic private CallEnv endproc;
7238104Sbostic 
7338104Sbostic /*
7438104Sbostic  * Set a frame to the current activation record.
7538104Sbostic  */
7638104Sbostic 
getcurframe(frp)7738104Sbostic private getcurframe(frp)
7838104Sbostic Frame frp;
7938104Sbostic {
8038104Sbostic     register int i;
8138104Sbostic 
8238104Sbostic     checkref(frp);
8338104Sbostic     frp->save_fp = reg(FRP);
8438104Sbostic     frp->save_pc = reg(PROGCTR);
8538104Sbostic     for (i = 0; i < NSAVEREG; i++) {
8638104Sbostic 	frp->save_reg[i] = reg(i);
8738104Sbostic     }
8838104Sbostic     if (frp->save_fp == nil) {
8938104Sbostic 	frp->nargwords = 0;
9038104Sbostic     } else {
9138104Sbostic 	findnumargs(frp);
9238104Sbostic     }
9338104Sbostic }
9438104Sbostic 
9538104Sbostic /*
9638104Sbostic  * Get the saved registers from one frame to another
9738104Sbostic  * given mask specifying which registers were actually saved.
9838104Sbostic  */
9938104Sbostic 
10038104Sbostic #define bis(b, n) ((b & (1 << (n))) != 0)
10138104Sbostic 
getsaveregs(newfrp,frp,mask)10238104Sbostic private getsaveregs (newfrp, frp, mask)
10338104Sbostic Frame newfrp, frp;
10438104Sbostic integer mask;
10538104Sbostic {
10638104Sbostic     integer i, j;
10738104Sbostic 
10838104Sbostic     j = 0;
10938104Sbostic     for (i = 0; i < NSAVEREG; i++) {
11038104Sbostic 	if (bis(mask, i)) {
11138104Sbostic 	    newfrp->save_reg[i] = frp->save_reg[j];
11238104Sbostic 	    ++j;
11338104Sbostic 	}
11438104Sbostic     }
11538104Sbostic }
11638104Sbostic 
11738104Sbostic /*
11838104Sbostic  * Return a pointer to the next activation record up the stack.
11938104Sbostic  * Return nil if there is none.
12038104Sbostic  * Writes over space pointed to by given argument.
12138104Sbostic  */
12238104Sbostic 
nextframe(frp)12338104Sbostic private Frame nextframe(frp)
12438104Sbostic Frame frp;
12538104Sbostic {
12638104Sbostic     Frame newfrp;
12738104Sbostic     struct Frame frame;
12838104Sbostic     integer mask;
12938104Sbostic     Address prev_frame, callpc, higher_fp, higher_pc;
13038104Sbostic     static integer ntramp = 0;
13138104Sbostic 
13238104Sbostic     newfrp = frp;
13338104Sbostic     prev_frame = frp->save_fp;
13438104Sbostic 
13538104Sbostic /*
13638104Sbostic  *  The check for interrupt generated frames is taken from adb with only
13738104Sbostic  *  partial understanding.  If you're in "sub" and on a sigxxx "sigsub"
13838104Sbostic  *  gets control, then the stack does NOT look like <main, sub, sigsub>.
13938104Sbostic  *
14038104Sbostic  *  As best I can make out it looks like:
14138104Sbostic  *
14238104Sbostic  *     <main, (machine check exception block + sub), sysframe, sigsub>.
14338104Sbostic  *
14438104Sbostic  *  When the signal occurs an exception block and a frame for the routine
14538104Sbostic  *  in which it occured are pushed on the user stack.  Then another frame
14638104Sbostic  *  is pushed corresponding to a call from the kernel to sigsub.
14738104Sbostic  *
14838104Sbostic  *  The addr in sub at which the exception occured is not in sub.save_pc
14938104Sbostic  *  but in the machine check exception block.  It is at the magic address
15038104Sbostic  *  fp + 84.
15138104Sbostic  *
15238104Sbostic  *  The current approach ignores the sys_frame (what adb reports as sigtramp)
15338104Sbostic  *  and takes the pc for sub from the exception block.  This allows the
15438104Sbostic  *  "where" command to report <main, sub, sigsub>, which seems reasonable.
15538104Sbostic  */
15638104Sbostic 
15738104Sbostic nextf:
15838104Sbostic     if (prev_frame + sizeof(struct Frame) <= USRSTACK) {
15938104Sbostic 	dread(&frame, prev_frame, sizeof(struct Frame));
16038104Sbostic     } else if (USRSTACK - prev_frame > 2 * sizeof(Word)) {
16138104Sbostic 	dread(&frame, prev_frame, USRSTACK - prev_frame);
16238104Sbostic     } else {
16338104Sbostic 	frame.save_fp = nil;
16438104Sbostic     }
16538104Sbostic     if (ntramp == 1) {
16638104Sbostic 	dread(&callpc, prev_frame + 92, sizeof(callpc));
16738104Sbostic     } else {
16838104Sbostic 	callpc = frame.save_pc;
16938104Sbostic     }
17038104Sbostic     if (frame.save_fp == nil or frame.save_pc == (Address) -1) {
17138104Sbostic 	newfrp = nil;
17238104Sbostic     } else {
17338104Sbostic 	if (inSignalHandler(callpc)) {
17438104Sbostic #	ifdef sun
17538104Sbostic 	    Address scp;
17638104Sbostic 
17738104Sbostic 	    dread(&scp, prev_frame + 16, sizeof(scp));
17838104Sbostic 	    dread(&callpc,
17938104Sbostic 		&(((struct sigcontext *)scp)->sc_pc), sizeof(Word)
18038104Sbostic 	    );
18138104Sbostic #	endif /* sun */
18238104Sbostic 	}
18338104Sbostic 	frame.save_pc = callpc;
18438104Sbostic         ntramp = 0;
18538104Sbostic 	higher_fp = frp->save_fp;
18638104Sbostic 	higher_pc = frp->save_pc;
18738104Sbostic 	newfrp->save_fp = frame.save_fp;
18838104Sbostic 	newfrp->save_pc = frame.save_pc;
18938104Sbostic 	    findnumargs(newfrp);
19038104Sbostic 	    findsavedregs(newfrp, higher_fp, higher_pc);
19138104Sbostic     }
19238104Sbostic     return newfrp;
19338104Sbostic }
19438104Sbostic 
19538104Sbostic /*
19638104Sbostic  * Finding the saved registers and number of arguments passed to
19738104Sbostic  * the current procedure is painful for the 68000.
19838104Sbostic  *
19938104Sbostic  * This is a version of the way adb for the 68000 does this.
20038104Sbostic  */
20138104Sbostic 
20238104Sbostic #define HIWORD	0xffff0000
20338104Sbostic #define LOWORD	0x0000ffff
20438104Sbostic #define LINKA6	0x4e560000	/* link a6,#x    */
20538104Sbostic #define ADDLSP	0xdffc0000	/* addl #x,sp    */
20638104Sbostic #define ADDWSP	0xdefc0000	/* addw #x,sp    */
20738104Sbostic #define LEASP	0x4fef0000	/* lea	sp@(x),sp*/
20838104Sbostic #define TSTBSP	0x4a2f0000	/* tstb sp@(x)   */
20938104Sbostic #define INSMSK	0xfff80000
21038104Sbostic #define MOVLSP	0x2e800000	/* movl dx,sp@   */
21138104Sbostic #define MOVLD0	0x20000000	/* movl d0,dx	 */
21238104Sbostic #define MOVLA0	0x20400000	/* movl d0,ax	 */
21338104Sbostic #define MVLMSK	0xf1ff0000
21438104Sbostic #define MOVEML	0x48d70000	/* moveml #x,sp@ */
21538104Sbostic #define JSR	0x4eb80000	/* jsr x.[WL]    */
21638104Sbostic #define JSRPC	0x4eba0000	/* jsr PC@( )    */
21738104Sbostic #define LONGBIT 0x00010000
21838104Sbostic #define BSR	0x61000000	/* bsr x	 */
21938104Sbostic #define BYTE3	0x0000ff00
22038104Sbostic #define LOBYTE	0x000000ff
22138104Sbostic #define ADQMSK	0xf1ff0000
22238104Sbostic #define ADDQSP	0x508f0000	/* addql #x,sp   */
22338104Sbostic #define ADDQWSP	0x504f0000	/* addqw #x,sp   */
22438104Sbostic 
22538104Sbostic private int savedregsmask;
22638104Sbostic private int savedregp;
22738104Sbostic 
22838104Sbostic /*
22938104Sbostic  * Find out how many words of arguments were passed to
23038104Sbostic  * the current procedure.
23138104Sbostic  */
23238104Sbostic 
findnumargs(newfrp)23338104Sbostic private findnumargs (newfrp)
23438104Sbostic Frame newfrp;
23538104Sbostic {
23638104Sbostic     integer val;
23738104Sbostic     integer instruc;
23838104Sbostic     Address addr;
23938104Sbostic 
24038104Sbostic     dread(&addr, newfrp->save_fp + sizeof(Address), sizeof(addr));
24138104Sbostic     iread(&instruc, addr, sizeof(instruc));
24238104Sbostic     if ((instruc&MVLMSK) == MOVLA0 or (instruc&MVLMSK) == MOVLD0) {
24338104Sbostic 	addr += 2;
24438104Sbostic 	iread(&instruc, addr, sizeof(instruc));
24538104Sbostic     }
24638104Sbostic     if ((instruc&ADQMSK) == ADDQSP or (instruc&ADQMSK) == ADDQWSP){
24738104Sbostic 	val = (instruc >> (16+9)) & 07;
24838104Sbostic 	if (val == 0) {
24938104Sbostic 	    val = 8;
25038104Sbostic 	}
25138104Sbostic     } else if ((instruc&HIWORD) == ADDLSP){
25238104Sbostic 	iread(&val, addr + 2, sizeof(val));
25338104Sbostic     } else if ((instruc&HIWORD) == ADDWSP || (instruc&HIWORD) == LEASP){
25438104Sbostic 	val = instruc&LOWORD;
25538104Sbostic     } else {
25638104Sbostic 	val = 0;
25738104Sbostic     }
25838104Sbostic     newfrp->nargwords = val / sizeof(Word);
25938104Sbostic }
26038104Sbostic 
26138104Sbostic /*
26238104Sbostic  * Get the saved registers for the given Frame.
26338104Sbostic  */
26438104Sbostic 
findsavedregs(newfrp,higher_fp,higher_pc)26538104Sbostic private findsavedregs (newfrp, higher_fp, higher_pc)
26638104Sbostic Frame newfrp;
26738104Sbostic register Address higher_fp, higher_pc;
26838104Sbostic {
26938104Sbostic     int val, regp, i;
27038104Sbostic     Address addr;
27138104Sbostic     Symbol func;
27238104Sbostic     Address calladdr;
27338104Sbostic     int instruc;
27438104Sbostic 
27538104Sbostic     /*
27638104Sbostic      * Find the entry point of the current procedure.
27738104Sbostic      * This is done by finding the procedure for the higher frame's pc
27838104Sbostic      * and taking its starting address.
27938104Sbostic      */
28038104Sbostic     func = whatblock(higher_pc, true);
28138104Sbostic     calladdr = codeloc(func) - FUNCOFFSET;
28238104Sbostic 
28338104Sbostic     /*
28438104Sbostic      * Look at the entry code for the current procedure
28538104Sbostic      * to determine which registers were saved, and where they are.
28638104Sbostic      *
28738104Sbostic      * First find the size of the activation record.
28838104Sbostic      */
28938104Sbostic     addr = calladdr;
29038104Sbostic     iread(&instruc, addr, sizeof(instruc));
29138104Sbostic     if ((instruc&HIWORD) == LINKA6) {
29238104Sbostic 	if ((instruc &= LOWORD) == 0) {
29338104Sbostic 	    /* look for addl */
29438104Sbostic 	    addr += 4;
29538104Sbostic 	    iread(&instruc, addr, sizeof(instruc));
29638104Sbostic 	    if ((instruc&HIWORD) == ADDLSP) {
29738104Sbostic 		iread(&instruc, addr + 2, sizeof(instruc));
29838104Sbostic 		addr += 6;
29938104Sbostic 	    } else {
30038104Sbostic 		instruc = 0;
30138104Sbostic 	    }
30238104Sbostic 	} else {
30338104Sbostic 	    /* link offset was non-zero -- sign extend it */
30438104Sbostic 	    instruc <<= 16;
30538104Sbostic 	    instruc >>= 16;
30638104Sbostic 	}
30738104Sbostic 	/* we now have the negative frame size */
30838104Sbostic 	regp = higher_fp + instruc;
30938104Sbostic 	savedregp = regp;
31038104Sbostic     }
31138104Sbostic 
31238104Sbostic     /*
31338104Sbostic      * Now find which registers were saved.
31438104Sbostic      * (expecting a probe instruction next)
31538104Sbostic      */
31638104Sbostic     iread(&instruc, addr, sizeof(instruc));
31738104Sbostic     if ((instruc&HIWORD) == TSTBSP) {
31838104Sbostic 	addr += 4;
31938104Sbostic 	iread(&instruc, addr, sizeof(instruc));
32038104Sbostic     }
32138104Sbostic     /*
32238104Sbostic      * expect either a moveml or a movl next
32338104Sbostic      */
32438104Sbostic     if ((instruc&INSMSK) == MOVLSP){
32538104Sbostic 	/*
32638104Sbostic 	 * Only one register saved.
32738104Sbostic 	 */
32838104Sbostic 	i = (instruc>>16) & 07;
32938104Sbostic 	dread(&(newfrp->save_reg[i]), regp, sizeof(Word));
33038104Sbostic 	savedregsmask = 1 << i;
33138104Sbostic     } else if ((instruc&HIWORD) == MOVEML) {
33238104Sbostic 	/*
33338104Sbostic 	 * Saving multiple registers or unoptimized code
33438104Sbostic 	 */
33538104Sbostic 	val = instruc & LOWORD;
33638104Sbostic 	savedregsmask = val;
33738104Sbostic 	i = 0;
33838104Sbostic 	while (val != 0) {
33938104Sbostic 	    if (val&1) {
34038104Sbostic 		dread(&(newfrp->save_reg[i]), regp, sizeof(Word));
34138104Sbostic 		regp += sizeof(Word);
34238104Sbostic 	    }
34338104Sbostic 	    val >>= 1;
34438104Sbostic 	    ++i;
34538104Sbostic 	}
34638104Sbostic     } else {
34738104Sbostic 	savedregsmask = 0;
34838104Sbostic     }
34938104Sbostic }
35038104Sbostic 
35138104Sbostic /*
35238104Sbostic  * Get the current frame information in the given Frame and store the
35338104Sbostic  * associated function in the given value-result parameter.
35438104Sbostic  */
35538104Sbostic 
getcurfunc(frp,fp)35638104Sbostic private getcurfunc (frp, fp)
35738104Sbostic Frame frp;
35838104Sbostic Symbol *fp;
35938104Sbostic {
36038104Sbostic     getcurframe(frp);
36138104Sbostic     *fp = whatblock(frp->save_pc);
36238104Sbostic }
36338104Sbostic 
36438104Sbostic /*
36538104Sbostic  * Return the frame associated with the next function up the call stack, or
36638104Sbostic  * nil if there is none.  The function is returned in a value-result parameter.
36738104Sbostic  * For "inline" functions the statically outer function and same frame
36838104Sbostic  * are returned.
36938104Sbostic  */
37038104Sbostic 
nextfunc(frp,fp)37138104Sbostic public Frame nextfunc (frp, fp)
37238104Sbostic Frame frp;
37338104Sbostic Symbol *fp;
37438104Sbostic {
37538104Sbostic     Symbol t;
37638104Sbostic     Frame nfrp;
37738104Sbostic 
37838104Sbostic     t = *fp;
37938104Sbostic     checkref(t);
38038104Sbostic     if (isinline(t)) {
38138104Sbostic 	t = container(t);
38238104Sbostic 	nfrp = frp;
38338104Sbostic     } else {
38438104Sbostic 	nfrp = nextframe(frp);
38538104Sbostic 	if (nfrp == nil) {
38638104Sbostic 	    t = nil;
38738104Sbostic 	} else {
38838104Sbostic 	    t = whatblock(nfrp->save_pc);
38938104Sbostic 	}
39038104Sbostic     }
39138104Sbostic     *fp = t;
39238104Sbostic     return nfrp;
39338104Sbostic }
39438104Sbostic 
39538104Sbostic /*
39638104Sbostic  * Return the frame associated with the given function.
39738104Sbostic  * If the function is nil, return the most recently activated frame.
39838104Sbostic  *
39938104Sbostic  * Static allocation for the frame.
40038104Sbostic  */
40138104Sbostic 
findframe(f)40238104Sbostic public Frame findframe(f)
40338104Sbostic Symbol f;
40438104Sbostic {
40538104Sbostic     Frame frp;
40638104Sbostic     static struct Frame frame;
40738104Sbostic     Symbol p;
40838104Sbostic     Boolean done;
40938104Sbostic 
41038104Sbostic     frp = &frame;
41138104Sbostic     getcurframe(frp);
41238104Sbostic     if (f != nil) {
41338104Sbostic 	if (f == curfunc and curframe != nil) {
41438104Sbostic 	    *frp = *curframe;
41538104Sbostic 	} else {
41638104Sbostic 	    done = false;
41738104Sbostic 	    p = whatblock(frp->save_pc);
41838104Sbostic 	    do {
41938104Sbostic 		if (p == f) {
42038104Sbostic 		    done = true;
42138104Sbostic 		} else if (p == program) {
42238104Sbostic 		    done = true;
42338104Sbostic 		    frp = nil;
42438104Sbostic 		} else {
42538104Sbostic 		    frp = nextfunc(frp, &p);
42638104Sbostic 		    if (frp == nil) {
42738104Sbostic 			done = true;
42838104Sbostic 		    }
42938104Sbostic 		}
43038104Sbostic 	    } while (not done);
43138104Sbostic 	}
43238104Sbostic     }
43338104Sbostic     return frp;
43438104Sbostic }
43538104Sbostic 
43638104Sbostic /*
43738104Sbostic  * Set the registers according to the given frame pointer.
43838104Sbostic  */
43938104Sbostic 
getnewregs(addr)44038104Sbostic public getnewregs (addr)
44138104Sbostic Address addr;
44238104Sbostic {
44338104Sbostic     struct Frame frame;
44438104Sbostic     integer i, j, mask;
44538104Sbostic 
44638104Sbostic     dread(&frame, addr, sizeof(frame));
44738104Sbostic     setreg(FRP, frame.save_fp);
44838104Sbostic     setreg(PROGCTR, frame.save_pc);
44938104Sbostic     pc = frame.save_pc;
45038104Sbostic     setcurfunc(whatblock(pc));
45138104Sbostic }
45238104Sbostic 
45338104Sbostic /*
45438104Sbostic  * Find the return address of the current procedure/function.
45538104Sbostic  */
45638104Sbostic 
return_addr()45738104Sbostic public Address return_addr()
45838104Sbostic {
45938104Sbostic     Frame frp;
46038104Sbostic     Address addr;
46138104Sbostic     struct Frame frame;
46238104Sbostic 
46338104Sbostic     frp = &frame;
46438104Sbostic     getcurframe(frp);
46538104Sbostic     frp = nextframe(frp);
46638104Sbostic     if (frp == nil) {
46738104Sbostic 	addr = 0;
46838104Sbostic     } else {
46938104Sbostic 	addr = frp->save_pc;
47038104Sbostic     }
47138104Sbostic     return addr;
47238104Sbostic }
47338104Sbostic 
47438104Sbostic /*
47538104Sbostic  * Push the value associated with the current function.
47638104Sbostic  */
47738104Sbostic 
pushretval(len,isindirect)47838104Sbostic public pushretval(len, isindirect)
47938104Sbostic integer len;
48038104Sbostic boolean isindirect;
48138104Sbostic {
48238104Sbostic     Word r0;
48338104Sbostic 
48438104Sbostic     r0 = reg(0);
48538104Sbostic     if (isindirect) {
48638104Sbostic 	rpush((Address) r0, len);
48738104Sbostic     } else {
48838104Sbostic 	switch (len) {
48938104Sbostic 	    case sizeof(char):
49038104Sbostic 		push(char, r0);
49138104Sbostic 		break;
49238104Sbostic 
49338104Sbostic 	    case sizeof(short):
49438104Sbostic 		push(short, r0);
49538104Sbostic 		break;
49638104Sbostic 
49738104Sbostic 	    default:
49838104Sbostic 		if (len == sizeof(Word)) {
49938104Sbostic 		    push(Word, r0);
50038104Sbostic 		} else if (len == 2*sizeof(Word)) {
50138104Sbostic 		    push(Word, r0);
50238104Sbostic 		    push(Word, reg(1));
50338104Sbostic 		} else {
50438104Sbostic 		    error("[internal error: bad size %d in pushretval]", len);
50538104Sbostic 		}
50638104Sbostic 		break;
50738104Sbostic 	}
50838104Sbostic     }
50938104Sbostic }
51038104Sbostic 
51138104Sbostic /*
51238104Sbostic  * Return the base address for locals in the given frame.
51338104Sbostic  */
51438104Sbostic 
locals_base(frp)51538104Sbostic public Address locals_base(frp)
51638104Sbostic Frame frp;
51738104Sbostic {
51838104Sbostic     return (frp == nil) ? reg(FRP) : frp->save_fp;
51938104Sbostic }
52038104Sbostic 
52138104Sbostic /*
52238104Sbostic  * Return the base address for arguments in the given frame.
52338104Sbostic  */
52438104Sbostic 
args_base(frp)52538104Sbostic public Address args_base(frp)
52638104Sbostic Frame frp;
52738104Sbostic {
52838104Sbostic     return (frp == nil) ? reg(FRP) : frp->save_fp;
52938104Sbostic }
53038104Sbostic 
53138104Sbostic /*
53238104Sbostic  * Return saved register n from the given frame.
53338104Sbostic  */
53438104Sbostic 
savereg(n,frp)53538104Sbostic public Word savereg(n, frp)
53638104Sbostic integer n;
53738104Sbostic Frame frp;
53838104Sbostic {
53938104Sbostic     Word w;
54038104Sbostic 
54138104Sbostic     if (frp == nil) {
54238104Sbostic 	w = reg(n);
54338104Sbostic     } else {
54438104Sbostic 	switch (n) {
54538104Sbostic 	    case FRP:
54638104Sbostic 		w = frp->save_fp;
54738104Sbostic 		break;
54838104Sbostic 
54938104Sbostic 	    case STKP:
55038104Sbostic 		w = reg(STKP);
55138104Sbostic 		break;
55238104Sbostic 
55338104Sbostic 	    case PROGCTR:
55438104Sbostic 		w = frp->save_pc;
55538104Sbostic 		break;
55638104Sbostic 
55738104Sbostic 	    default:
55838104Sbostic 		assert(n >= 0 and n < NSAVEREG);
55938104Sbostic 		w = frp->save_reg[n];
56038104Sbostic 		break;
56138104Sbostic 	}
56238104Sbostic     }
56338104Sbostic     return w;
56438104Sbostic }
56538104Sbostic 
56638104Sbostic /*
56738104Sbostic  * Return the nth argument to the current procedure.
56838104Sbostic  */
56938104Sbostic 
argn(n,frp)57038104Sbostic public Word argn(n, frp)
57138104Sbostic integer n;
57238104Sbostic Frame frp;
57338104Sbostic {
57438104Sbostic     Address argaddr;
57538104Sbostic     Word w;
57638104Sbostic 
57738104Sbostic     argaddr = args_base(frp) + 4 + (n * sizeof(Word));
57838104Sbostic     dread(&w, argaddr, sizeof(w));
57938104Sbostic     return w;
58038104Sbostic }
58138104Sbostic 
58238104Sbostic /*
58338104Sbostic  * Return the number of words of arguments passed to the procedure
58438104Sbostic  * associated with the given frame (it's a macro for the VAX).
58538104Sbostic  */
58638104Sbostic 
nargspassed(frp)58738104Sbostic public integer nargspassed (frp)
58838104Sbostic Frame frp;
58938104Sbostic {
59038104Sbostic     integer n;
59138104Sbostic     struct Frame frame;
59238104Sbostic 
59338104Sbostic     if (frp == nil) {
59438104Sbostic 	getcurframe(&frame);
59538104Sbostic 	n = frame.nargwords;
59638104Sbostic     } else {
59738104Sbostic 	n = frp->nargwords;
59838104Sbostic     }
59938104Sbostic     return n;
60038104Sbostic }
60138104Sbostic 
60238104Sbostic /*
60338104Sbostic  * Print a list of currently active blocks starting with most recent.
60438104Sbostic  */
60538104Sbostic 
wherecmd()60638104Sbostic public wherecmd()
60738104Sbostic {
60838104Sbostic     walkstack(false);
60938104Sbostic }
61038104Sbostic 
61138104Sbostic /*
61238104Sbostic  * Print the variables in the given frame or the current one if nil.
61338104Sbostic  */
61438104Sbostic 
dump(func)61538104Sbostic public dump (func)
61638104Sbostic Symbol func;
61738104Sbostic {
61838104Sbostic     Symbol f;
61938104Sbostic     Frame frp;
62038104Sbostic 
62138104Sbostic     if (func == nil) {
62238104Sbostic 	f = curfunc;
62338104Sbostic 	if (curframe != nil) {
62438104Sbostic 	    frp = curframe;
62538104Sbostic 	} else {
62638104Sbostic 	    frp = findframe(f);
62738104Sbostic 	}
62838104Sbostic     } else {
62938104Sbostic 	f = func;
63038104Sbostic 	frp = findframe(f);
63138104Sbostic     }
63238104Sbostic     showaggrs = true;
63338104Sbostic     printcallinfo(f, frp);
63438104Sbostic     dumpvars(f, frp);
63538104Sbostic }
63638104Sbostic 
63738104Sbostic /*
63838104Sbostic  * Dump all values.
63938104Sbostic  */
64038104Sbostic 
dumpall()64138104Sbostic public dumpall ()
64238104Sbostic {
64338104Sbostic     walkstack(true);
64438104Sbostic }
64538104Sbostic 
64638104Sbostic /*
64738104Sbostic  * Walk the stack of active procedures printing information
64838104Sbostic  * about each active procedure.
64938104Sbostic  */
65038104Sbostic 
walkstack(dumpvariables)65138104Sbostic private walkstack(dumpvariables)
65238104Sbostic Boolean dumpvariables;
65338104Sbostic {
65438104Sbostic     Frame frp;
65538104Sbostic     boolean save;
65638104Sbostic     Symbol f;
65738104Sbostic     struct Frame frame;
65838104Sbostic 
65938104Sbostic     if (notstarted(process) or isfinished(process)) {
66038104Sbostic 	error("program is not active");
66138104Sbostic     } else {
66238104Sbostic 	save = walkingstack;
66338104Sbostic 	walkingstack = true;
66438104Sbostic 	showaggrs = dumpvariables;
66538104Sbostic 	frp = &frame;
66638104Sbostic 	getcurfunc(frp, &f);
66738104Sbostic 	for (;;) {
66838104Sbostic 	    printcallinfo(f, frp);
66938104Sbostic 	    if (dumpvariables) {
67038104Sbostic 		dumpvars(f, frp);
67138104Sbostic 		putchar('\n');
67238104Sbostic 	    }
67338104Sbostic 	    frp = nextfunc(frp, &f);
67438104Sbostic 	    if (frp == nil or f == program) {
67538104Sbostic 		break;
67638104Sbostic 	    }
67738104Sbostic 	}
67838104Sbostic 	if (dumpvariables) {
67938104Sbostic 	    printf("in \"%s\":\n", symname(program));
68038104Sbostic 	    dumpvars(program, nil);
68138104Sbostic 	    putchar('\n');
68238104Sbostic 	}
68338104Sbostic 	walkingstack = save;
68438104Sbostic     }
68538104Sbostic }
68638104Sbostic 
68738104Sbostic /*
68838104Sbostic  * Print out the information about a call, i.e.,
68938104Sbostic  * routine name, parameter values, and source location.
69038104Sbostic  */
69138104Sbostic 
printcallinfo(f,frp)69238104Sbostic private printcallinfo (f, frp)
69338104Sbostic Symbol f;
69438104Sbostic Frame frp;
69538104Sbostic {
69638104Sbostic     Lineno line;
69738104Sbostic     Address savepc;
69838104Sbostic 
69938104Sbostic     savepc = frp->save_pc;
70038104Sbostic     if (frp->save_fp != reg(FRP)) {
70138104Sbostic 	savepc -= 1;
70238104Sbostic     }
70338104Sbostic     printname(stdout, f);
70438104Sbostic     if (not isinline(f)) {
70538104Sbostic 	printparams(f, frp);
70638104Sbostic     }
70738104Sbostic     line = srcline(savepc);
70838104Sbostic     if (line != 0) {
70938104Sbostic 	printf(", line %d", line);
71038104Sbostic 	printf(" in \"%s\"\n", srcfilename(savepc));
71138104Sbostic     } else {
71238104Sbostic 	printf(" at 0x%x\n", savepc);
71338104Sbostic     }
71438104Sbostic }
71538104Sbostic 
71638104Sbostic /*
71738104Sbostic  * Set the current function to the given symbol.
71838104Sbostic  * We must adjust "curframe" so that subsequent operations are
71938104Sbostic  * not confused; for simplicity we simply clear it.
72038104Sbostic  */
72138104Sbostic 
setcurfunc(f)72238104Sbostic public setcurfunc (f)
72338104Sbostic Symbol f;
72438104Sbostic {
72538104Sbostic     curfunc = f;
72638104Sbostic     curframe = nil;
72738104Sbostic }
72838104Sbostic 
72938104Sbostic /*
73038104Sbostic  * Return the frame for the current function.
73138104Sbostic  * The space for the frame is allocated statically.
73238104Sbostic  */
73338104Sbostic 
curfuncframe()73438104Sbostic public Frame curfuncframe ()
73538104Sbostic {
73638104Sbostic     static struct Frame frame;
73738104Sbostic     Frame frp;
73838104Sbostic 
73938104Sbostic     if (curframe == nil) {
74038104Sbostic 	frp = findframe(curfunc);
74138104Sbostic 	curframe = &curframerec;
74238104Sbostic 	*curframe = *frp;
74338104Sbostic     } else {
74438104Sbostic 	frp = &frame;
74538104Sbostic 	*frp = *curframe;
74638104Sbostic     }
74738104Sbostic     return frp;
74838104Sbostic }
74938104Sbostic 
75038104Sbostic /*
75138104Sbostic  * Set curfunc to be N up/down the stack from its current value.
75238104Sbostic  */
75338104Sbostic 
up(n)75438104Sbostic public up (n)
75538104Sbostic integer n;
75638104Sbostic {
75738104Sbostic     integer i;
75838104Sbostic     Symbol f;
75938104Sbostic     Frame frp;
76038104Sbostic     boolean done;
76138104Sbostic 
76238104Sbostic     if (not isactive(program)) {
76338104Sbostic 	error("program is not active");
76438104Sbostic     } else if (curfunc == nil) {
76538104Sbostic 	error("no current function");
76638104Sbostic     } else {
76738104Sbostic 	i = 0;
76838104Sbostic 	f = curfunc;
76938104Sbostic 	frp = curfuncframe();
77038104Sbostic 	done = false;
77138104Sbostic 	do {
77238104Sbostic 	    if (frp == nil) {
77338104Sbostic 		done = true;
77438104Sbostic 		error("not that many levels");
77538104Sbostic 	    } else if (i >= n) {
77638104Sbostic 		done = true;
77738104Sbostic 		curfunc = f;
77838104Sbostic 		curframe = &curframerec;
77938104Sbostic 		*curframe = *frp;
78038104Sbostic 		showaggrs = false;
78138104Sbostic 		printcallinfo(curfunc, curframe);
78238104Sbostic 	    } else if (f == program) {
78338104Sbostic 		done = true;
78438104Sbostic 		error("not that many levels");
78538104Sbostic 	    } else {
78638104Sbostic 		frp = nextfunc(frp, &f);
78738104Sbostic 	    }
78838104Sbostic 	    ++i;
78938104Sbostic 	} while (not done);
79038104Sbostic     }
79138104Sbostic }
79238104Sbostic 
down(n)79338104Sbostic public down (n)
79438104Sbostic integer n;
79538104Sbostic {
79638104Sbostic     integer i, depth;
79738104Sbostic     Frame frp, curfrp;
79838104Sbostic     Symbol f;
79938104Sbostic     struct Frame frame;
80038104Sbostic 
80138104Sbostic     if (not isactive(program)) {
80238104Sbostic 	error("program is not active");
80338104Sbostic     } else if (curfunc == nil) {
80438104Sbostic 	error("no current function");
80538104Sbostic     } else {
80638104Sbostic 	depth = 0;
80738104Sbostic 	frp = &frame;
80838104Sbostic 	getcurfunc(frp, &f);
80938104Sbostic 	if (curframe == nil) {
81038104Sbostic 	    curfrp = findframe(curfunc);
81138104Sbostic 	    curframe = &curframerec;
81238104Sbostic 	    *curframe = *curfrp;
81338104Sbostic 	}
81438104Sbostic 	while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) {
81538104Sbostic 	    frp = nextfunc(frp, &f);
81638104Sbostic 	    ++depth;
81738104Sbostic 	}
81838104Sbostic 	if (f == nil or n > depth) {
81938104Sbostic 	    error("not that many levels");
82038104Sbostic 	} else {
82138104Sbostic 	    depth -= n;
82238104Sbostic 	    frp = &frame;
82338104Sbostic 	    getcurfunc(frp, &f);
82438104Sbostic 	    for (i = 0; i < depth; i++) {
82538104Sbostic 		frp = nextfunc(frp, &f);
82638104Sbostic 		assert(frp != nil);
82738104Sbostic 	    }
82838104Sbostic 	    curfunc = f;
82938104Sbostic 	    *curframe = *frp;
83038104Sbostic 	    showaggrs = false;
83138104Sbostic 	    printcallinfo(curfunc, curframe);
83238104Sbostic 	}
83338104Sbostic     }
83438104Sbostic }
83538104Sbostic 
83638104Sbostic /*
83738104Sbostic  * Find the entry point of a procedure or function.
83838104Sbostic  */
83938104Sbostic 
findbeginning(f)84038104Sbostic public findbeginning (f)
84138104Sbostic Symbol f;
84238104Sbostic {
84338104Sbostic     if (isinternal(f)) {
84438104Sbostic 	f->symvalue.funcv.beginaddr += 18;	/* VAX only */
84538104Sbostic     } else {
84638104Sbostic 	/* on 68000's don't add for beginning of program */
84738104Sbostic 	if (f->symvalue.funcv.beginaddr != CODESTART) {
84838104Sbostic 	    f->symvalue.funcv.beginaddr += FUNCOFFSET;
84938104Sbostic 	}
85038104Sbostic     }
85138104Sbostic }
85238104Sbostic 
85338104Sbostic /*
85438104Sbostic  * Return the address corresponding to the first line in a function.
85538104Sbostic  */
85638104Sbostic 
firstline(f)85738104Sbostic public Address firstline(f)
85838104Sbostic Symbol f;
85938104Sbostic {
86038104Sbostic     Address addr;
86138104Sbostic 
86238104Sbostic     addr = codeloc(f);
86338104Sbostic     while (linelookup(addr) == 0 and addr < objsize) {
86438104Sbostic 	++addr;
86538104Sbostic     }
86638104Sbostic     if (addr == objsize) {
86738104Sbostic 	addr = -1;
86838104Sbostic     }
86938104Sbostic     return addr;
87038104Sbostic }
87138104Sbostic 
87238104Sbostic /*
87338104Sbostic  * Catcher drops strike three ...
87438104Sbostic  */
87538104Sbostic 
runtofirst()87638104Sbostic public runtofirst()
87738104Sbostic {
87838104Sbostic     Address addr, endaddr;
87938104Sbostic 
88038104Sbostic     addr = pc;
88138104Sbostic     endaddr = objsize + CODESTART;
88238104Sbostic     while (linelookup(addr) == 0 and addr < endaddr) {
88338104Sbostic 	++addr;
88438104Sbostic     }
88538104Sbostic     if (addr < endaddr) {
88638104Sbostic 	stepto(addr);
88738104Sbostic     }
88838104Sbostic }
88938104Sbostic 
89038104Sbostic /*
89138104Sbostic  * Return the address corresponding to the end of the program.
89238104Sbostic  *
89338104Sbostic  * We look for the entry to "exit".
89438104Sbostic  */
89538104Sbostic 
lastaddr()89638104Sbostic public Address lastaddr()
89738104Sbostic {
89838104Sbostic     Symbol s;
89938104Sbostic 
90038104Sbostic     s = lookup(identname("exit", true));
90138104Sbostic     if (s == nil) {
90238104Sbostic 	panic("can't find exit");
90338104Sbostic     }
90438104Sbostic     return codeloc(s);
90538104Sbostic }
90638104Sbostic 
90738104Sbostic /*
90838104Sbostic  * Decide if the given function is currently active.
90938104Sbostic  *
91038104Sbostic  * We avoid calls to "findframe" during a stack trace for efficiency.
91138104Sbostic  * Presumably information evaluated while walking the stack is active.
91238104Sbostic  */
91338104Sbostic 
isactive(f)91438104Sbostic public Boolean isactive (f)
91538104Sbostic Symbol f;
91638104Sbostic {
91738104Sbostic     Boolean b;
91838104Sbostic 
91938104Sbostic     if (isfinished(process)) {
92038104Sbostic 	b = false;
92138104Sbostic     } else {
92238104Sbostic 	if (walkingstack or f == program or f == nil or
92338104Sbostic 	  (ismodule(f) and isactive(container(f)))) {
92438104Sbostic 	    b = true;
92538104Sbostic 	} else {
92638104Sbostic 	    b = (Boolean) (findframe(f) != nil);
92738104Sbostic 	}
92838104Sbostic     }
92938104Sbostic     return b;
93038104Sbostic }
93138104Sbostic 
93238104Sbostic /*
93338104Sbostic  * Evaluate a call to a procedure.
93438104Sbostic  */
93538104Sbostic 
callproc(exprnode,isfunc)93638104Sbostic public callproc(exprnode, isfunc)
93738104Sbostic Node exprnode;
93838104Sbostic boolean isfunc;
93938104Sbostic {
94038104Sbostic     Node procnode, arglist;
94138104Sbostic     Symbol proc;
94238104Sbostic     integer argc;
94338104Sbostic 
94438104Sbostic     procnode = exprnode->value.arg[0];
94538104Sbostic     arglist = exprnode->value.arg[1];
94638104Sbostic     if (procnode->op != O_SYM) {
94738104Sbostic 	beginerrmsg();
94838104Sbostic 	fprintf(stderr, "can't call \"");
94938104Sbostic 	prtree(stderr, procnode);
95038104Sbostic 	fprintf(stderr, "\"");
95138104Sbostic 	enderrmsg();
95238104Sbostic     }
95338104Sbostic     assert(procnode->op == O_SYM);
95438104Sbostic     proc = procnode->value.sym;
95538104Sbostic     if (not isblock(proc)) {
95638104Sbostic 	error("\"%s\" is not a procedure or function", symname(proc));
95738104Sbostic     }
95838104Sbostic     endproc.isfunc = isfunc;
95938104Sbostic     endproc.callnode = exprnode;
96038104Sbostic     endproc.cmdnode = topnode;
96138104Sbostic     pushenv();
96238104Sbostic     pc = codeloc(proc);
96338104Sbostic     argc = pushargs(proc, arglist);
96438104Sbostic     setreg(FRP, 1);	/* have to ensure it's non-zero for return_addr() */
96538104Sbostic     beginproc(proc, argc);
96638104Sbostic     event_once(
96738104Sbostic 	build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)),
96838104Sbostic 	buildcmdlist(build(O_PROCRTN, proc))
96938104Sbostic     );
97038104Sbostic     isstopped = false;
97138104Sbostic     if (not bpact()) {
97238104Sbostic 	isstopped = true;
97338104Sbostic 	cont(0);
97438104Sbostic     }
97538104Sbostic     /*
97638104Sbostic      * bpact() won't return true, it will call printstatus() and go back
97738104Sbostic      * to command input if a breakpoint is found.
97838104Sbostic      */
97938104Sbostic     /* NOTREACHED */
98038104Sbostic }
98138104Sbostic 
98238104Sbostic /*
98338104Sbostic  * Push the arguments on the process' stack.  We do this by first
98438104Sbostic  * evaluating them on the "eval" stack, then copying into the process'
98538104Sbostic  * space.
98638104Sbostic  */
98738104Sbostic 
pushargs(proc,arglist)98838104Sbostic private integer pushargs(proc, arglist)
98938104Sbostic Symbol proc;
99038104Sbostic Node arglist;
99138104Sbostic {
99238104Sbostic     Stack *savesp;
99338104Sbostic     int argc, args_size;
99438104Sbostic 
99538104Sbostic     savesp = sp;
99638104Sbostic     if (varIsSet("$unsafecall")) {
99738104Sbostic 	argc = unsafe_evalargs(proc, arglist);
99838104Sbostic     } else {
99938104Sbostic 	argc = evalargs(proc, arglist);
100038104Sbostic     }
100138104Sbostic     args_size = sp - savesp;
100238104Sbostic     setreg(STKP, reg(STKP) - args_size);
100338104Sbostic     dwrite(savesp, reg(STKP), args_size);
100438104Sbostic     sp = savesp;
100538104Sbostic     return argc;
100638104Sbostic }
100738104Sbostic 
100838104Sbostic /*
100938104Sbostic  * Check to see if an expression is correct for a given parameter.
101038104Sbostic  * If the given parameter is false, don't worry about type inconsistencies.
101138104Sbostic  *
101238104Sbostic  * Return whether or not it is ok.
101338104Sbostic  */
101438104Sbostic 
chkparam(actual,formal,chk)101538104Sbostic private boolean chkparam (actual, formal, chk)
101638104Sbostic Node actual;
101738104Sbostic Symbol formal;
101838104Sbostic boolean chk;
101938104Sbostic {
102038104Sbostic     boolean b;
102138104Sbostic 
102238104Sbostic     b = true;
102338104Sbostic     if (chk) {
102438104Sbostic 	if (formal == nil) {
102538104Sbostic 	    beginerrmsg();
102638104Sbostic 	    fprintf(stderr, "too many parameters");
102738104Sbostic 	    b = false;
102838104Sbostic 	} else if (not compatible(formal->type, actual->nodetype)) {
102938104Sbostic 	    beginerrmsg();
103038104Sbostic 	    fprintf(stderr, "type mismatch for %s", symname(formal));
103138104Sbostic 	    b = false;
103238104Sbostic 	}
103338104Sbostic     }
103438104Sbostic     if (b and formal != nil and
103538104Sbostic 	isvarparam(formal) and not isopenarray(formal->type) and
103638104Sbostic 	not (
103738104Sbostic 	    actual->op == O_RVAL or actual->nodetype == t_addr or
103838104Sbostic 	    (
103938104Sbostic 		actual->op == O_TYPERENAME and
104038104Sbostic 		(
104138104Sbostic 		    actual->value.arg[0]->op == O_RVAL or
104238104Sbostic 		    actual->value.arg[0]->nodetype == t_addr
104338104Sbostic 		)
104438104Sbostic 	    )
104538104Sbostic 	)
104638104Sbostic     ) {
104738104Sbostic 	beginerrmsg();
104838104Sbostic 	fprintf(stderr, "expected variable, found \"");
104938104Sbostic 	prtree(stderr, actual);
105038104Sbostic 	fprintf(stderr, "\"");
105138104Sbostic 	b = false;
105238104Sbostic     }
105338104Sbostic     return b;
105438104Sbostic }
105538104Sbostic 
105638104Sbostic /*
105738104Sbostic  * Pass an expression to a particular parameter.
105838104Sbostic  *
105938104Sbostic  * Normally we pass either the address or value, but in some cases
106038104Sbostic  * (such as C strings) we want to copy the value onto the stack and
106138104Sbostic  * pass its address.
106238104Sbostic  *
106338104Sbostic  * Another special case raised by strings is the possibility that
106438104Sbostic  * the actual parameter will be larger than the formal, even with
106538104Sbostic  * appropriate type-checking.  This occurs because we assume during
106638104Sbostic  * evaluation that strings are null-terminated, whereas some languages,
106738104Sbostic  * notably Pascal, do not work under that assumption.
106838104Sbostic  */
106938104Sbostic 
passparam(actual,formal)107038104Sbostic private passparam (actual, formal)
107138104Sbostic Node actual;
107238104Sbostic Symbol formal;
107338104Sbostic {
107438104Sbostic     boolean b;
107538104Sbostic     Address addr;
107638104Sbostic     Stack *savesp;
107738104Sbostic     integer actsize, formsize;
107838104Sbostic 
107938104Sbostic     if (formal != nil and isvarparam(formal) and
108038104Sbostic 	(not isopenarray(formal->type))
108138104Sbostic     ) {
108238104Sbostic 	addr = lval(actual->value.arg[0]);
108338104Sbostic 	push(Address, addr);
108438104Sbostic     } else if (passaddr(formal, actual->nodetype)) {
108538104Sbostic 	savesp = sp;
108638104Sbostic 	eval(actual);
108738104Sbostic 	actsize = sp - savesp;
108838104Sbostic 	setreg(STKP,
108938104Sbostic 	    reg(STKP) - ((actsize + sizeof(Word) - 1) & ~(sizeof(Word) - 1))
109038104Sbostic 	);
109138104Sbostic 	dwrite(savesp, reg(STKP), actsize);
109238104Sbostic 	sp = savesp;
109338104Sbostic 	push(Address, reg(STKP));
109438104Sbostic 	if (formal != nil and isopenarray(formal->type)) {
109538104Sbostic 	    push(integer, actsize div size(formal->type->type));
109638104Sbostic 	}
109738104Sbostic     } else if (formal != nil) {
109838104Sbostic 	formsize = size(formal);
109938104Sbostic 	savesp = sp;
110038104Sbostic 	eval(actual);
110138104Sbostic 	actsize = sp - savesp;
110238104Sbostic 	if (actsize > formsize) {
110338104Sbostic 	    sp -= (actsize - formsize);
110438104Sbostic 	}
110538104Sbostic     } else {
110638104Sbostic 	eval(actual);
110738104Sbostic     }
110838104Sbostic }
110938104Sbostic 
111038104Sbostic /*
111138104Sbostic  * Evaluate an argument list left-to-right.
111238104Sbostic  */
111338104Sbostic 
evalargs(proc,arglist)111438104Sbostic private integer evalargs(proc, arglist)
111538104Sbostic Symbol proc;
111638104Sbostic Node arglist;
111738104Sbostic {
111838104Sbostic     Node p, actual;
111938104Sbostic     Symbol formal;
112038104Sbostic     Stack *savesp;
112138104Sbostic     integer count;
112238104Sbostic     boolean chk;
112338104Sbostic 
112438104Sbostic     savesp = sp;
112538104Sbostic     count = 0;
112638104Sbostic     formal = proc->chain;
112738104Sbostic     chk = (boolean) (not nosource(proc));
112838104Sbostic     for (p = arglist; p != nil; p = p->value.arg[1]) {
112938104Sbostic 	assert(p->op == O_COMMA);
113038104Sbostic 	actual = p->value.arg[0];
113138104Sbostic 	if (not chkparam(actual, formal, chk)) {
113238104Sbostic 	    fprintf(stderr, " in call to %s", symname(proc));
113338104Sbostic 	    sp = savesp;
113438104Sbostic 	    enderrmsg();
113538104Sbostic 	}
113638104Sbostic 	passparam(actual, formal);
113738104Sbostic 	if (formal != nil) {
113838104Sbostic 	    formal = formal->chain;
113938104Sbostic 	}
114038104Sbostic 	++count;
114138104Sbostic     }
114238104Sbostic     if (chk) {
114338104Sbostic 	if (formal != nil) {
114438104Sbostic 	    sp = savesp;
114538104Sbostic 	    error("not enough parameters to %s", symname(proc));
114638104Sbostic 	}
114738104Sbostic     }
114838104Sbostic     return count;
114938104Sbostic }
115038104Sbostic 
115138104Sbostic /*
115238104Sbostic  * Evaluate an argument list without any type checking.
115338104Sbostic  * This is only useful for procedures with a varying number of
115438104Sbostic  * arguments that are compiled -g.
115538104Sbostic  */
115638104Sbostic 
unsafe_evalargs(proc,arglist)115738104Sbostic private integer unsafe_evalargs (proc, arglist)
115838104Sbostic Symbol proc;
115938104Sbostic Node arglist;
116038104Sbostic {
116138104Sbostic     Node p;
116238104Sbostic     integer count;
116338104Sbostic 
116438104Sbostic     count = 0;
116538104Sbostic     for (p = arglist; p != nil; p = p->value.arg[1]) {
116638104Sbostic 	assert(p->op == O_COMMA);
116738104Sbostic 	eval(p->value.arg[0]);
116838104Sbostic 	++count;
116938104Sbostic     }
117038104Sbostic     return count;
117138104Sbostic }
117238104Sbostic 
procreturn(f)117338104Sbostic public procreturn(f)
117438104Sbostic Symbol f;
117538104Sbostic {
117638104Sbostic     integer retvalsize;
117738104Sbostic     Node tmp;
117838104Sbostic     char *copy;
117938104Sbostic 
118038104Sbostic     flushoutput();
118138104Sbostic     popenv();
118238104Sbostic     if (endproc.isfunc) {
118338104Sbostic 	retvalsize = size(f->type);
118438104Sbostic 	if (retvalsize > sizeof(long)) {
118538104Sbostic 	    pushretval(retvalsize, true);
118638104Sbostic 	    copy = newarr(char, retvalsize);
118738104Sbostic 	    popn(retvalsize, copy);
118838104Sbostic 	    tmp = build(O_SCON, copy);
118938104Sbostic 	} else {
119038104Sbostic 	    tmp = build(O_LCON, (long) (reg(0)));
119138104Sbostic 	}
119238104Sbostic 	tmp->nodetype = f->type;
119338104Sbostic 	tfree(endproc.callnode);
119438104Sbostic 	*(endproc.callnode) = *(tmp);
119538104Sbostic 	dispose(tmp);
119638104Sbostic 	eval(endproc.cmdnode);
119738104Sbostic     } else {
119838104Sbostic 	putchar('\n');
119938104Sbostic 	printname(stdout, f);
120038104Sbostic 	printf(" returns successfully\n");
120138104Sbostic     }
120238104Sbostic     erecover();
120338104Sbostic }
120438104Sbostic 
120538104Sbostic /*
120638104Sbostic  * Push the current environment.
120738104Sbostic  */
120838104Sbostic 
pushenv()120938104Sbostic private pushenv()
121038104Sbostic {
121138104Sbostic     push(Address, pc);
121238104Sbostic     push(Lineno, curline);
121338104Sbostic     push(String, cursource);
121438104Sbostic     push(Boolean, isstopped);
121538104Sbostic     push(Symbol, curfunc);
121638104Sbostic     push(Frame, curframe);
121738104Sbostic     push(struct Frame, curframerec);
121838104Sbostic     push(CallEnv, endproc);
121938104Sbostic     push(Word, reg(PROGCTR));
122038104Sbostic     push(Word, reg(STKP));
122138104Sbostic     push(Word, reg(FRP));
122238104Sbostic }
122338104Sbostic 
122438104Sbostic /*
122538104Sbostic  * Pop back to the real world.
122638104Sbostic  */
122738104Sbostic 
popenv()122838104Sbostic public popenv()
122938104Sbostic {
123038104Sbostic     String filename;
123138104Sbostic 
123238104Sbostic     setreg(FRP, pop(Word));
123338104Sbostic     setreg(STKP, pop(Word));
123438104Sbostic     setreg(PROGCTR, pop(Word));
123538104Sbostic     endproc = pop(CallEnv);
123638104Sbostic     curframerec = pop(struct Frame);
123738104Sbostic     curframe = pop(Frame);
123838104Sbostic     curfunc = pop(Symbol);
123938104Sbostic     isstopped = pop(Boolean);
124038104Sbostic     filename = pop(String);
124138104Sbostic     curline = pop(Lineno);
124238104Sbostic     pc = pop(Address);
124338104Sbostic     setsource(filename);
124438104Sbostic }
124538104Sbostic 
124638104Sbostic /*
124738104Sbostic  * Flush the debuggee's standard output.
124838104Sbostic  *
124938104Sbostic  * This is VERY dependent on the use of stdio.
125038104Sbostic  */
125138104Sbostic 
flushoutput()125238104Sbostic public flushoutput()
125338104Sbostic {
125438104Sbostic     Symbol p, iob;
125538104Sbostic     Stack *savesp;
125638104Sbostic 
125738104Sbostic     p = lookup(identname("fflush", true));
125838104Sbostic     while (p != nil and not isblock(p)) {
125938104Sbostic 	p = p->next_sym;
126038104Sbostic     }
126138104Sbostic     if (p != nil) {
126238104Sbostic 	iob = lookup(identname("_iob", true));
126338104Sbostic 	if (iob != nil) {
126438104Sbostic 	    pushenv();
126538104Sbostic 	    pc = codeloc(p) - FUNCOFFSET;
126638104Sbostic 	    savesp = sp;
126738104Sbostic 	    push(long, address(iob, nil) + sizeof(*stdout));
126838104Sbostic 	    setreg(STKP, reg(STKP) - sizeof(long));
126938104Sbostic 	    dwrite(savesp, reg(STKP), sizeof(long));
127038104Sbostic 	    sp = savesp;
127138104Sbostic 	    beginproc(p, 1);
127238104Sbostic 	    stepto(return_addr());
127338104Sbostic 	    popenv();
127438104Sbostic 	}
127538104Sbostic     }
127638104Sbostic }
1277