xref: /csrg-svn/old/dbx/runtime.c (revision 18231)
19678Slinton /* Copyright (c) 1982 Regents of the University of California */
29678Slinton 
3*18231Slinton static	char sccsid[] = "@(#)runtime.c	1.13 (Berkeley) 03/01/85";
49678Slinton 
5*18231Slinton static char rcsid[] = "$Header: runtime.c,v 1.5 84/12/26 10:41:52 linton Exp $";
6*18231Slinton 
79678Slinton /*
89678Slinton  * Runtime organization dependent routines, mostly dealing with
99678Slinton  * activation records.
109678Slinton  */
119678Slinton 
129678Slinton #include "defs.h"
139678Slinton #include "runtime.h"
149678Slinton #include "process.h"
159678Slinton #include "machine.h"
169678Slinton #include "events.h"
179678Slinton #include "mappings.h"
189678Slinton #include "symbols.h"
199678Slinton #include "tree.h"
209678Slinton #include "eval.h"
219678Slinton #include "operators.h"
229678Slinton #include "object.h"
2312546Scsvaf #include <sys/param.h>
249678Slinton 
259678Slinton #ifndef public
269678Slinton typedef struct Frame *Frame;
279678Slinton 
289678Slinton #include "machine.h"
299678Slinton #endif
309678Slinton 
319678Slinton #define NSAVEREG 12
329678Slinton 
339678Slinton struct Frame {
34*18231Slinton     integer condition_handler;
35*18231Slinton     integer mask;
369678Slinton     Address save_ap;		/* argument pointer */
379678Slinton     Address save_fp;		/* frame pointer */
389678Slinton     Address save_pc;		/* program counter */
399678Slinton     Word save_reg[NSAVEREG];	/* not necessarily there */
409678Slinton };
419678Slinton 
4216618Ssam private Frame curframe = nil;
4316618Ssam private struct Frame curframerec;
449678Slinton private Boolean walkingstack = false;
459678Slinton 
4616618Ssam #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp)
4716618Ssam 
48*18231Slinton #define isstackaddr(addr) \
49*18231Slinton     (((addr) < 0x80000000) and ((addr) > 0x80000000 - 0x200 * UPAGES))
50*18231Slinton 
51*18231Slinton typedef struct {
52*18231Slinton     Node callnode;
53*18231Slinton     Node cmdnode;
54*18231Slinton     boolean isfunc;
55*18231Slinton } CallEnv;
56*18231Slinton 
57*18231Slinton private CallEnv endproc;
58*18231Slinton 
599678Slinton /*
609678Slinton  * Set a frame to the current activation record.
619678Slinton  */
629678Slinton 
639678Slinton private getcurframe(frp)
64*18231Slinton Frame frp;
659678Slinton {
669678Slinton     register int i;
679678Slinton 
689678Slinton     checkref(frp);
699678Slinton     frp->mask = reg(NREG);
709678Slinton     frp->save_ap = reg(ARGP);
719678Slinton     frp->save_fp = reg(FRP);
72*18231Slinton     frp->save_pc = reg(PROGCTR);
739678Slinton     for (i = 0; i < NSAVEREG; i++) {
749678Slinton 	frp->save_reg[i] = reg(i);
759678Slinton     }
769678Slinton }
779678Slinton 
789678Slinton /*
79*18231Slinton  * Get the saved registers from one frame to another
80*18231Slinton  * given mask specifying which registers were actually saved.
81*18231Slinton  */
82*18231Slinton 
83*18231Slinton #define bis(b, n) ((b & (1 << (n))) != 0)
84*18231Slinton 
85*18231Slinton private getsaveregs (newfrp, frp, mask)
86*18231Slinton Frame newfrp, frp;
87*18231Slinton integer mask;
88*18231Slinton {
89*18231Slinton     integer i, j;
90*18231Slinton 
91*18231Slinton     j = 0;
92*18231Slinton     for (i = 0; i < NSAVEREG; i++) {
93*18231Slinton 	if (bis(mask, i)) {
94*18231Slinton 	    newfrp->save_reg[i] = frp->save_reg[j];
95*18231Slinton 	    ++j;
96*18231Slinton 	}
97*18231Slinton     }
98*18231Slinton }
99*18231Slinton 
100*18231Slinton /*
1019678Slinton  * Return a pointer to the next activation record up the stack.
1029678Slinton  * Return nil if there is none.
1039678Slinton  * Writes over space pointed to by given argument.
1049678Slinton  */
1059678Slinton 
1069678Slinton private Frame nextframe(frp)
1079678Slinton Frame frp;
1089678Slinton {
109*18231Slinton     Frame newfrp;
1109678Slinton     struct Frame frame;
111*18231Slinton     integer mask;
11212546Scsvaf     Address prev_frame, callpc;
113*18231Slinton     static integer ntramp = 0;
1149678Slinton 
1159678Slinton     newfrp = frp;
11612546Scsvaf     prev_frame = frp->save_fp;
11712546Scsvaf 
11813937Slinton /*
11913937Slinton  *  The check for interrupt generated frames is taken from adb with only
12013937Slinton  *  partial understanding.  If you're in "sub" and on a sigxxx "sigsub"
12113937Slinton  *  gets control, then the stack does NOT look like <main, sub, sigsub>.
12212546Scsvaf  *
12312546Scsvaf  *  As best I can make out it looks like:
12412546Scsvaf  *
12513937Slinton  *     <main, (machine check exception block + sub), sysframe, sigsub>.
12613937Slinton  *
12713937Slinton  *  When the signal occurs an exception block and a frame for the routine
12813937Slinton  *  in which it occured are pushed on the user stack.  Then another frame
12913937Slinton  *  is pushed corresponding to a call from the kernel to sigsub.
13013937Slinton  *
13112546Scsvaf  *  The addr in sub at which the exception occured is not in sub.save_pc
13213937Slinton  *  but in the machine check exception block.  It is at the magic address
13314620Ssam  *  fp + 84.
13412546Scsvaf  *
13512546Scsvaf  *  The current approach ignores the sys_frame (what adb reports as sigtramp)
13613937Slinton  *  and takes the pc for sub from the exception block.  This allows the
13713937Slinton  *  "where" command to report <main, sub, sigsub>, which seems reasonable.
13812546Scsvaf  */
13912546Scsvaf 
14013937Slinton nextf:
14113937Slinton     dread(&frame, prev_frame, sizeof(struct Frame));
14213937Slinton     if (ntramp == 1) {
14314620Ssam 	dread(&callpc, prev_frame + 84, sizeof(callpc));
14413937Slinton     } else {
14513937Slinton 	callpc = frame.save_pc;
14613937Slinton     }
147*18231Slinton     if (frame.save_fp == nil or frame.save_pc == (Address) -1) {
1489678Slinton 	newfrp = nil;
149*18231Slinton     } else if (isstackaddr(callpc)) {
150*18231Slinton 	ntramp++;
151*18231Slinton 	prev_frame = frame.save_fp;
152*18231Slinton 	goto nextf;
15313937Slinton     } else {
15412546Scsvaf 	frame.save_pc = callpc;
15513937Slinton         ntramp = 0;
1569678Slinton 	mask = ((frame.mask >> 16) & 0x0fff);
157*18231Slinton 	getsaveregs(newfrp, &frame, mask);
1589678Slinton 	newfrp->condition_handler = frame.condition_handler;
1599678Slinton 	newfrp->mask = mask;
1609678Slinton 	newfrp->save_ap = frame.save_ap;
1619678Slinton 	newfrp->save_fp = frame.save_fp;
1629678Slinton 	newfrp->save_pc = frame.save_pc;
1639678Slinton     }
1649678Slinton     return newfrp;
1659678Slinton }
1669678Slinton 
1679678Slinton /*
16816618Ssam  * Get the current frame information in the given Frame and store the
16916618Ssam  * associated function in the given value-result parameter.
17016618Ssam  */
17116618Ssam 
17216618Ssam private getcurfunc (frp, fp)
17316618Ssam Frame frp;
17416618Ssam Symbol *fp;
17516618Ssam {
17616618Ssam     getcurframe(frp);
17716618Ssam     *fp = whatblock(frp->save_pc);
17816618Ssam }
17916618Ssam 
18016618Ssam /*
18116618Ssam  * Return the frame associated with the next function up the call stack, or
18216618Ssam  * nil if there is none.  The function is returned in a value-result parameter.
18316618Ssam  * For "inline" functions the statically outer function and same frame
18416618Ssam  * are returned.
18516618Ssam  */
18616618Ssam 
187*18231Slinton public Frame nextfunc (frp, fp)
18816618Ssam Frame frp;
18916618Ssam Symbol *fp;
19016618Ssam {
19116618Ssam     Symbol t;
19216618Ssam     Frame nfrp;
19316618Ssam 
19416618Ssam     t = *fp;
19516618Ssam     checkref(t);
19616618Ssam     if (isinline(t)) {
19716618Ssam 	t = container(t);
19816618Ssam 	nfrp = frp;
19916618Ssam     } else {
20016618Ssam 	nfrp = nextframe(frp);
20116618Ssam 	if (nfrp == nil) {
20216618Ssam 	    t = nil;
20316618Ssam 	} else {
20416618Ssam 	    t = whatblock(nfrp->save_pc);
20516618Ssam 	}
20616618Ssam     }
20716618Ssam     *fp = t;
20816618Ssam     return nfrp;
20916618Ssam }
21016618Ssam 
21116618Ssam /*
2129678Slinton  * Return the frame associated with the given function.
2139678Slinton  * If the function is nil, return the most recently activated frame.
2149678Slinton  *
2159678Slinton  * Static allocation for the frame.
2169678Slinton  */
2179678Slinton 
2189678Slinton public Frame findframe(f)
2199678Slinton Symbol f;
2209678Slinton {
221*18231Slinton     Frame frp;
2229678Slinton     static struct Frame frame;
22311866Slinton     Symbol p;
224*18231Slinton     Boolean done;
2259678Slinton 
2269678Slinton     frp = &frame;
2279678Slinton     getcurframe(frp);
228*18231Slinton     if (f != nil) {
229*18231Slinton 	if (f == curfunc and curframe != nil) {
230*18231Slinton 	    *frp = *curframe;
231*18231Slinton 	} else {
232*18231Slinton 	    done = false;
233*18231Slinton 	    p = whatblock(frp->save_pc);
234*18231Slinton 	    do {
235*18231Slinton 		if (p == f) {
236*18231Slinton 		    done = true;
237*18231Slinton 		} else if (p == program) {
238*18231Slinton 		    done = true;
239*18231Slinton 		    frp = nil;
240*18231Slinton 		} else {
241*18231Slinton 		    frp = nextfunc(frp, &p);
242*18231Slinton 		    if (frp == nil) {
243*18231Slinton 			done = true;
244*18231Slinton 		    }
245*18231Slinton 		}
246*18231Slinton 	    } while (not done);
24715784Ssam 	}
248*18231Slinton     }
249*18231Slinton     return frp;
250*18231Slinton }
251*18231Slinton 
252*18231Slinton /*
253*18231Slinton  * Set the registers according to the given frame pointer.
254*18231Slinton  */
255*18231Slinton 
256*18231Slinton public getnewregs (addr)
257*18231Slinton Address addr;
258*18231Slinton {
259*18231Slinton     struct Frame frame;
260*18231Slinton     integer i, j, mask;
261*18231Slinton 
262*18231Slinton     dread(&frame, addr, sizeof(frame));
263*18231Slinton     setreg(ARGP, frame.save_ap);
264*18231Slinton     setreg(FRP, frame.save_fp);
265*18231Slinton     setreg(PROGCTR, frame.save_pc);
266*18231Slinton     mask = ((frame.mask >> 16) & 0x0fff);
267*18231Slinton     j = 0;
268*18231Slinton     for (i = 0; i < NSAVEREG; i++) {
269*18231Slinton 	if (bis(mask, i)) {
270*18231Slinton 	    setreg(i, frame.save_reg[j]);
271*18231Slinton 	    ++j;
27216636Ssam 	}
2739678Slinton     }
274*18231Slinton     pc = frame.save_pc;
275*18231Slinton     setcurfunc(whatblock(pc));
2769678Slinton }
2779678Slinton 
2789678Slinton /*
2799678Slinton  * Find the return address of the current procedure/function.
2809678Slinton  */
2819678Slinton 
2829678Slinton public Address return_addr()
2839678Slinton {
2849678Slinton     Frame frp;
2859678Slinton     Address addr;
2869678Slinton     struct Frame frame;
2879678Slinton 
2889678Slinton     frp = &frame;
2899678Slinton     getcurframe(frp);
2909678Slinton     frp = nextframe(frp);
2919678Slinton     if (frp == nil) {
2929678Slinton 	addr = 0;
2939678Slinton     } else {
2949678Slinton 	addr = frp->save_pc;
2959678Slinton     }
2969678Slinton     return addr;
2979678Slinton }
2989678Slinton 
2999678Slinton /*
3009678Slinton  * Push the value associated with the current function.
3019678Slinton  */
3029678Slinton 
3039678Slinton public pushretval(len, isindirect)
304*18231Slinton integer len;
305*18231Slinton boolean isindirect;
3069678Slinton {
3079678Slinton     Word r0;
3089678Slinton 
3099678Slinton     r0 = reg(0);
3109678Slinton     if (isindirect) {
3119678Slinton 	rpush((Address) r0, len);
3129678Slinton     } else {
3139678Slinton 	switch (len) {
3149678Slinton 	    case sizeof(char):
3159678Slinton 		push(char, r0);
3169678Slinton 		break;
3179678Slinton 
3189678Slinton 	    case sizeof(short):
3199678Slinton 		push(short, r0);
3209678Slinton 		break;
3219678Slinton 
3229678Slinton 	    default:
3239678Slinton 		if (len == sizeof(Word)) {
3249678Slinton 		    push(Word, r0);
3259678Slinton 		} else if (len == 2*sizeof(Word)) {
3269678Slinton 		    push(Word, r0);
3279678Slinton 		    push(Word, reg(1));
3289678Slinton 		} else {
329*18231Slinton 		    error("[internal error: bad size %d in pushretval]", len);
3309678Slinton 		}
3319678Slinton 		break;
3329678Slinton 	}
3339678Slinton     }
3349678Slinton }
3359678Slinton 
3369678Slinton /*
3379678Slinton  * Return the base address for locals in the given frame.
3389678Slinton  */
3399678Slinton 
3409678Slinton public Address locals_base(frp)
341*18231Slinton Frame frp;
3429678Slinton {
3439678Slinton     return (frp == nil) ? reg(FRP) : frp->save_fp;
3449678Slinton }
3459678Slinton 
3469678Slinton /*
3479678Slinton  * Return the base address for arguments in the given frame.
3489678Slinton  */
3499678Slinton 
3509678Slinton public Address args_base(frp)
351*18231Slinton Frame frp;
3529678Slinton {
3539678Slinton     return (frp == nil) ? reg(ARGP) : frp->save_ap;
3549678Slinton }
3559678Slinton 
3569678Slinton /*
3579678Slinton  * Return saved register n from the given frame.
3589678Slinton  */
3599678Slinton 
3609678Slinton public Word savereg(n, frp)
361*18231Slinton integer n;
362*18231Slinton Frame frp;
3639678Slinton {
364*18231Slinton     Word w;
3659678Slinton 
3669678Slinton     if (frp == nil) {
3679678Slinton 	w = reg(n);
3689678Slinton     } else {
3699678Slinton 	switch (n) {
3709678Slinton 	    case ARGP:
3719678Slinton 		w = frp->save_ap;
3729678Slinton 		break;
3739678Slinton 
3749678Slinton 	    case FRP:
3759678Slinton 		w = frp->save_fp;
3769678Slinton 		break;
3779678Slinton 
3789678Slinton 	    case STKP:
3799678Slinton 		w = reg(STKP);
3809678Slinton 		break;
3819678Slinton 
3829678Slinton 	    case PROGCTR:
3839678Slinton 		w = frp->save_pc;
3849678Slinton 		break;
3859678Slinton 
3869678Slinton 	    default:
3879678Slinton 		assert(n >= 0 and n < NSAVEREG);
3889678Slinton 		w = frp->save_reg[n];
3899678Slinton 		break;
3909678Slinton 	}
3919678Slinton     }
3929678Slinton     return w;
3939678Slinton }
3949678Slinton 
3959678Slinton /*
3969678Slinton  * Return the nth argument to the current procedure.
3979678Slinton  */
3989678Slinton 
3999678Slinton public Word argn(n, frp)
400*18231Slinton integer n;
4019678Slinton Frame frp;
4029678Slinton {
4039678Slinton     Word w;
4049678Slinton 
4059678Slinton     dread(&w, args_base(frp) + (n * sizeof(Word)), sizeof(w));
4069678Slinton     return w;
4079678Slinton }
4089678Slinton 
4099678Slinton /*
410*18231Slinton  * Print a list of currently active blocks starting with most recent.
4119678Slinton  */
4129678Slinton 
413*18231Slinton public wherecmd()
4149678Slinton {
415*18231Slinton     walkstack(false);
4169678Slinton }
4179678Slinton 
4189678Slinton /*
419*18231Slinton  * Print the variables in the given frame or the current one if nil.
4209678Slinton  */
4219678Slinton 
422*18231Slinton public dump (func)
423*18231Slinton Symbol func;
4249678Slinton {
425*18231Slinton     Symbol f;
426*18231Slinton     Frame frp;
427*18231Slinton 
428*18231Slinton     if (func == nil) {
429*18231Slinton 	f = curfunc;
430*18231Slinton 	if (curframe != nil) {
431*18231Slinton 	    frp = curframe;
432*18231Slinton 	} else {
433*18231Slinton 	    frp = findframe(f);
434*18231Slinton 	}
435*18231Slinton     } else {
436*18231Slinton 	f = func;
437*18231Slinton 	frp = findframe(f);
438*18231Slinton     }
439*18231Slinton     showaggrs = true;
440*18231Slinton     printcallinfo(f, frp);
441*18231Slinton     dumpvars(f, frp);
4429678Slinton }
4439678Slinton 
4449678Slinton /*
445*18231Slinton  * Dump all values.
4469678Slinton  */
4479678Slinton 
448*18231Slinton public dumpall ()
4499678Slinton {
4509678Slinton     walkstack(true);
4519678Slinton }
4529678Slinton 
4539678Slinton /*
4549678Slinton  * Walk the stack of active procedures printing information
4559678Slinton  * about each active procedure.
4569678Slinton  */
4579678Slinton 
4589678Slinton private walkstack(dumpvariables)
4599678Slinton Boolean dumpvariables;
4609678Slinton {
461*18231Slinton     Frame frp;
462*18231Slinton     boolean save;
46316618Ssam     Symbol f;
4649678Slinton     struct Frame frame;
4659678Slinton 
466*18231Slinton     if (notstarted(process) or isfinished(process)) {
4679678Slinton 	error("program is not active");
4689678Slinton     } else {
4699678Slinton 	save = walkingstack;
4709678Slinton 	walkingstack = true;
471*18231Slinton 	showaggrs = dumpvariables;
4729678Slinton 	frp = &frame;
47316618Ssam 	getcurfunc(frp, &f);
474*18231Slinton 	for (;;) {
475*18231Slinton 	    printcallinfo(f, frp);
4769678Slinton 	    if (dumpvariables) {
4779678Slinton 		dumpvars(f, frp);
4789678Slinton 		putchar('\n');
4799678Slinton 	    }
48016618Ssam 	    frp = nextfunc(frp, &f);
481*18231Slinton 	    if (frp == nil or f == program) {
482*18231Slinton 		break;
483*18231Slinton 	    }
484*18231Slinton 	}
4859678Slinton 	if (dumpvariables) {
4869678Slinton 	    printf("in \"%s\":\n", symname(program));
4879678Slinton 	    dumpvars(program, nil);
4889678Slinton 	    putchar('\n');
4899678Slinton 	}
4909678Slinton 	walkingstack = save;
4919678Slinton     }
4929678Slinton }
4939678Slinton 
4949678Slinton /*
495*18231Slinton  * Print out the information about a call, i.e.,
496*18231Slinton  * routine name, parameter values, and source location.
497*18231Slinton  */
498*18231Slinton 
499*18231Slinton private printcallinfo (f, frp)
500*18231Slinton Symbol f;
501*18231Slinton Frame frp;
502*18231Slinton {
503*18231Slinton     Lineno line;
504*18231Slinton     Address savepc;
505*18231Slinton 
506*18231Slinton     savepc = frp->save_pc;
507*18231Slinton     if (frp->save_fp != reg(FRP)) {
508*18231Slinton 	savepc -= 1;
509*18231Slinton     }
510*18231Slinton     printname(stdout, f);
511*18231Slinton     if (not isinline(f)) {
512*18231Slinton 	printparams(f, frp);
513*18231Slinton     }
514*18231Slinton     line = srcline(savepc);
515*18231Slinton     if (line != 0) {
516*18231Slinton 	printf(", line %d", line);
517*18231Slinton 	printf(" in \"%s\"\n", srcfilename(savepc));
518*18231Slinton     } else {
519*18231Slinton 	printf(" at 0x%x\n", savepc);
520*18231Slinton     }
521*18231Slinton }
522*18231Slinton 
523*18231Slinton /*
52416618Ssam  * Set the current function to the given symbol.
52516618Ssam  * We must adjust "curframe" so that subsequent operations are
52616618Ssam  * not confused; for simplicity we simply clear it.
52716618Ssam  */
52816618Ssam 
52916618Ssam public setcurfunc (f)
53016618Ssam Symbol f;
53116618Ssam {
53216618Ssam     curfunc = f;
53316618Ssam     curframe = nil;
53416618Ssam }
53516618Ssam 
53616618Ssam /*
537*18231Slinton  * Return the frame for the current function.
538*18231Slinton  * The space for the frame is allocated statically.
539*18231Slinton  */
540*18231Slinton 
541*18231Slinton public Frame curfuncframe ()
542*18231Slinton {
543*18231Slinton     static struct Frame frame;
544*18231Slinton     Frame frp;
545*18231Slinton 
546*18231Slinton     if (curframe == nil) {
547*18231Slinton 	frp = findframe(curfunc);
548*18231Slinton 	curframe = &curframerec;
549*18231Slinton 	*curframe = *frp;
550*18231Slinton     } else {
551*18231Slinton 	frp = &frame;
552*18231Slinton 	*frp = *curframe;
553*18231Slinton     }
554*18231Slinton     return frp;
555*18231Slinton }
556*18231Slinton 
557*18231Slinton /*
55816618Ssam  * Set curfunc to be N up/down the stack from its current value.
55916618Ssam  */
56016618Ssam 
56116618Ssam public up (n)
56216618Ssam integer n;
56316618Ssam {
56416618Ssam     integer i;
56516618Ssam     Symbol f;
56616618Ssam     Frame frp;
56716618Ssam     boolean done;
56816618Ssam 
56916618Ssam     if (not isactive(program)) {
57016618Ssam 	error("program is not active");
57116618Ssam     } else if (curfunc == nil) {
57216618Ssam 	error("no current function");
57316618Ssam     } else {
57416618Ssam 	i = 0;
57516618Ssam 	f = curfunc;
576*18231Slinton 	frp = curfuncframe();
57716618Ssam 	done = false;
57816618Ssam 	do {
57916618Ssam 	    if (frp == nil) {
58016618Ssam 		done = true;
58116618Ssam 		error("not that many levels");
58216618Ssam 	    } else if (i >= n) {
58316618Ssam 		done = true;
58416618Ssam 		curfunc = f;
58516618Ssam 		curframe = &curframerec;
58616618Ssam 		*curframe = *frp;
587*18231Slinton 		showaggrs = false;
588*18231Slinton 		printcallinfo(curfunc, curframe);
58916618Ssam 	    } else if (f == program) {
59016618Ssam 		done = true;
59116618Ssam 		error("not that many levels");
59216618Ssam 	    } else {
59316618Ssam 		frp = nextfunc(frp, &f);
59416618Ssam 	    }
59516618Ssam 	    ++i;
59616618Ssam 	} while (not done);
59716618Ssam     }
59816618Ssam }
59916618Ssam 
60016618Ssam public down (n)
60116618Ssam integer n;
60216618Ssam {
60316618Ssam     integer i, depth;
604*18231Slinton     Frame frp, curfrp;
60516618Ssam     Symbol f;
60616618Ssam     struct Frame frame;
60716618Ssam 
60816618Ssam     if (not isactive(program)) {
60916618Ssam 	error("program is not active");
61016618Ssam     } else if (curfunc == nil) {
61116618Ssam 	error("no current function");
61216618Ssam     } else {
61316618Ssam 	depth = 0;
61416618Ssam 	frp = &frame;
61516618Ssam 	getcurfunc(frp, &f);
61616618Ssam 	if (curframe == nil) {
617*18231Slinton 	    curfrp = findframe(curfunc);
61816618Ssam 	    curframe = &curframerec;
619*18231Slinton 	    *curframe = *curfrp;
62016618Ssam 	}
62116618Ssam 	while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) {
62216618Ssam 	    frp = nextfunc(frp, &f);
62316618Ssam 	    ++depth;
62416618Ssam 	}
62516618Ssam 	if (f == nil or n > depth) {
62616618Ssam 	    error("not that many levels");
62716618Ssam 	} else {
62816618Ssam 	    depth -= n;
62916618Ssam 	    frp = &frame;
63016618Ssam 	    getcurfunc(frp, &f);
63116618Ssam 	    for (i = 0; i < depth; i++) {
63216618Ssam 		frp = nextfunc(frp, &f);
63316618Ssam 		assert(frp != nil);
63416618Ssam 	    }
63516618Ssam 	    curfunc = f;
63616618Ssam 	    *curframe = *frp;
637*18231Slinton 	    showaggrs = false;
638*18231Slinton 	    printcallinfo(curfunc, curframe);
63916618Ssam 	}
64016618Ssam     }
64116618Ssam }
64216618Ssam 
64316618Ssam /*
6449678Slinton  * Find the entry point of a procedure or function.
6459678Slinton  */
6469678Slinton 
647*18231Slinton public findbeginning (f)
6489678Slinton Symbol f;
6499678Slinton {
65016618Ssam     if (isinternal(f)) {
65116618Ssam 	f->symvalue.funcv.beginaddr += 15;
65216618Ssam     } else {
65316618Ssam 	f->symvalue.funcv.beginaddr += 2;
65416618Ssam     }
6559678Slinton }
6569678Slinton 
6579678Slinton /*
6589678Slinton  * Return the address corresponding to the first line in a function.
6599678Slinton  */
6609678Slinton 
6619678Slinton public Address firstline(f)
6629678Slinton Symbol f;
6639678Slinton {
6649678Slinton     Address addr;
6659678Slinton 
6669678Slinton     addr = codeloc(f);
6679678Slinton     while (linelookup(addr) == 0 and addr < objsize) {
6689678Slinton 	++addr;
6699678Slinton     }
6709678Slinton     if (addr == objsize) {
6719678Slinton 	addr = -1;
6729678Slinton     }
6739678Slinton     return addr;
6749678Slinton }
6759678Slinton 
6769678Slinton /*
6779678Slinton  * Catcher drops strike three ...
6789678Slinton  */
6799678Slinton 
6809678Slinton public runtofirst()
6819678Slinton {
6829678Slinton     Address addr;
6839678Slinton 
6849678Slinton     addr = pc;
6859678Slinton     while (linelookup(addr) == 0 and addr < objsize) {
6869678Slinton 	++addr;
6879678Slinton     }
6889678Slinton     if (addr < objsize) {
6899678Slinton 	stepto(addr);
6909678Slinton     }
6919678Slinton }
6929678Slinton 
6939678Slinton /*
6949678Slinton  * Return the address corresponding to the end of the program.
6959678Slinton  *
6969678Slinton  * We look for the entry to "exit".
6979678Slinton  */
6989678Slinton 
6999678Slinton public Address lastaddr()
7009678Slinton {
701*18231Slinton     Symbol s;
7029678Slinton 
7039678Slinton     s = lookup(identname("exit", true));
7049678Slinton     if (s == nil) {
7059678Slinton 	panic("can't find exit");
7069678Slinton     }
7079678Slinton     return codeloc(s);
7089678Slinton }
7099678Slinton 
7109678Slinton /*
7119678Slinton  * Decide if the given function is currently active.
7129678Slinton  *
7139678Slinton  * We avoid calls to "findframe" during a stack trace for efficiency.
7149678Slinton  * Presumably information evaluated while walking the stack is active.
7159678Slinton  */
7169678Slinton 
7179678Slinton public Boolean isactive(f)
7189678Slinton Symbol f;
7199678Slinton {
720*18231Slinton     Boolean b;
7219678Slinton 
7229678Slinton     if (isfinished(process)) {
7239678Slinton 	b = false;
7249678Slinton     } else {
7259678Slinton 	if (walkingstack or f == program or
7269678Slinton 	  (ismodule(f) and isactive(container(f)))) {
7279678Slinton 	    b = true;
7289678Slinton 	} else {
7299678Slinton 	    b = (Boolean) (findframe(f) != nil);
7309678Slinton 	}
7319678Slinton     }
7329678Slinton     return b;
7339678Slinton }
7349678Slinton 
7359678Slinton /*
7369678Slinton  * Evaluate a call to a procedure.
7379678Slinton  */
7389678Slinton 
739*18231Slinton public callproc(exprnode, isfunc)
740*18231Slinton Node exprnode;
741*18231Slinton boolean isfunc;
7429678Slinton {
743*18231Slinton     Node procnode, arglist;
7449678Slinton     Symbol proc;
745*18231Slinton     integer argc;
7469678Slinton 
747*18231Slinton     procnode = exprnode->value.arg[0];
748*18231Slinton     arglist = exprnode->value.arg[1];
7499678Slinton     if (procnode->op != O_SYM) {
7509678Slinton 	beginerrmsg();
7519678Slinton 	fprintf(stderr, "can't call \"");
7529678Slinton 	prtree(stderr, procnode);
7539678Slinton 	fprintf(stderr, "\"");
7549678Slinton 	enderrmsg();
7559678Slinton     }
7569678Slinton     assert(procnode->op == O_SYM);
7579678Slinton     proc = procnode->value.sym;
7589678Slinton     if (not isblock(proc)) {
7599678Slinton 	error("\"%s\" is not a procedure or function", symname(proc));
7609678Slinton     }
761*18231Slinton     endproc.isfunc = isfunc;
762*18231Slinton     endproc.callnode = exprnode;
763*18231Slinton     endproc.cmdnode = topnode;
7649678Slinton     pushenv();
7659678Slinton     pc = codeloc(proc);
7669678Slinton     argc = pushargs(proc, arglist);
7679678Slinton     beginproc(proc, argc);
768*18231Slinton     event_once(
769*18231Slinton 	build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)),
770*18231Slinton 	buildcmdlist(build(O_PROCRTN, proc))
771*18231Slinton     );
772*18231Slinton     isstopped = false;
773*18231Slinton     if (not bpact()) {
774*18231Slinton 	isstopped = true;
775*18231Slinton 	cont(0);
776*18231Slinton     }
777*18231Slinton     /*
778*18231Slinton      * bpact() won't return true, it will call printstatus() and go back
779*18231Slinton      * to command input if a breakpoint is found.
780*18231Slinton      */
7819678Slinton     /* NOTREACHED */
7829678Slinton }
7839678Slinton 
7849678Slinton /*
7859678Slinton  * Push the arguments on the process' stack.  We do this by first
7869678Slinton  * evaluating them on the "eval" stack, then copying into the process'
7879678Slinton  * space.
7889678Slinton  */
7899678Slinton 
790*18231Slinton private integer pushargs(proc, arglist)
7919678Slinton Symbol proc;
7929678Slinton Node arglist;
7939678Slinton {
7949678Slinton     Stack *savesp;
7959678Slinton     int argc, args_size;
7969678Slinton 
7979678Slinton     savesp = sp;
7989678Slinton     argc = evalargs(proc, arglist);
7999678Slinton     args_size = sp - savesp;
8009678Slinton     setreg(STKP, reg(STKP) - args_size);
8019678Slinton     dwrite(savesp, reg(STKP), args_size);
8029678Slinton     sp = savesp;
8039678Slinton     return argc;
8049678Slinton }
8059678Slinton 
8069678Slinton /*
80716618Ssam  * Check to see if an expression is correct for a given parameter.
80816618Ssam  * If the given parameter is false, don't worry about type inconsistencies.
80916618Ssam  *
81016618Ssam  * Return whether or not it is ok.
8119678Slinton  */
8129678Slinton 
81316618Ssam private boolean chkparam (actual, formal, chk)
81416618Ssam Node actual;
81516618Ssam Symbol formal;
81616618Ssam boolean chk;
81716618Ssam {
81816618Ssam     boolean b;
81916618Ssam 
82016618Ssam     b = true;
82116618Ssam     if (chk) {
82216618Ssam 	if (formal == nil) {
82316618Ssam 	    beginerrmsg();
82416618Ssam 	    fprintf(stderr, "too many parameters");
82516618Ssam 	    b = false;
82616618Ssam 	} else if (not compatible(formal->type, actual->nodetype)) {
82716618Ssam 	    beginerrmsg();
82816618Ssam 	    fprintf(stderr, "type mismatch for %s", symname(formal));
82916618Ssam 	    b = false;
83016618Ssam 	}
83116618Ssam     }
832*18231Slinton     if (b and formal != nil and
833*18231Slinton 	isvarparam(formal) and not isopenarray(formal->type) and
834*18231Slinton 	not (
835*18231Slinton 	    actual->op == O_RVAL or actual->nodetype == t_addr or
836*18231Slinton 	    (
837*18231Slinton 		actual->op == O_TYPERENAME and
838*18231Slinton 		(
839*18231Slinton 		    actual->value.arg[0]->op == O_RVAL or
840*18231Slinton 		    actual->value.arg[0]->nodetype == t_addr
841*18231Slinton 		)
842*18231Slinton 	    )
843*18231Slinton 	)
844*18231Slinton     ) {
84516618Ssam 	beginerrmsg();
84616618Ssam 	fprintf(stderr, "expected variable, found \"");
84716618Ssam 	prtree(stderr, actual);
84816618Ssam 	fprintf(stderr, "\"");
84916618Ssam 	b = false;
85016618Ssam     }
85116618Ssam     return b;
85216618Ssam }
85316618Ssam 
85416618Ssam /*
85516618Ssam  * Pass an expression to a particular parameter.
85616618Ssam  *
85716618Ssam  * Normally we pass either the address or value, but in some cases
85816618Ssam  * (such as C strings) we want to copy the value onto the stack and
85916618Ssam  * pass its address.
860*18231Slinton  *
861*18231Slinton  * Another special case raised by strings is the possibility that
862*18231Slinton  * the actual parameter will be larger than the formal, even with
863*18231Slinton  * appropriate type-checking.  This occurs because we assume during
864*18231Slinton  * evaluation that strings are null-terminated, whereas some languages,
865*18231Slinton  * notably Pascal, do not work under that assumption.
86616618Ssam  */
86716618Ssam 
86816618Ssam private passparam (actual, formal)
86916618Ssam Node actual;
87016618Ssam Symbol formal;
87116618Ssam {
87216618Ssam     boolean b;
87316618Ssam     Address addr;
87416618Ssam     Stack *savesp;
875*18231Slinton     integer actsize, formsize;
87616618Ssam 
877*18231Slinton     if (formal != nil and isvarparam(formal) and
878*18231Slinton 	(not isopenarray(formal->type))
879*18231Slinton     ) {
88016618Ssam 	addr = lval(actual->value.arg[0]);
88116618Ssam 	push(Address, addr);
88216618Ssam     } else if (passaddr(formal, actual->nodetype)) {
88316618Ssam 	savesp = sp;
88416618Ssam 	eval(actual);
885*18231Slinton 	actsize = sp - savesp;
886*18231Slinton 	setreg(STKP,
887*18231Slinton 	    reg(STKP) - ((actsize + sizeof(Word) - 1) & ~(sizeof(Word) - 1))
888*18231Slinton 	);
889*18231Slinton 	dwrite(savesp, reg(STKP), actsize);
89016618Ssam 	sp = savesp;
89116618Ssam 	push(Address, reg(STKP));
89216618Ssam 	if (formal != nil and isopenarray(formal->type)) {
893*18231Slinton 	    push(integer, actsize div size(formal->type->type));
89416618Ssam 	}
895*18231Slinton     } else if (formal != nil) {
896*18231Slinton 	formsize = size(formal);
897*18231Slinton 	savesp = sp;
898*18231Slinton 	eval(actual);
899*18231Slinton 	actsize = sp - savesp;
900*18231Slinton 	if (actsize > formsize) {
901*18231Slinton 	    sp -= (actsize - formsize);
902*18231Slinton 	}
90316618Ssam     } else {
90416618Ssam 	eval(actual);
90516618Ssam     }
90616618Ssam }
90716618Ssam 
90816618Ssam /*
90916618Ssam  * Evaluate an argument list left-to-right.
91016618Ssam  */
91116618Ssam 
912*18231Slinton private integer evalargs(proc, arglist)
9139678Slinton Symbol proc;
9149678Slinton Node arglist;
9159678Slinton {
91616618Ssam     Node p, actual;
91716618Ssam     Symbol formal;
9189678Slinton     Stack *savesp;
919*18231Slinton     integer count;
92016618Ssam     boolean chk;
9219678Slinton 
9229678Slinton     savesp = sp;
9239678Slinton     count = 0;
92416618Ssam     formal = proc->chain;
92516618Ssam     chk = (boolean) (not nosource(proc));
9269678Slinton     for (p = arglist; p != nil; p = p->value.arg[1]) {
92716618Ssam 	assert(p->op == O_COMMA);
92816618Ssam 	actual = p->value.arg[0];
92916618Ssam 	if (not chkparam(actual, formal, chk)) {
93016618Ssam 	    fprintf(stderr, " in call to %s", symname(proc));
9319678Slinton 	    sp = savesp;
93216618Ssam 	    enderrmsg();
9339678Slinton 	}
93416618Ssam 	passparam(actual, formal);
93516618Ssam 	if (formal != nil) {
93616618Ssam 	    formal = formal->chain;
9379678Slinton 	}
9389678Slinton 	++count;
9399678Slinton     }
94016618Ssam     if (chk) {
94116618Ssam 	if (formal != nil) {
94216618Ssam 	    sp = savesp;
94316618Ssam 	    error("not enough parameters to %s", symname(proc));
94416618Ssam 	}
9459678Slinton     }
9469678Slinton     return count;
9479678Slinton }
9489678Slinton 
9499678Slinton public procreturn(f)
9509678Slinton Symbol f;
9519678Slinton {
952*18231Slinton     integer retvalsize;
953*18231Slinton     Node tmp;
954*18231Slinton     char *copy;
955*18231Slinton 
9569678Slinton     flushoutput();
9579678Slinton     popenv();
958*18231Slinton     if (endproc.isfunc) {
959*18231Slinton 	retvalsize = size(f->type);
960*18231Slinton 	if (retvalsize > sizeof(long)) {
961*18231Slinton 	    pushretval(retvalsize, true);
962*18231Slinton 	    copy = newarr(char, retvalsize);
963*18231Slinton 	    popn(retvalsize, copy);
964*18231Slinton 	    tmp = build(O_SCON, copy);
965*18231Slinton 	} else {
966*18231Slinton 	    tmp = build(O_LCON, (long) (reg(0)));
967*18231Slinton 	}
968*18231Slinton 	tmp->nodetype = f->type;
969*18231Slinton 	tfree(endproc.callnode);
970*18231Slinton 	*(endproc.callnode) = *(tmp);
971*18231Slinton 	dispose(tmp);
972*18231Slinton 	eval(endproc.cmdnode);
973*18231Slinton     } else {
974*18231Slinton 	putchar('\n');
975*18231Slinton 	printname(stdout, f);
976*18231Slinton 	printf(" returns successfully\n", symname(f));
977*18231Slinton     }
9789678Slinton     erecover();
9799678Slinton }
9809678Slinton 
9819678Slinton /*
9829678Slinton  * Push the current environment.
9839678Slinton  */
9849678Slinton 
9859678Slinton private pushenv()
9869678Slinton {
9879678Slinton     push(Address, pc);
9889678Slinton     push(Lineno, curline);
9899678Slinton     push(String, cursource);
9909678Slinton     push(Boolean, isstopped);
9919678Slinton     push(Symbol, curfunc);
99216618Ssam     push(Frame, curframe);
99316618Ssam     push(struct Frame, curframerec);
994*18231Slinton     push(CallEnv, endproc);
9959678Slinton     push(Word, reg(PROGCTR));
9969678Slinton     push(Word, reg(STKP));
9979678Slinton }
9989678Slinton 
9999678Slinton /*
10009678Slinton  * Pop back to the real world.
10019678Slinton  */
10029678Slinton 
10039678Slinton public popenv()
10049678Slinton {
1005*18231Slinton     String filename;
10069678Slinton 
10079678Slinton     setreg(STKP, pop(Word));
10089678Slinton     setreg(PROGCTR, pop(Word));
1009*18231Slinton     endproc = pop(CallEnv);
101016618Ssam     curframerec = pop(struct Frame);
101116618Ssam     curframe = pop(Frame);
10129678Slinton     curfunc = pop(Symbol);
10139678Slinton     isstopped = pop(Boolean);
10149678Slinton     filename = pop(String);
10159678Slinton     curline = pop(Lineno);
10169678Slinton     pc = pop(Address);
10179678Slinton     setsource(filename);
10189678Slinton }
10199678Slinton 
10209678Slinton /*
10219678Slinton  * Flush the debuggee's standard output.
10229678Slinton  *
10239678Slinton  * This is VERY dependent on the use of stdio.
10249678Slinton  */
10259678Slinton 
10269678Slinton public flushoutput()
10279678Slinton {
1028*18231Slinton     Symbol p, iob;
1029*18231Slinton     Stack *savesp;
10309678Slinton 
10319678Slinton     p = lookup(identname("fflush", true));
10329678Slinton     while (p != nil and not isblock(p)) {
10339678Slinton 	p = p->next_sym;
10349678Slinton     }
10359678Slinton     if (p != nil) {
10369678Slinton 	iob = lookup(identname("_iob", true));
10379678Slinton 	if (iob != nil) {
10389678Slinton 	    pushenv();
10399678Slinton 	    pc = codeloc(p);
10409678Slinton 	    savesp = sp;
10419678Slinton 	    push(long, address(iob, nil) + sizeof(struct _iobuf));
10429678Slinton 	    setreg(STKP, reg(STKP) - sizeof(long));
10439678Slinton 	    dwrite(savesp, reg(STKP), sizeof(long));
10449678Slinton 	    sp = savesp;
10459678Slinton 	    beginproc(p, 1);
10469678Slinton 	    stepto(return_addr());
10479678Slinton 	    popenv();
10489678Slinton 	}
10499678Slinton     }
10509678Slinton }
1051