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