xref: /csrg-svn/old/dbx/runtime.c (revision 16618)
112546Scsvaf 
29678Slinton /* Copyright (c) 1982 Regents of the University of California */
39678Slinton 
4*16618Ssam static char sccsid[] = "@(#)runtime.c 1.8 8/10/83";
59678Slinton 
6*16618Ssam static char rcsid[] = "$Header: runtime.c,v 1.3 84/03/27 10:23:40 linton Exp $";
7*16618Ssam 
89678Slinton /*
99678Slinton  * Runtime organization dependent routines, mostly dealing with
109678Slinton  * activation records.
119678Slinton  */
129678Slinton 
139678Slinton #include "defs.h"
149678Slinton #include "runtime.h"
159678Slinton #include "process.h"
169678Slinton #include "machine.h"
179678Slinton #include "events.h"
189678Slinton #include "mappings.h"
199678Slinton #include "symbols.h"
209678Slinton #include "tree.h"
219678Slinton #include "eval.h"
229678Slinton #include "operators.h"
239678Slinton #include "object.h"
2412546Scsvaf #include <sys/param.h>
259678Slinton 
269678Slinton #ifndef public
279678Slinton typedef struct Frame *Frame;
289678Slinton 
299678Slinton #include "machine.h"
309678Slinton #endif
319678Slinton 
329678Slinton #define NSAVEREG 12
339678Slinton 
349678Slinton struct Frame {
359678Slinton     Integer condition_handler;
369678Slinton     Integer mask;
379678Slinton     Address save_ap;		/* argument pointer */
389678Slinton     Address save_fp;		/* frame pointer */
399678Slinton     Address save_pc;		/* program counter */
409678Slinton     Word save_reg[NSAVEREG];	/* not necessarily there */
419678Slinton };
429678Slinton 
43*16618Ssam private Frame curframe = nil;
44*16618Ssam private struct Frame curframerec;
459678Slinton private Boolean walkingstack = false;
469678Slinton 
47*16618Ssam #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp)
48*16618Ssam 
499678Slinton /*
509678Slinton  * Set a frame to the current activation record.
519678Slinton  */
529678Slinton 
539678Slinton private getcurframe(frp)
549678Slinton register Frame frp;
559678Slinton {
569678Slinton     register int i;
579678Slinton 
589678Slinton     checkref(frp);
599678Slinton     frp->mask = reg(NREG);
609678Slinton     frp->save_ap = reg(ARGP);
619678Slinton     frp->save_fp = reg(FRP);
6212051Slinton     frp->save_pc = reg(PROGCTR) + 1;
639678Slinton     for (i = 0; i < NSAVEREG; i++) {
649678Slinton 	frp->save_reg[i] = reg(i);
659678Slinton     }
669678Slinton }
679678Slinton 
689678Slinton /*
699678Slinton  * Return a pointer to the next activation record up the stack.
709678Slinton  * Return nil if there is none.
719678Slinton  * Writes over space pointed to by given argument.
729678Slinton  */
739678Slinton 
749678Slinton #define bis(b, n) ((b & (1 << (n))) != 0)
759678Slinton 
769678Slinton private Frame nextframe(frp)
779678Slinton Frame frp;
789678Slinton {
799678Slinton     register Frame newfrp;
809678Slinton     struct Frame frame;
819678Slinton     register Integer i, j, mask;
8212546Scsvaf     Address prev_frame, callpc;
8313937Slinton     static Integer ntramp = 0;
849678Slinton 
859678Slinton     newfrp = frp;
8612546Scsvaf     prev_frame = frp->save_fp;
8712546Scsvaf 
8813937Slinton /*
8913937Slinton  *  The check for interrupt generated frames is taken from adb with only
9013937Slinton  *  partial understanding.  If you're in "sub" and on a sigxxx "sigsub"
9113937Slinton  *  gets control, then the stack does NOT look like <main, sub, sigsub>.
9212546Scsvaf  *
9312546Scsvaf  *  As best I can make out it looks like:
9412546Scsvaf  *
9513937Slinton  *     <main, (machine check exception block + sub), sysframe, sigsub>.
9613937Slinton  *
9713937Slinton  *  When the signal occurs an exception block and a frame for the routine
9813937Slinton  *  in which it occured are pushed on the user stack.  Then another frame
9913937Slinton  *  is pushed corresponding to a call from the kernel to sigsub.
10013937Slinton  *
10112546Scsvaf  *  The addr in sub at which the exception occured is not in sub.save_pc
10213937Slinton  *  but in the machine check exception block.  It is at the magic address
10314620Ssam  *  fp + 84.
10412546Scsvaf  *
10512546Scsvaf  *  The current approach ignores the sys_frame (what adb reports as sigtramp)
10613937Slinton  *  and takes the pc for sub from the exception block.  This allows the
10713937Slinton  *  "where" command to report <main, sub, sigsub>, which seems reasonable.
10812546Scsvaf  */
10912546Scsvaf 
11013937Slinton nextf:
11113937Slinton     dread(&frame, prev_frame, sizeof(struct Frame));
11213937Slinton     if (ntramp == 1) {
11314620Ssam 	dread(&callpc, prev_frame + 84, sizeof(callpc));
11413937Slinton     } else {
11513937Slinton 	callpc = frame.save_pc;
11613937Slinton     }
1179678Slinton     if (frame.save_fp == nil) {
1189678Slinton 	newfrp = nil;
11913937Slinton     } else if (callpc > 0x80000000 - 0x200 * UPAGES ) {
12012546Scsvaf 	 ntramp++;
12112546Scsvaf 	 prev_frame = frame.save_fp;
12212546Scsvaf 	 goto nextf;
12313937Slinton     } else {
12412546Scsvaf 	frame.save_pc = callpc;
12513937Slinton         ntramp = 0;
1269678Slinton 	mask = ((frame.mask >> 16) & 0x0fff);
1279678Slinton 	j = 0;
1289678Slinton 	for (i = 0; i < NSAVEREG; i++) {
1299678Slinton 	    if (bis(mask, i)) {
1309678Slinton 		newfrp->save_reg[i] = frame.save_reg[j];
1319678Slinton 		++j;
1329678Slinton 	    }
1339678Slinton 	}
1349678Slinton 	newfrp->condition_handler = frame.condition_handler;
1359678Slinton 	newfrp->mask = mask;
1369678Slinton 	newfrp->save_ap = frame.save_ap;
1379678Slinton 	newfrp->save_fp = frame.save_fp;
1389678Slinton 	newfrp->save_pc = frame.save_pc;
1399678Slinton     }
1409678Slinton     return newfrp;
1419678Slinton }
1429678Slinton 
1439678Slinton /*
144*16618Ssam  * Get the current frame information in the given Frame and store the
145*16618Ssam  * associated function in the given value-result parameter.
146*16618Ssam  */
147*16618Ssam 
148*16618Ssam private getcurfunc (frp, fp)
149*16618Ssam Frame frp;
150*16618Ssam Symbol *fp;
151*16618Ssam {
152*16618Ssam     getcurframe(frp);
153*16618Ssam     *fp = whatblock(frp->save_pc);
154*16618Ssam }
155*16618Ssam 
156*16618Ssam /*
157*16618Ssam  * Return the frame associated with the next function up the call stack, or
158*16618Ssam  * nil if there is none.  The function is returned in a value-result parameter.
159*16618Ssam  * For "inline" functions the statically outer function and same frame
160*16618Ssam  * are returned.
161*16618Ssam  */
162*16618Ssam 
163*16618Ssam private Frame nextfunc (frp, fp)
164*16618Ssam Frame frp;
165*16618Ssam Symbol *fp;
166*16618Ssam {
167*16618Ssam     Symbol t;
168*16618Ssam     Frame nfrp;
169*16618Ssam 
170*16618Ssam     t = *fp;
171*16618Ssam     checkref(t);
172*16618Ssam     if (isinline(t)) {
173*16618Ssam 	t = container(t);
174*16618Ssam 	nfrp = frp;
175*16618Ssam     } else {
176*16618Ssam 	nfrp = nextframe(frp);
177*16618Ssam 	if (nfrp == nil) {
178*16618Ssam 	    t = nil;
179*16618Ssam 	} else {
180*16618Ssam 	    t = whatblock(nfrp->save_pc);
181*16618Ssam 	}
182*16618Ssam     }
183*16618Ssam     *fp = t;
184*16618Ssam     return nfrp;
185*16618Ssam }
186*16618Ssam 
187*16618Ssam /*
1889678Slinton  * Return the frame associated with the given function.
1899678Slinton  * If the function is nil, return the most recently activated frame.
1909678Slinton  *
1919678Slinton  * Static allocation for the frame.
1929678Slinton  */
1939678Slinton 
1949678Slinton public Frame findframe(f)
1959678Slinton Symbol f;
1969678Slinton {
1979678Slinton     register Frame frp;
1989678Slinton     static struct Frame frame;
19911866Slinton     Symbol p;
200*16618Ssam     Boolean done;
2019678Slinton 
2029678Slinton     frp = &frame;
2039678Slinton     getcurframe(frp);
204*16618Ssam     if (f != nil) {
205*16618Ssam 	if (f == curfunc and curframe != nil) {
206*16618Ssam 	    *frp = *curframe;
207*16618Ssam 	} else {
208*16618Ssam 	    done = false;
209*16618Ssam 	    p = whatblock(frp->save_pc);
210*16618Ssam 	    do {
211*16618Ssam 		if (p == f) {
212*16618Ssam 		    done = true;
213*16618Ssam 		} else if (p == program) {
214*16618Ssam 		    done = true;
215*16618Ssam 		    frp = nil;
216*16618Ssam 		} else {
217*16618Ssam 		    frp = nextfunc(frp, &p);
218*16618Ssam 		    if (frp == nil) {
219*16618Ssam 			done = true;
220*16618Ssam 		    }
221*16618Ssam 		}
222*16618Ssam 	    } while (not done);
22315784Ssam 	}
2249678Slinton     }
225*16618Ssam     return frp;
2269678Slinton }
2279678Slinton 
2289678Slinton /*
2299678Slinton  * Find the return address of the current procedure/function.
2309678Slinton  */
2319678Slinton 
2329678Slinton public Address return_addr()
2339678Slinton {
2349678Slinton     Frame frp;
2359678Slinton     Address addr;
2369678Slinton     struct Frame frame;
2379678Slinton 
2389678Slinton     frp = &frame;
2399678Slinton     getcurframe(frp);
2409678Slinton     frp = nextframe(frp);
2419678Slinton     if (frp == nil) {
2429678Slinton 	addr = 0;
2439678Slinton     } else {
2449678Slinton 	addr = frp->save_pc;
2459678Slinton     }
2469678Slinton     return addr;
2479678Slinton }
2489678Slinton 
2499678Slinton /*
2509678Slinton  * Push the value associated with the current function.
2519678Slinton  */
2529678Slinton 
2539678Slinton public pushretval(len, isindirect)
2549678Slinton Integer len;
2559678Slinton Boolean isindirect;
2569678Slinton {
2579678Slinton     Word r0;
2589678Slinton 
2599678Slinton     r0 = reg(0);
2609678Slinton     if (isindirect) {
2619678Slinton 	rpush((Address) r0, len);
2629678Slinton     } else {
2639678Slinton 	switch (len) {
2649678Slinton 	    case sizeof(char):
2659678Slinton 		push(char, r0);
2669678Slinton 		break;
2679678Slinton 
2689678Slinton 	    case sizeof(short):
2699678Slinton 		push(short, r0);
2709678Slinton 		break;
2719678Slinton 
2729678Slinton 	    default:
2739678Slinton 		if (len == sizeof(Word)) {
2749678Slinton 		    push(Word, r0);
2759678Slinton 		} else if (len == 2*sizeof(Word)) {
2769678Slinton 		    push(Word, r0);
2779678Slinton 		    push(Word, reg(1));
2789678Slinton 		} else {
2799678Slinton 		    panic("not indirect in pushretval?");
2809678Slinton 		}
2819678Slinton 		break;
2829678Slinton 	}
2839678Slinton     }
2849678Slinton }
2859678Slinton 
2869678Slinton /*
2879678Slinton  * Return the base address for locals in the given frame.
2889678Slinton  */
2899678Slinton 
2909678Slinton public Address locals_base(frp)
2919678Slinton register Frame frp;
2929678Slinton {
2939678Slinton     return (frp == nil) ? reg(FRP) : frp->save_fp;
2949678Slinton }
2959678Slinton 
2969678Slinton /*
2979678Slinton  * Return the base address for arguments in the given frame.
2989678Slinton  */
2999678Slinton 
3009678Slinton public Address args_base(frp)
3019678Slinton register Frame frp;
3029678Slinton {
3039678Slinton     return (frp == nil) ? reg(ARGP) : frp->save_ap;
3049678Slinton }
3059678Slinton 
3069678Slinton /*
3079678Slinton  * Return saved register n from the given frame.
3089678Slinton  */
3099678Slinton 
3109678Slinton public Word savereg(n, frp)
3119678Slinton register Integer n;
3129678Slinton register Frame frp;
3139678Slinton {
3149678Slinton     register Word w;
3159678Slinton 
3169678Slinton     if (frp == nil) {
3179678Slinton 	w = reg(n);
3189678Slinton     } else {
3199678Slinton 	switch (n) {
3209678Slinton 	    case ARGP:
3219678Slinton 		w = frp->save_ap;
3229678Slinton 		break;
3239678Slinton 
3249678Slinton 	    case FRP:
3259678Slinton 		w = frp->save_fp;
3269678Slinton 		break;
3279678Slinton 
3289678Slinton 	    case STKP:
3299678Slinton 		w = reg(STKP);
3309678Slinton 		break;
3319678Slinton 
3329678Slinton 	    case PROGCTR:
3339678Slinton 		w = frp->save_pc;
3349678Slinton 		break;
3359678Slinton 
3369678Slinton 	    default:
3379678Slinton 		assert(n >= 0 and n < NSAVEREG);
3389678Slinton 		w = frp->save_reg[n];
3399678Slinton 		break;
3409678Slinton 	}
3419678Slinton     }
3429678Slinton     return w;
3439678Slinton }
3449678Slinton 
3459678Slinton /*
3469678Slinton  * Return the nth argument to the current procedure.
3479678Slinton  */
3489678Slinton 
3499678Slinton public Word argn(n, frp)
3509678Slinton Integer n;
3519678Slinton Frame frp;
3529678Slinton {
3539678Slinton     Word w;
3549678Slinton 
3559678Slinton     dread(&w, args_base(frp) + (n * sizeof(Word)), sizeof(w));
3569678Slinton     return w;
3579678Slinton }
3589678Slinton 
3599678Slinton /*
3609678Slinton  * Calculate the entry address for a procedure or function parameter,
3619678Slinton  * given the address of the descriptor.
3629678Slinton  */
3639678Slinton 
3649678Slinton public Address fparamaddr(a)
3659678Slinton Address a;
3669678Slinton {
3679678Slinton     Address r;
3689678Slinton 
3699678Slinton     dread(&r, a, sizeof(r));
3709678Slinton     return r;
3719678Slinton }
3729678Slinton 
3739678Slinton /*
3749678Slinton  * Print a list of currently active blocks starting with most recent.
3759678Slinton  */
3769678Slinton 
3779678Slinton public wherecmd()
3789678Slinton {
3799678Slinton     walkstack(false);
3809678Slinton }
3819678Slinton 
3829678Slinton /*
3839678Slinton  * Dump the world to the given file.
3849678Slinton  * Like "where", but variables are dumped also.
3859678Slinton  */
3869678Slinton 
3879678Slinton public dump()
3889678Slinton {
3899678Slinton     walkstack(true);
3909678Slinton }
3919678Slinton 
3929678Slinton /*
3939678Slinton  * Walk the stack of active procedures printing information
3949678Slinton  * about each active procedure.
3959678Slinton  */
3969678Slinton 
3979678Slinton private walkstack(dumpvariables)
3989678Slinton Boolean dumpvariables;
3999678Slinton {
4009678Slinton     register Frame frp;
4019678Slinton     register Boolean save;
4029678Slinton     register Lineno line;
403*16618Ssam     Symbol f;
4049678Slinton     struct Frame frame;
4059678Slinton 
4069678Slinton     if (notstarted(process)) {
4079678Slinton 	error("program is not active");
4089678Slinton     } else {
4099678Slinton 	save = walkingstack;
4109678Slinton 	walkingstack = true;
4119678Slinton 	frp = &frame;
412*16618Ssam 	getcurfunc(frp, &f);
4139678Slinton 	do {
4149678Slinton 	    printf("%s", symname(f));
41514442Slinton 	    if (not isinline(f)) {
41614442Slinton 		printparams(f, frp);
41714442Slinton 	    }
4189841Slinton 	    line = srcline(frp->save_pc - 1);
4199678Slinton 	    if (line != 0) {
4209678Slinton 		printf(", line %d", line);
4219841Slinton 		printf(" in \"%s\"\n", srcfilename(frp->save_pc - 1));
4229678Slinton 	    } else {
4239678Slinton 		printf(" at 0x%x\n", frp->save_pc);
4249678Slinton 	    }
4259678Slinton 	    if (dumpvariables) {
4269678Slinton 		dumpvars(f, frp);
4279678Slinton 		putchar('\n');
4289678Slinton 	    }
429*16618Ssam 	    frp = nextfunc(frp, &f);
43011866Slinton 	} while (frp != nil and f != program);
4319678Slinton 	if (dumpvariables) {
4329678Slinton 	    printf("in \"%s\":\n", symname(program));
4339678Slinton 	    dumpvars(program, nil);
4349678Slinton 	    putchar('\n');
4359678Slinton 	}
4369678Slinton 	walkingstack = save;
4379678Slinton     }
4389678Slinton }
4399678Slinton 
4409678Slinton /*
441*16618Ssam  * Set the current function to the given symbol.
442*16618Ssam  * We must adjust "curframe" so that subsequent operations are
443*16618Ssam  * not confused; for simplicity we simply clear it.
444*16618Ssam  */
445*16618Ssam 
446*16618Ssam public setcurfunc (f)
447*16618Ssam Symbol f;
448*16618Ssam {
449*16618Ssam     curfunc = f;
450*16618Ssam     curframe = nil;
451*16618Ssam }
452*16618Ssam 
453*16618Ssam /*
454*16618Ssam  * Set curfunc to be N up/down the stack from its current value.
455*16618Ssam  */
456*16618Ssam 
457*16618Ssam public up (n)
458*16618Ssam integer n;
459*16618Ssam {
460*16618Ssam     integer i;
461*16618Ssam     Symbol f;
462*16618Ssam     Frame frp;
463*16618Ssam     boolean done;
464*16618Ssam 
465*16618Ssam     if (not isactive(program)) {
466*16618Ssam 	error("program is not active");
467*16618Ssam     } else if (curfunc == nil) {
468*16618Ssam 	error("no current function");
469*16618Ssam     } else {
470*16618Ssam 	i = 0;
471*16618Ssam 	f = curfunc;
472*16618Ssam 	if (curframe != nil) {
473*16618Ssam 	    frp = curframe;
474*16618Ssam 	} else {
475*16618Ssam 	    frp = findframe(f);
476*16618Ssam 	}
477*16618Ssam 	done = false;
478*16618Ssam 	do {
479*16618Ssam 	    if (frp == nil) {
480*16618Ssam 		done = true;
481*16618Ssam 		error("not that many levels");
482*16618Ssam 	    } else if (i >= n) {
483*16618Ssam 		done = true;
484*16618Ssam 		curfunc = f;
485*16618Ssam 		curframe = &curframerec;
486*16618Ssam 		*curframe = *frp;
487*16618Ssam 	    } else if (f == program) {
488*16618Ssam 		done = true;
489*16618Ssam 		error("not that many levels");
490*16618Ssam 	    } else {
491*16618Ssam 		frp = nextfunc(frp, &f);
492*16618Ssam 	    }
493*16618Ssam 	    ++i;
494*16618Ssam 	} while (not done);
495*16618Ssam     }
496*16618Ssam }
497*16618Ssam 
498*16618Ssam public down (n)
499*16618Ssam integer n;
500*16618Ssam {
501*16618Ssam     integer i, depth;
502*16618Ssam     register Frame frp;
503*16618Ssam     Symbol f;
504*16618Ssam     struct Frame frame;
505*16618Ssam 
506*16618Ssam     if (not isactive(program)) {
507*16618Ssam 	error("program is not active");
508*16618Ssam     } else if (curfunc == nil) {
509*16618Ssam 	error("no current function");
510*16618Ssam     } else {
511*16618Ssam 	depth = 0;
512*16618Ssam 	frp = &frame;
513*16618Ssam 	getcurfunc(frp, &f);
514*16618Ssam 	if (curframe == nil) {
515*16618Ssam 	    curframe = &curframerec;
516*16618Ssam 	    *curframe = *(findframe(curfunc));
517*16618Ssam 	}
518*16618Ssam 	while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) {
519*16618Ssam 	    frp = nextfunc(frp, &f);
520*16618Ssam 	    ++depth;
521*16618Ssam 	}
522*16618Ssam 	if (f == nil or n > depth) {
523*16618Ssam 	    error("not that many levels");
524*16618Ssam 	} else {
525*16618Ssam 	    depth -= n;
526*16618Ssam 	    frp = &frame;
527*16618Ssam 	    getcurfunc(frp, &f);
528*16618Ssam 	    for (i = 0; i < depth; i++) {
529*16618Ssam 		frp = nextfunc(frp, &f);
530*16618Ssam 		assert(frp != nil);
531*16618Ssam 	    }
532*16618Ssam 	    curfunc = f;
533*16618Ssam 	    *curframe = *frp;
534*16618Ssam 	}
535*16618Ssam     }
536*16618Ssam }
537*16618Ssam 
538*16618Ssam /*
5399678Slinton  * Find the entry point of a procedure or function.
5409678Slinton  */
5419678Slinton 
5429678Slinton public findbeginning(f)
5439678Slinton Symbol f;
5449678Slinton {
545*16618Ssam     if (isinternal(f)) {
546*16618Ssam 	f->symvalue.funcv.beginaddr += 15;
547*16618Ssam     } else {
548*16618Ssam 	f->symvalue.funcv.beginaddr += 2;
549*16618Ssam     }
5509678Slinton }
5519678Slinton 
5529678Slinton /*
5539678Slinton  * Return the address corresponding to the first line in a function.
5549678Slinton  */
5559678Slinton 
5569678Slinton public Address firstline(f)
5579678Slinton Symbol f;
5589678Slinton {
5599678Slinton     Address addr;
5609678Slinton 
5619678Slinton     addr = codeloc(f);
5629678Slinton     while (linelookup(addr) == 0 and addr < objsize) {
5639678Slinton 	++addr;
5649678Slinton     }
5659678Slinton     if (addr == objsize) {
5669678Slinton 	addr = -1;
5679678Slinton     }
5689678Slinton     return addr;
5699678Slinton }
5709678Slinton 
5719678Slinton /*
5729678Slinton  * Catcher drops strike three ...
5739678Slinton  */
5749678Slinton 
5759678Slinton public runtofirst()
5769678Slinton {
5779678Slinton     Address addr;
5789678Slinton 
5799678Slinton     addr = pc;
5809678Slinton     while (linelookup(addr) == 0 and addr < objsize) {
5819678Slinton 	++addr;
5829678Slinton     }
5839678Slinton     if (addr < objsize) {
5849678Slinton 	stepto(addr);
5859678Slinton     }
5869678Slinton }
5879678Slinton 
5889678Slinton /*
5899678Slinton  * Return the address corresponding to the end of the program.
5909678Slinton  *
5919678Slinton  * We look for the entry to "exit".
5929678Slinton  */
5939678Slinton 
5949678Slinton public Address lastaddr()
5959678Slinton {
5969678Slinton     register Symbol s;
5979678Slinton 
5989678Slinton     s = lookup(identname("exit", true));
5999678Slinton     if (s == nil) {
6009678Slinton 	panic("can't find exit");
6019678Slinton     }
6029678Slinton     return codeloc(s);
6039678Slinton }
6049678Slinton 
6059678Slinton /*
6069678Slinton  * Decide if the given function is currently active.
6079678Slinton  *
6089678Slinton  * We avoid calls to "findframe" during a stack trace for efficiency.
6099678Slinton  * Presumably information evaluated while walking the stack is active.
6109678Slinton  */
6119678Slinton 
6129678Slinton public Boolean isactive(f)
6139678Slinton Symbol f;
6149678Slinton {
6159678Slinton     register Boolean b;
6169678Slinton 
6179678Slinton     if (isfinished(process)) {
6189678Slinton 	b = false;
6199678Slinton     } else {
6209678Slinton 	if (walkingstack or f == program or
6219678Slinton 	  (ismodule(f) and isactive(container(f)))) {
6229678Slinton 	    b = true;
6239678Slinton 	} else {
6249678Slinton 	    b = (Boolean) (findframe(f) != nil);
6259678Slinton 	}
6269678Slinton     }
6279678Slinton     return b;
6289678Slinton }
6299678Slinton 
6309678Slinton /*
6319678Slinton  * Evaluate a call to a procedure.
6329678Slinton  */
6339678Slinton 
6349678Slinton public callproc(procnode, arglist)
6359678Slinton Node procnode;
6369678Slinton Node arglist;
6379678Slinton {
6389678Slinton     Symbol proc;
6399678Slinton     Integer argc;
6409678Slinton 
6419678Slinton     if (procnode->op != O_SYM) {
6429678Slinton 	beginerrmsg();
6439678Slinton 	fprintf(stderr, "can't call \"");
6449678Slinton 	prtree(stderr, procnode);
6459678Slinton 	fprintf(stderr, "\"");
6469678Slinton 	enderrmsg();
6479678Slinton     }
6489678Slinton     assert(procnode->op == O_SYM);
6499678Slinton     proc = procnode->value.sym;
6509678Slinton     if (not isblock(proc)) {
6519678Slinton 	error("\"%s\" is not a procedure or function", symname(proc));
6529678Slinton     }
6539678Slinton     pushenv();
6549678Slinton     pc = codeloc(proc);
6559678Slinton     argc = pushargs(proc, arglist);
6569678Slinton     beginproc(proc, argc);
6579678Slinton     isstopped = true;
6589678Slinton     event_once(build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)),
6599678Slinton 	buildcmdlist(build(O_PROCRTN, proc)));
660*16618Ssam     cont(0);
6619678Slinton     /* NOTREACHED */
6629678Slinton }
6639678Slinton 
6649678Slinton /*
6659678Slinton  * Push the arguments on the process' stack.  We do this by first
6669678Slinton  * evaluating them on the "eval" stack, then copying into the process'
6679678Slinton  * space.
6689678Slinton  */
6699678Slinton 
6709678Slinton private Integer pushargs(proc, arglist)
6719678Slinton Symbol proc;
6729678Slinton Node arglist;
6739678Slinton {
6749678Slinton     Stack *savesp;
6759678Slinton     int argc, args_size;
6769678Slinton 
6779678Slinton     savesp = sp;
6789678Slinton     argc = evalargs(proc, arglist);
6799678Slinton     args_size = sp - savesp;
6809678Slinton     setreg(STKP, reg(STKP) - args_size);
6819678Slinton     dwrite(savesp, reg(STKP), args_size);
6829678Slinton     sp = savesp;
6839678Slinton     return argc;
6849678Slinton }
6859678Slinton 
6869678Slinton /*
687*16618Ssam  * Check to see if an expression is correct for a given parameter.
688*16618Ssam  * If the given parameter is false, don't worry about type inconsistencies.
689*16618Ssam  *
690*16618Ssam  * Return whether or not it is ok.
6919678Slinton  */
6929678Slinton 
693*16618Ssam private boolean chkparam (actual, formal, chk)
694*16618Ssam Node actual;
695*16618Ssam Symbol formal;
696*16618Ssam boolean chk;
697*16618Ssam {
698*16618Ssam     boolean b;
699*16618Ssam 
700*16618Ssam     b = true;
701*16618Ssam     if (chk) {
702*16618Ssam 	if (formal == nil) {
703*16618Ssam 	    beginerrmsg();
704*16618Ssam 	    fprintf(stderr, "too many parameters");
705*16618Ssam 	    b = false;
706*16618Ssam 	} else if (not compatible(formal->type, actual->nodetype)) {
707*16618Ssam 	    beginerrmsg();
708*16618Ssam 	    fprintf(stderr, "type mismatch for %s", symname(formal));
709*16618Ssam 	    b = false;
710*16618Ssam 	}
711*16618Ssam     }
712*16618Ssam     if (b and formal != nil and isvarparam(formal) and
713*16618Ssam 	not isopenarray(formal->type) and actual->op != O_RVAL)
714*16618Ssam     {
715*16618Ssam 	beginerrmsg();
716*16618Ssam 	fprintf(stderr, "expected variable, found \"");
717*16618Ssam 	prtree(stderr, actual);
718*16618Ssam 	fprintf(stderr, "\"");
719*16618Ssam 	b = false;
720*16618Ssam     }
721*16618Ssam     return b;
722*16618Ssam }
723*16618Ssam 
724*16618Ssam /*
725*16618Ssam  * Pass an expression to a particular parameter.
726*16618Ssam  *
727*16618Ssam  * Normally we pass either the address or value, but in some cases
728*16618Ssam  * (such as C strings) we want to copy the value onto the stack and
729*16618Ssam  * pass its address.
730*16618Ssam  */
731*16618Ssam 
732*16618Ssam private passparam (actual, formal)
733*16618Ssam Node actual;
734*16618Ssam Symbol formal;
735*16618Ssam {
736*16618Ssam     boolean b;
737*16618Ssam     Address addr;
738*16618Ssam     Stack *savesp;
739*16618Ssam     integer paramsize;
740*16618Ssam 
741*16618Ssam     if (isvarparam(formal) and not isopenarray(formal->type)) {
742*16618Ssam 	addr = lval(actual->value.arg[0]);
743*16618Ssam 	push(Address, addr);
744*16618Ssam     } else if (passaddr(formal, actual->nodetype)) {
745*16618Ssam 	savesp = sp;
746*16618Ssam 	eval(actual);
747*16618Ssam 	paramsize = sp - savesp;
748*16618Ssam 	setreg(STKP, reg(STKP) - paramsize);
749*16618Ssam 	dwrite(savesp, reg(STKP), paramsize);
750*16618Ssam 	sp = savesp;
751*16618Ssam 	push(Address, reg(STKP));
752*16618Ssam 	if (formal != nil and isopenarray(formal->type)) {
753*16618Ssam 	    push(integer, paramsize div size(formal->type->type));
754*16618Ssam 	}
755*16618Ssam     } else {
756*16618Ssam 	eval(actual);
757*16618Ssam     }
758*16618Ssam }
759*16618Ssam 
760*16618Ssam /*
761*16618Ssam  * Evaluate an argument list left-to-right.
762*16618Ssam  */
763*16618Ssam 
7649678Slinton private Integer evalargs(proc, arglist)
7659678Slinton Symbol proc;
7669678Slinton Node arglist;
7679678Slinton {
768*16618Ssam     Node p, actual;
769*16618Ssam     Symbol formal;
7709678Slinton     Stack *savesp;
7719678Slinton     Integer count;
772*16618Ssam     boolean chk;
7739678Slinton 
7749678Slinton     savesp = sp;
7759678Slinton     count = 0;
776*16618Ssam     formal = proc->chain;
777*16618Ssam     chk = (boolean) (not nosource(proc));
7789678Slinton     for (p = arglist; p != nil; p = p->value.arg[1]) {
779*16618Ssam 	assert(p->op == O_COMMA);
780*16618Ssam 	actual = p->value.arg[0];
781*16618Ssam 	if (not chkparam(actual, formal, chk)) {
782*16618Ssam 	    fprintf(stderr, " in call to %s", symname(proc));
7839678Slinton 	    sp = savesp;
784*16618Ssam 	    enderrmsg();
7859678Slinton 	}
786*16618Ssam 	passparam(actual, formal);
787*16618Ssam 	if (formal != nil) {
788*16618Ssam 	    formal = formal->chain;
7899678Slinton 	}
7909678Slinton 	++count;
7919678Slinton     }
792*16618Ssam     if (chk) {
793*16618Ssam 	if (formal != nil) {
794*16618Ssam 	    sp = savesp;
795*16618Ssam 	    error("not enough parameters to %s", symname(proc));
796*16618Ssam 	}
7979678Slinton     }
7989678Slinton     return count;
7999678Slinton }
8009678Slinton 
8019678Slinton public procreturn(f)
8029678Slinton Symbol f;
8039678Slinton {
8049678Slinton     flushoutput();
8059678Slinton     putchar('\n');
8069678Slinton     printname(stdout, f);
8079678Slinton     printf(" returns successfully\n", symname(f));
8089678Slinton     popenv();
8099678Slinton     erecover();
8109678Slinton }
8119678Slinton 
8129678Slinton /*
8139678Slinton  * Push the current environment.
8149678Slinton  */
8159678Slinton 
8169678Slinton private pushenv()
8179678Slinton {
8189678Slinton     push(Address, pc);
8199678Slinton     push(Lineno, curline);
8209678Slinton     push(String, cursource);
8219678Slinton     push(Boolean, isstopped);
8229678Slinton     push(Symbol, curfunc);
823*16618Ssam     push(Frame, curframe);
824*16618Ssam     push(struct Frame, curframerec);
8259678Slinton     push(Word, reg(PROGCTR));
8269678Slinton     push(Word, reg(STKP));
8279678Slinton }
8289678Slinton 
8299678Slinton /*
8309678Slinton  * Pop back to the real world.
8319678Slinton  */
8329678Slinton 
8339678Slinton public popenv()
8349678Slinton {
8359678Slinton     register String filename;
8369678Slinton 
8379678Slinton     setreg(STKP, pop(Word));
8389678Slinton     setreg(PROGCTR, pop(Word));
839*16618Ssam     curframerec = pop(struct Frame);
840*16618Ssam     curframe = pop(Frame);
8419678Slinton     curfunc = pop(Symbol);
8429678Slinton     isstopped = pop(Boolean);
8439678Slinton     filename = pop(String);
8449678Slinton     curline = pop(Lineno);
8459678Slinton     pc = pop(Address);
8469678Slinton     setsource(filename);
8479678Slinton }
8489678Slinton 
8499678Slinton /*
8509678Slinton  * Flush the debuggee's standard output.
8519678Slinton  *
8529678Slinton  * This is VERY dependent on the use of stdio.
8539678Slinton  */
8549678Slinton 
8559678Slinton public flushoutput()
8569678Slinton {
8579678Slinton     register Symbol p, iob;
8589678Slinton     register Stack *savesp;
8599678Slinton 
8609678Slinton     p = lookup(identname("fflush", true));
8619678Slinton     while (p != nil and not isblock(p)) {
8629678Slinton 	p = p->next_sym;
8639678Slinton     }
8649678Slinton     if (p != nil) {
8659678Slinton 	iob = lookup(identname("_iob", true));
8669678Slinton 	if (iob != nil) {
8679678Slinton 	    pushenv();
8689678Slinton 	    pc = codeloc(p);
8699678Slinton 	    savesp = sp;
8709678Slinton 	    push(long, address(iob, nil) + sizeof(struct _iobuf));
8719678Slinton 	    setreg(STKP, reg(STKP) - sizeof(long));
8729678Slinton 	    dwrite(savesp, reg(STKP), sizeof(long));
8739678Slinton 	    sp = savesp;
8749678Slinton 	    beginproc(p, 1);
8759678Slinton 	    stepto(return_addr());
8769678Slinton 	    popenv();
8779678Slinton 	}
8789678Slinton     }
8799678Slinton }
880