xref: /csrg-svn/old/dbx/runtime.c (revision 16636)
112546Scsvaf 
29678Slinton /* Copyright (c) 1982 Regents of the University of California */
39678Slinton 
4*16636Ssam static	char sccsid[] = "@(#)runtime.c	1.11 (Berkeley) 06/23/84";
59678Slinton 
69678Slinton /*
79678Slinton  * Runtime organization dependent routines, mostly dealing with
89678Slinton  * activation records.
99678Slinton  */
109678Slinton 
119678Slinton #include "defs.h"
129678Slinton #include "runtime.h"
139678Slinton #include "process.h"
149678Slinton #include "machine.h"
159678Slinton #include "events.h"
169678Slinton #include "mappings.h"
179678Slinton #include "symbols.h"
189678Slinton #include "tree.h"
199678Slinton #include "eval.h"
209678Slinton #include "operators.h"
219678Slinton #include "object.h"
2212546Scsvaf #include <sys/param.h>
239678Slinton 
249678Slinton #ifndef public
259678Slinton typedef struct Frame *Frame;
269678Slinton 
279678Slinton #include "machine.h"
289678Slinton #endif
299678Slinton 
309678Slinton #define NSAVEREG 12
319678Slinton 
329678Slinton struct Frame {
339678Slinton     Integer condition_handler;
349678Slinton     Integer mask;
359678Slinton     Address save_ap;		/* argument pointer */
369678Slinton     Address save_fp;		/* frame pointer */
379678Slinton     Address save_pc;		/* program counter */
389678Slinton     Word save_reg[NSAVEREG];	/* not necessarily there */
399678Slinton };
409678Slinton 
4116618Ssam private Frame curframe = nil;
4216618Ssam private struct Frame curframerec;
439678Slinton private Boolean walkingstack = false;
449678Slinton 
4516618Ssam #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp)
4616618Ssam 
479678Slinton /*
489678Slinton  * Set a frame to the current activation record.
499678Slinton  */
509678Slinton 
519678Slinton private getcurframe(frp)
529678Slinton register Frame frp;
539678Slinton {
549678Slinton     register int i;
559678Slinton 
569678Slinton     checkref(frp);
579678Slinton     frp->mask = reg(NREG);
589678Slinton     frp->save_ap = reg(ARGP);
599678Slinton     frp->save_fp = reg(FRP);
6012051Slinton     frp->save_pc = reg(PROGCTR) + 1;
619678Slinton     for (i = 0; i < NSAVEREG; i++) {
629678Slinton 	frp->save_reg[i] = reg(i);
639678Slinton     }
649678Slinton }
659678Slinton 
669678Slinton /*
679678Slinton  * Return a pointer to the next activation record up the stack.
689678Slinton  * Return nil if there is none.
699678Slinton  * Writes over space pointed to by given argument.
709678Slinton  */
719678Slinton 
729678Slinton #define bis(b, n) ((b & (1 << (n))) != 0)
739678Slinton 
749678Slinton private Frame nextframe(frp)
759678Slinton Frame frp;
769678Slinton {
779678Slinton     register Frame newfrp;
789678Slinton     struct Frame frame;
799678Slinton     register Integer i, j, mask;
8012546Scsvaf     Address prev_frame, callpc;
8113937Slinton     static Integer ntramp = 0;
829678Slinton 
839678Slinton     newfrp = frp;
8412546Scsvaf     prev_frame = frp->save_fp;
8512546Scsvaf 
8613937Slinton /*
8713937Slinton  *  The check for interrupt generated frames is taken from adb with only
8813937Slinton  *  partial understanding.  If you're in "sub" and on a sigxxx "sigsub"
8913937Slinton  *  gets control, then the stack does NOT look like <main, sub, sigsub>.
9012546Scsvaf  *
9112546Scsvaf  *  As best I can make out it looks like:
9212546Scsvaf  *
9313937Slinton  *     <main, (machine check exception block + sub), sysframe, sigsub>.
9413937Slinton  *
9513937Slinton  *  When the signal occurs an exception block and a frame for the routine
9613937Slinton  *  in which it occured are pushed on the user stack.  Then another frame
9713937Slinton  *  is pushed corresponding to a call from the kernel to sigsub.
9813937Slinton  *
9912546Scsvaf  *  The addr in sub at which the exception occured is not in sub.save_pc
10013937Slinton  *  but in the machine check exception block.  It is at the magic address
10114620Ssam  *  fp + 84.
10212546Scsvaf  *
10312546Scsvaf  *  The current approach ignores the sys_frame (what adb reports as sigtramp)
10413937Slinton  *  and takes the pc for sub from the exception block.  This allows the
10513937Slinton  *  "where" command to report <main, sub, sigsub>, which seems reasonable.
10612546Scsvaf  */
10712546Scsvaf 
10813937Slinton nextf:
10913937Slinton     dread(&frame, prev_frame, sizeof(struct Frame));
11013937Slinton     if (ntramp == 1) {
11114620Ssam 	dread(&callpc, prev_frame + 84, sizeof(callpc));
11213937Slinton     } else {
11313937Slinton 	callpc = frame.save_pc;
11413937Slinton     }
1159678Slinton     if (frame.save_fp == nil) {
1169678Slinton 	newfrp = nil;
11713937Slinton     } else if (callpc > 0x80000000 - 0x200 * UPAGES ) {
11812546Scsvaf 	 ntramp++;
11912546Scsvaf 	 prev_frame = frame.save_fp;
12012546Scsvaf 	 goto nextf;
12113937Slinton     } else {
12212546Scsvaf 	frame.save_pc = callpc;
12313937Slinton         ntramp = 0;
1249678Slinton 	mask = ((frame.mask >> 16) & 0x0fff);
1259678Slinton 	j = 0;
1269678Slinton 	for (i = 0; i < NSAVEREG; i++) {
1279678Slinton 	    if (bis(mask, i)) {
1289678Slinton 		newfrp->save_reg[i] = frame.save_reg[j];
1299678Slinton 		++j;
1309678Slinton 	    }
1319678Slinton 	}
1329678Slinton 	newfrp->condition_handler = frame.condition_handler;
1339678Slinton 	newfrp->mask = mask;
1349678Slinton 	newfrp->save_ap = frame.save_ap;
1359678Slinton 	newfrp->save_fp = frame.save_fp;
1369678Slinton 	newfrp->save_pc = frame.save_pc;
1379678Slinton     }
1389678Slinton     return newfrp;
1399678Slinton }
1409678Slinton 
1419678Slinton /*
14216618Ssam  * Get the current frame information in the given Frame and store the
14316618Ssam  * associated function in the given value-result parameter.
14416618Ssam  */
14516618Ssam 
14616618Ssam private getcurfunc (frp, fp)
14716618Ssam Frame frp;
14816618Ssam Symbol *fp;
14916618Ssam {
15016618Ssam     getcurframe(frp);
15116618Ssam     *fp = whatblock(frp->save_pc);
15216618Ssam }
15316618Ssam 
15416618Ssam /*
15516618Ssam  * Return the frame associated with the next function up the call stack, or
15616618Ssam  * nil if there is none.  The function is returned in a value-result parameter.
15716618Ssam  * For "inline" functions the statically outer function and same frame
15816618Ssam  * are returned.
15916618Ssam  */
16016618Ssam 
16116618Ssam private Frame nextfunc (frp, fp)
16216618Ssam Frame frp;
16316618Ssam Symbol *fp;
16416618Ssam {
16516618Ssam     Symbol t;
16616618Ssam     Frame nfrp;
16716618Ssam 
16816618Ssam     t = *fp;
16916618Ssam     checkref(t);
17016618Ssam     if (isinline(t)) {
17116618Ssam 	t = container(t);
17216618Ssam 	nfrp = frp;
17316618Ssam     } else {
17416618Ssam 	nfrp = nextframe(frp);
17516618Ssam 	if (nfrp == nil) {
17616618Ssam 	    t = nil;
17716618Ssam 	} else {
17816618Ssam 	    t = whatblock(nfrp->save_pc);
17916618Ssam 	}
18016618Ssam     }
18116618Ssam     *fp = t;
18216618Ssam     return nfrp;
18316618Ssam }
18416618Ssam 
18516618Ssam /*
1869678Slinton  * Return the frame associated with the given function.
1879678Slinton  * If the function is nil, return the most recently activated frame.
1889678Slinton  *
1899678Slinton  * Static allocation for the frame.
1909678Slinton  */
1919678Slinton 
1929678Slinton public Frame findframe(f)
1939678Slinton Symbol f;
1949678Slinton {
1959678Slinton     register Frame frp;
1969678Slinton     static struct Frame frame;
19711866Slinton     Symbol p;
1989678Slinton 
1999678Slinton     frp = &frame;
2009678Slinton     getcurframe(frp);
201*16636Ssam     if (f == nil)
202*16636Ssam 	return (frp);
203*16636Ssam     /*
204*16636Ssam      * Starting at the current stack frame,
205*16636Ssam      * walk backwards looking for a symbol
206*16636Ssam      * match.  Beware of local blocks which
207*16636Ssam      * have a back pointer but no stack frame.
208*16636Ssam      */
209*16636Ssam     p = whatblock(frp->save_pc);
210*16636Ssam     while (p != f) {
211*16636Ssam 	if (p == program) {
212*16636Ssam 	    frp = nil;
213*16636Ssam 	    break;
21415784Ssam 	}
215*16636Ssam 	if (isinline(p)) {
216*16636Ssam 	    p = container(p);
217*16636Ssam 	    continue;
218*16636Ssam 	}
219*16636Ssam 	frp = nextframe(frp);
220*16636Ssam 	if (frp == nil)
221*16636Ssam 	   break;
222*16636Ssam 	p = whatblock(frp->save_pc);
2239678Slinton     }
224*16636Ssam     return (frp);
2259678Slinton }
2269678Slinton 
2279678Slinton /*
2289678Slinton  * Find the return address of the current procedure/function.
2299678Slinton  */
2309678Slinton 
2319678Slinton public Address return_addr()
2329678Slinton {
2339678Slinton     Frame frp;
2349678Slinton     Address addr;
2359678Slinton     struct Frame frame;
2369678Slinton 
2379678Slinton     frp = &frame;
2389678Slinton     getcurframe(frp);
2399678Slinton     frp = nextframe(frp);
2409678Slinton     if (frp == nil) {
2419678Slinton 	addr = 0;
2429678Slinton     } else {
2439678Slinton 	addr = frp->save_pc;
2449678Slinton     }
2459678Slinton     return addr;
2469678Slinton }
2479678Slinton 
2489678Slinton /*
2499678Slinton  * Push the value associated with the current function.
2509678Slinton  */
2519678Slinton 
2529678Slinton public pushretval(len, isindirect)
2539678Slinton Integer len;
2549678Slinton Boolean isindirect;
2559678Slinton {
2569678Slinton     Word r0;
2579678Slinton 
2589678Slinton     r0 = reg(0);
2599678Slinton     if (isindirect) {
2609678Slinton 	rpush((Address) r0, len);
2619678Slinton     } else {
2629678Slinton 	switch (len) {
2639678Slinton 	    case sizeof(char):
2649678Slinton 		push(char, r0);
2659678Slinton 		break;
2669678Slinton 
2679678Slinton 	    case sizeof(short):
2689678Slinton 		push(short, r0);
2699678Slinton 		break;
2709678Slinton 
2719678Slinton 	    default:
2729678Slinton 		if (len == sizeof(Word)) {
2739678Slinton 		    push(Word, r0);
2749678Slinton 		} else if (len == 2*sizeof(Word)) {
2759678Slinton 		    push(Word, r0);
2769678Slinton 		    push(Word, reg(1));
2779678Slinton 		} else {
2789678Slinton 		    panic("not indirect in pushretval?");
2799678Slinton 		}
2809678Slinton 		break;
2819678Slinton 	}
2829678Slinton     }
2839678Slinton }
2849678Slinton 
2859678Slinton /*
2869678Slinton  * Return the base address for locals in the given frame.
2879678Slinton  */
2889678Slinton 
2899678Slinton public Address locals_base(frp)
2909678Slinton register Frame frp;
2919678Slinton {
2929678Slinton     return (frp == nil) ? reg(FRP) : frp->save_fp;
2939678Slinton }
2949678Slinton 
2959678Slinton /*
2969678Slinton  * Return the base address for arguments in the given frame.
2979678Slinton  */
2989678Slinton 
2999678Slinton public Address args_base(frp)
3009678Slinton register Frame frp;
3019678Slinton {
3029678Slinton     return (frp == nil) ? reg(ARGP) : frp->save_ap;
3039678Slinton }
3049678Slinton 
3059678Slinton /*
3069678Slinton  * Return saved register n from the given frame.
3079678Slinton  */
3089678Slinton 
3099678Slinton public Word savereg(n, frp)
3109678Slinton register Integer n;
3119678Slinton register Frame frp;
3129678Slinton {
3139678Slinton     register Word w;
3149678Slinton 
3159678Slinton     if (frp == nil) {
3169678Slinton 	w = reg(n);
3179678Slinton     } else {
3189678Slinton 	switch (n) {
3199678Slinton 	    case ARGP:
3209678Slinton 		w = frp->save_ap;
3219678Slinton 		break;
3229678Slinton 
3239678Slinton 	    case FRP:
3249678Slinton 		w = frp->save_fp;
3259678Slinton 		break;
3269678Slinton 
3279678Slinton 	    case STKP:
3289678Slinton 		w = reg(STKP);
3299678Slinton 		break;
3309678Slinton 
3319678Slinton 	    case PROGCTR:
3329678Slinton 		w = frp->save_pc;
3339678Slinton 		break;
3349678Slinton 
3359678Slinton 	    default:
3369678Slinton 		assert(n >= 0 and n < NSAVEREG);
3379678Slinton 		w = frp->save_reg[n];
3389678Slinton 		break;
3399678Slinton 	}
3409678Slinton     }
3419678Slinton     return w;
3429678Slinton }
3439678Slinton 
3449678Slinton /*
3459678Slinton  * Return the nth argument to the current procedure.
3469678Slinton  */
3479678Slinton 
3489678Slinton public Word argn(n, frp)
3499678Slinton Integer n;
3509678Slinton Frame frp;
3519678Slinton {
3529678Slinton     Word w;
3539678Slinton 
3549678Slinton     dread(&w, args_base(frp) + (n * sizeof(Word)), sizeof(w));
3559678Slinton     return w;
3569678Slinton }
3579678Slinton 
3589678Slinton /*
3599678Slinton  * Calculate the entry address for a procedure or function parameter,
3609678Slinton  * given the address of the descriptor.
3619678Slinton  */
3629678Slinton 
3639678Slinton public Address fparamaddr(a)
3649678Slinton Address a;
3659678Slinton {
3669678Slinton     Address r;
3679678Slinton 
3689678Slinton     dread(&r, a, sizeof(r));
3699678Slinton     return r;
3709678Slinton }
3719678Slinton 
3729678Slinton /*
3739678Slinton  * Print a list of currently active blocks starting with most recent.
3749678Slinton  */
3759678Slinton 
3769678Slinton public wherecmd()
3779678Slinton {
3789678Slinton     walkstack(false);
3799678Slinton }
3809678Slinton 
3819678Slinton /*
3829678Slinton  * Dump the world to the given file.
3839678Slinton  * Like "where", but variables are dumped also.
3849678Slinton  */
3859678Slinton 
3869678Slinton public dump()
3879678Slinton {
3889678Slinton     walkstack(true);
3899678Slinton }
3909678Slinton 
3919678Slinton /*
3929678Slinton  * Walk the stack of active procedures printing information
3939678Slinton  * about each active procedure.
3949678Slinton  */
3959678Slinton 
3969678Slinton private walkstack(dumpvariables)
3979678Slinton Boolean dumpvariables;
3989678Slinton {
3999678Slinton     register Frame frp;
4009678Slinton     register Boolean save;
4019678Slinton     register Lineno line;
40216618Ssam     Symbol f;
4039678Slinton     struct Frame frame;
4049678Slinton 
4059678Slinton     if (notstarted(process)) {
4069678Slinton 	error("program is not active");
4079678Slinton     } else {
4089678Slinton 	save = walkingstack;
4099678Slinton 	walkingstack = true;
4109678Slinton 	frp = &frame;
41116618Ssam 	getcurfunc(frp, &f);
4129678Slinton 	do {
4139678Slinton 	    printf("%s", symname(f));
41414442Slinton 	    if (not isinline(f)) {
41514442Slinton 		printparams(f, frp);
41614442Slinton 	    }
4179841Slinton 	    line = srcline(frp->save_pc - 1);
4189678Slinton 	    if (line != 0) {
4199678Slinton 		printf(", line %d", line);
4209841Slinton 		printf(" in \"%s\"\n", srcfilename(frp->save_pc - 1));
4219678Slinton 	    } else {
4229678Slinton 		printf(" at 0x%x\n", frp->save_pc);
4239678Slinton 	    }
4249678Slinton 	    if (dumpvariables) {
4259678Slinton 		dumpvars(f, frp);
4269678Slinton 		putchar('\n');
4279678Slinton 	    }
42816618Ssam 	    frp = nextfunc(frp, &f);
42911866Slinton 	} while (frp != nil and f != program);
4309678Slinton 	if (dumpvariables) {
4319678Slinton 	    printf("in \"%s\":\n", symname(program));
4329678Slinton 	    dumpvars(program, nil);
4339678Slinton 	    putchar('\n');
4349678Slinton 	}
4359678Slinton 	walkingstack = save;
4369678Slinton     }
4379678Slinton }
4389678Slinton 
4399678Slinton /*
44016618Ssam  * Set the current function to the given symbol.
44116618Ssam  * We must adjust "curframe" so that subsequent operations are
44216618Ssam  * not confused; for simplicity we simply clear it.
44316618Ssam  */
44416618Ssam 
44516618Ssam public setcurfunc (f)
44616618Ssam Symbol f;
44716618Ssam {
44816618Ssam     curfunc = f;
44916618Ssam     curframe = nil;
45016618Ssam }
45116618Ssam 
45216618Ssam /*
45316618Ssam  * Set curfunc to be N up/down the stack from its current value.
45416618Ssam  */
45516618Ssam 
45616618Ssam public up (n)
45716618Ssam integer n;
45816618Ssam {
45916618Ssam     integer i;
46016618Ssam     Symbol f;
46116618Ssam     Frame frp;
46216618Ssam     boolean done;
46316618Ssam 
46416618Ssam     if (not isactive(program)) {
46516618Ssam 	error("program is not active");
46616618Ssam     } else if (curfunc == nil) {
46716618Ssam 	error("no current function");
46816618Ssam     } else {
46916618Ssam 	i = 0;
47016618Ssam 	f = curfunc;
47116618Ssam 	if (curframe != nil) {
47216618Ssam 	    frp = curframe;
47316618Ssam 	} else {
47416618Ssam 	    frp = findframe(f);
47516618Ssam 	}
47616618Ssam 	done = false;
47716618Ssam 	do {
47816618Ssam 	    if (frp == nil) {
47916618Ssam 		done = true;
48016618Ssam 		error("not that many levels");
48116618Ssam 	    } else if (i >= n) {
48216618Ssam 		done = true;
48316618Ssam 		curfunc = f;
48416618Ssam 		curframe = &curframerec;
48516618Ssam 		*curframe = *frp;
48616618Ssam 	    } else if (f == program) {
48716618Ssam 		done = true;
48816618Ssam 		error("not that many levels");
48916618Ssam 	    } else {
49016618Ssam 		frp = nextfunc(frp, &f);
49116618Ssam 	    }
49216618Ssam 	    ++i;
49316618Ssam 	} while (not done);
49416618Ssam     }
49516618Ssam }
49616618Ssam 
49716618Ssam public down (n)
49816618Ssam integer n;
49916618Ssam {
50016618Ssam     integer i, depth;
50116618Ssam     register Frame frp;
50216618Ssam     Symbol f;
50316618Ssam     struct Frame frame;
50416618Ssam 
50516618Ssam     if (not isactive(program)) {
50616618Ssam 	error("program is not active");
50716618Ssam     } else if (curfunc == nil) {
50816618Ssam 	error("no current function");
50916618Ssam     } else {
51016618Ssam 	depth = 0;
51116618Ssam 	frp = &frame;
51216618Ssam 	getcurfunc(frp, &f);
51316618Ssam 	if (curframe == nil) {
51416618Ssam 	    curframe = &curframerec;
51516618Ssam 	    *curframe = *(findframe(curfunc));
51616618Ssam 	}
51716618Ssam 	while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) {
51816618Ssam 	    frp = nextfunc(frp, &f);
51916618Ssam 	    ++depth;
52016618Ssam 	}
52116618Ssam 	if (f == nil or n > depth) {
52216618Ssam 	    error("not that many levels");
52316618Ssam 	} else {
52416618Ssam 	    depth -= n;
52516618Ssam 	    frp = &frame;
52616618Ssam 	    getcurfunc(frp, &f);
52716618Ssam 	    for (i = 0; i < depth; i++) {
52816618Ssam 		frp = nextfunc(frp, &f);
52916618Ssam 		assert(frp != nil);
53016618Ssam 	    }
53116618Ssam 	    curfunc = f;
53216618Ssam 	    *curframe = *frp;
53316618Ssam 	}
53416618Ssam     }
53516618Ssam }
53616618Ssam 
53716618Ssam /*
5389678Slinton  * Find the entry point of a procedure or function.
5399678Slinton  */
5409678Slinton 
5419678Slinton public findbeginning(f)
5429678Slinton Symbol f;
5439678Slinton {
54416618Ssam     if (isinternal(f)) {
54516618Ssam 	f->symvalue.funcv.beginaddr += 15;
54616618Ssam     } else {
54716618Ssam 	f->symvalue.funcv.beginaddr += 2;
54816618Ssam     }
5499678Slinton }
5509678Slinton 
5519678Slinton /*
5529678Slinton  * Return the address corresponding to the first line in a function.
5539678Slinton  */
5549678Slinton 
5559678Slinton public Address firstline(f)
5569678Slinton Symbol f;
5579678Slinton {
5589678Slinton     Address addr;
5599678Slinton 
5609678Slinton     addr = codeloc(f);
5619678Slinton     while (linelookup(addr) == 0 and addr < objsize) {
5629678Slinton 	++addr;
5639678Slinton     }
5649678Slinton     if (addr == objsize) {
5659678Slinton 	addr = -1;
5669678Slinton     }
5679678Slinton     return addr;
5689678Slinton }
5699678Slinton 
5709678Slinton /*
5719678Slinton  * Catcher drops strike three ...
5729678Slinton  */
5739678Slinton 
5749678Slinton public runtofirst()
5759678Slinton {
5769678Slinton     Address addr;
5779678Slinton 
5789678Slinton     addr = pc;
5799678Slinton     while (linelookup(addr) == 0 and addr < objsize) {
5809678Slinton 	++addr;
5819678Slinton     }
5829678Slinton     if (addr < objsize) {
5839678Slinton 	stepto(addr);
5849678Slinton     }
5859678Slinton }
5869678Slinton 
5879678Slinton /*
5889678Slinton  * Return the address corresponding to the end of the program.
5899678Slinton  *
5909678Slinton  * We look for the entry to "exit".
5919678Slinton  */
5929678Slinton 
5939678Slinton public Address lastaddr()
5949678Slinton {
5959678Slinton     register Symbol s;
5969678Slinton 
5979678Slinton     s = lookup(identname("exit", true));
5989678Slinton     if (s == nil) {
5999678Slinton 	panic("can't find exit");
6009678Slinton     }
6019678Slinton     return codeloc(s);
6029678Slinton }
6039678Slinton 
6049678Slinton /*
6059678Slinton  * Decide if the given function is currently active.
6069678Slinton  *
6079678Slinton  * We avoid calls to "findframe" during a stack trace for efficiency.
6089678Slinton  * Presumably information evaluated while walking the stack is active.
6099678Slinton  */
6109678Slinton 
6119678Slinton public Boolean isactive(f)
6129678Slinton Symbol f;
6139678Slinton {
6149678Slinton     register Boolean b;
6159678Slinton 
6169678Slinton     if (isfinished(process)) {
6179678Slinton 	b = false;
6189678Slinton     } else {
6199678Slinton 	if (walkingstack or f == program or
6209678Slinton 	  (ismodule(f) and isactive(container(f)))) {
6219678Slinton 	    b = true;
6229678Slinton 	} else {
6239678Slinton 	    b = (Boolean) (findframe(f) != nil);
6249678Slinton 	}
6259678Slinton     }
6269678Slinton     return b;
6279678Slinton }
6289678Slinton 
6299678Slinton /*
6309678Slinton  * Evaluate a call to a procedure.
6319678Slinton  */
6329678Slinton 
6339678Slinton public callproc(procnode, arglist)
6349678Slinton Node procnode;
6359678Slinton Node arglist;
6369678Slinton {
6379678Slinton     Symbol proc;
6389678Slinton     Integer argc;
6399678Slinton 
6409678Slinton     if (procnode->op != O_SYM) {
6419678Slinton 	beginerrmsg();
6429678Slinton 	fprintf(stderr, "can't call \"");
6439678Slinton 	prtree(stderr, procnode);
6449678Slinton 	fprintf(stderr, "\"");
6459678Slinton 	enderrmsg();
6469678Slinton     }
6479678Slinton     assert(procnode->op == O_SYM);
6489678Slinton     proc = procnode->value.sym;
6499678Slinton     if (not isblock(proc)) {
6509678Slinton 	error("\"%s\" is not a procedure or function", symname(proc));
6519678Slinton     }
6529678Slinton     pushenv();
6539678Slinton     pc = codeloc(proc);
6549678Slinton     argc = pushargs(proc, arglist);
6559678Slinton     beginproc(proc, argc);
6569678Slinton     isstopped = true;
6579678Slinton     event_once(build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)),
6589678Slinton 	buildcmdlist(build(O_PROCRTN, proc)));
65916618Ssam     cont(0);
6609678Slinton     /* NOTREACHED */
6619678Slinton }
6629678Slinton 
6639678Slinton /*
6649678Slinton  * Push the arguments on the process' stack.  We do this by first
6659678Slinton  * evaluating them on the "eval" stack, then copying into the process'
6669678Slinton  * space.
6679678Slinton  */
6689678Slinton 
6699678Slinton private Integer pushargs(proc, arglist)
6709678Slinton Symbol proc;
6719678Slinton Node arglist;
6729678Slinton {
6739678Slinton     Stack *savesp;
6749678Slinton     int argc, args_size;
6759678Slinton 
6769678Slinton     savesp = sp;
6779678Slinton     argc = evalargs(proc, arglist);
6789678Slinton     args_size = sp - savesp;
6799678Slinton     setreg(STKP, reg(STKP) - args_size);
6809678Slinton     dwrite(savesp, reg(STKP), args_size);
6819678Slinton     sp = savesp;
6829678Slinton     return argc;
6839678Slinton }
6849678Slinton 
6859678Slinton /*
68616618Ssam  * Check to see if an expression is correct for a given parameter.
68716618Ssam  * If the given parameter is false, don't worry about type inconsistencies.
68816618Ssam  *
68916618Ssam  * Return whether or not it is ok.
6909678Slinton  */
6919678Slinton 
69216618Ssam private boolean chkparam (actual, formal, chk)
69316618Ssam Node actual;
69416618Ssam Symbol formal;
69516618Ssam boolean chk;
69616618Ssam {
69716618Ssam     boolean b;
69816618Ssam 
69916618Ssam     b = true;
70016618Ssam     if (chk) {
70116618Ssam 	if (formal == nil) {
70216618Ssam 	    beginerrmsg();
70316618Ssam 	    fprintf(stderr, "too many parameters");
70416618Ssam 	    b = false;
70516618Ssam 	} else if (not compatible(formal->type, actual->nodetype)) {
70616618Ssam 	    beginerrmsg();
70716618Ssam 	    fprintf(stderr, "type mismatch for %s", symname(formal));
70816618Ssam 	    b = false;
70916618Ssam 	}
71016618Ssam     }
71116618Ssam     if (b and formal != nil and isvarparam(formal) and
71216618Ssam 	not isopenarray(formal->type) and actual->op != O_RVAL)
71316618Ssam     {
71416618Ssam 	beginerrmsg();
71516618Ssam 	fprintf(stderr, "expected variable, found \"");
71616618Ssam 	prtree(stderr, actual);
71716618Ssam 	fprintf(stderr, "\"");
71816618Ssam 	b = false;
71916618Ssam     }
72016618Ssam     return b;
72116618Ssam }
72216618Ssam 
72316618Ssam /*
72416618Ssam  * Pass an expression to a particular parameter.
72516618Ssam  *
72616618Ssam  * Normally we pass either the address or value, but in some cases
72716618Ssam  * (such as C strings) we want to copy the value onto the stack and
72816618Ssam  * pass its address.
72916618Ssam  */
73016618Ssam 
73116618Ssam private passparam (actual, formal)
73216618Ssam Node actual;
73316618Ssam Symbol formal;
73416618Ssam {
73516618Ssam     boolean b;
73616618Ssam     Address addr;
73716618Ssam     Stack *savesp;
73816618Ssam     integer paramsize;
73916618Ssam 
74016618Ssam     if (isvarparam(formal) and not isopenarray(formal->type)) {
74116618Ssam 	addr = lval(actual->value.arg[0]);
74216618Ssam 	push(Address, addr);
74316618Ssam     } else if (passaddr(formal, actual->nodetype)) {
74416618Ssam 	savesp = sp;
74516618Ssam 	eval(actual);
74616618Ssam 	paramsize = sp - savesp;
74716618Ssam 	setreg(STKP, reg(STKP) - paramsize);
74816618Ssam 	dwrite(savesp, reg(STKP), paramsize);
74916618Ssam 	sp = savesp;
75016618Ssam 	push(Address, reg(STKP));
75116618Ssam 	if (formal != nil and isopenarray(formal->type)) {
75216618Ssam 	    push(integer, paramsize div size(formal->type->type));
75316618Ssam 	}
75416618Ssam     } else {
75516618Ssam 	eval(actual);
75616618Ssam     }
75716618Ssam }
75816618Ssam 
75916618Ssam /*
76016618Ssam  * Evaluate an argument list left-to-right.
76116618Ssam  */
76216618Ssam 
7639678Slinton private Integer evalargs(proc, arglist)
7649678Slinton Symbol proc;
7659678Slinton Node arglist;
7669678Slinton {
76716618Ssam     Node p, actual;
76816618Ssam     Symbol formal;
7699678Slinton     Stack *savesp;
7709678Slinton     Integer count;
77116618Ssam     boolean chk;
7729678Slinton 
7739678Slinton     savesp = sp;
7749678Slinton     count = 0;
77516618Ssam     formal = proc->chain;
77616618Ssam     chk = (boolean) (not nosource(proc));
7779678Slinton     for (p = arglist; p != nil; p = p->value.arg[1]) {
77816618Ssam 	assert(p->op == O_COMMA);
77916618Ssam 	actual = p->value.arg[0];
78016618Ssam 	if (not chkparam(actual, formal, chk)) {
78116618Ssam 	    fprintf(stderr, " in call to %s", symname(proc));
7829678Slinton 	    sp = savesp;
78316618Ssam 	    enderrmsg();
7849678Slinton 	}
78516618Ssam 	passparam(actual, formal);
78616618Ssam 	if (formal != nil) {
78716618Ssam 	    formal = formal->chain;
7889678Slinton 	}
7899678Slinton 	++count;
7909678Slinton     }
79116618Ssam     if (chk) {
79216618Ssam 	if (formal != nil) {
79316618Ssam 	    sp = savesp;
79416618Ssam 	    error("not enough parameters to %s", symname(proc));
79516618Ssam 	}
7969678Slinton     }
7979678Slinton     return count;
7989678Slinton }
7999678Slinton 
8009678Slinton public procreturn(f)
8019678Slinton Symbol f;
8029678Slinton {
8039678Slinton     flushoutput();
8049678Slinton     putchar('\n');
8059678Slinton     printname(stdout, f);
8069678Slinton     printf(" returns successfully\n", symname(f));
8079678Slinton     popenv();
8089678Slinton     erecover();
8099678Slinton }
8109678Slinton 
8119678Slinton /*
8129678Slinton  * Push the current environment.
8139678Slinton  */
8149678Slinton 
8159678Slinton private pushenv()
8169678Slinton {
8179678Slinton     push(Address, pc);
8189678Slinton     push(Lineno, curline);
8199678Slinton     push(String, cursource);
8209678Slinton     push(Boolean, isstopped);
8219678Slinton     push(Symbol, curfunc);
82216618Ssam     push(Frame, curframe);
82316618Ssam     push(struct Frame, curframerec);
8249678Slinton     push(Word, reg(PROGCTR));
8259678Slinton     push(Word, reg(STKP));
8269678Slinton }
8279678Slinton 
8289678Slinton /*
8299678Slinton  * Pop back to the real world.
8309678Slinton  */
8319678Slinton 
8329678Slinton public popenv()
8339678Slinton {
8349678Slinton     register String filename;
8359678Slinton 
8369678Slinton     setreg(STKP, pop(Word));
8379678Slinton     setreg(PROGCTR, pop(Word));
83816618Ssam     curframerec = pop(struct Frame);
83916618Ssam     curframe = pop(Frame);
8409678Slinton     curfunc = pop(Symbol);
8419678Slinton     isstopped = pop(Boolean);
8429678Slinton     filename = pop(String);
8439678Slinton     curline = pop(Lineno);
8449678Slinton     pc = pop(Address);
8459678Slinton     setsource(filename);
8469678Slinton }
8479678Slinton 
8489678Slinton /*
8499678Slinton  * Flush the debuggee's standard output.
8509678Slinton  *
8519678Slinton  * This is VERY dependent on the use of stdio.
8529678Slinton  */
8539678Slinton 
8549678Slinton public flushoutput()
8559678Slinton {
8569678Slinton     register Symbol p, iob;
8579678Slinton     register Stack *savesp;
8589678Slinton 
8599678Slinton     p = lookup(identname("fflush", true));
8609678Slinton     while (p != nil and not isblock(p)) {
8619678Slinton 	p = p->next_sym;
8629678Slinton     }
8639678Slinton     if (p != nil) {
8649678Slinton 	iob = lookup(identname("_iob", true));
8659678Slinton 	if (iob != nil) {
8669678Slinton 	    pushenv();
8679678Slinton 	    pc = codeloc(p);
8689678Slinton 	    savesp = sp;
8699678Slinton 	    push(long, address(iob, nil) + sizeof(struct _iobuf));
8709678Slinton 	    setreg(STKP, reg(STKP) - sizeof(long));
8719678Slinton 	    dwrite(savesp, reg(STKP), sizeof(long));
8729678Slinton 	    sp = savesp;
8739678Slinton 	    beginproc(p, 1);
8749678Slinton 	    stepto(return_addr());
8759678Slinton 	    popenv();
8769678Slinton 	}
8779678Slinton     }
8789678Slinton }
879