xref: /csrg-svn/old/dbx/runtime.c (revision 30797)
121621Sdist /*
221621Sdist  * Copyright (c) 1983 Regents of the University of California.
321621Sdist  * All rights reserved.  The Berkeley software License Agreement
421621Sdist  * specifies the terms and conditions for redistribution.
521621Sdist  */
69678Slinton 
721621Sdist #ifndef lint
8*30797Sbostic static char sccsid[] = "@(#)runtime.c	5.3 (Berkeley) 04/06/87";
921621Sdist #endif not lint
109678Slinton 
1118231Slinton static char rcsid[] = "$Header: runtime.c,v 1.5 84/12/26 10:41:52 linton Exp $";
1218231Slinton 
139678Slinton /*
149678Slinton  * Runtime organization dependent routines, mostly dealing with
159678Slinton  * activation records.
169678Slinton  */
179678Slinton 
189678Slinton #include "defs.h"
199678Slinton #include "runtime.h"
209678Slinton #include "process.h"
219678Slinton #include "machine.h"
229678Slinton #include "events.h"
239678Slinton #include "mappings.h"
249678Slinton #include "symbols.h"
259678Slinton #include "tree.h"
269678Slinton #include "eval.h"
279678Slinton #include "operators.h"
289678Slinton #include "object.h"
2912546Scsvaf #include <sys/param.h>
309678Slinton 
319678Slinton #ifndef public
329678Slinton typedef struct Frame *Frame;
339678Slinton 
349678Slinton #include "machine.h"
359678Slinton #endif
369678Slinton 
379678Slinton #define NSAVEREG 12
389678Slinton 
399678Slinton struct Frame {
4018231Slinton     integer condition_handler;
4118231Slinton     integer mask;
429678Slinton     Address save_ap;		/* argument pointer */
439678Slinton     Address save_fp;		/* frame pointer */
449678Slinton     Address save_pc;		/* program counter */
459678Slinton     Word save_reg[NSAVEREG];	/* not necessarily there */
469678Slinton };
479678Slinton 
4816618Ssam private Frame curframe = nil;
4916618Ssam private struct Frame curframerec;
509678Slinton private Boolean walkingstack = false;
519678Slinton 
5216618Ssam #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp)
5316618Ssam 
5418231Slinton #define isstackaddr(addr) \
5518231Slinton     (((addr) < 0x80000000) and ((addr) > 0x80000000 - 0x200 * UPAGES))
5618231Slinton 
5718231Slinton typedef struct {
5818231Slinton     Node callnode;
5918231Slinton     Node cmdnode;
6018231Slinton     boolean isfunc;
6118231Slinton } CallEnv;
6218231Slinton 
6318231Slinton private CallEnv endproc;
6418231Slinton 
659678Slinton /*
669678Slinton  * Set a frame to the current activation record.
679678Slinton  */
689678Slinton 
getcurframe(frp)699678Slinton private getcurframe(frp)
7018231Slinton Frame frp;
719678Slinton {
729678Slinton     register int i;
739678Slinton 
749678Slinton     checkref(frp);
759678Slinton     frp->mask = reg(NREG);
769678Slinton     frp->save_ap = reg(ARGP);
779678Slinton     frp->save_fp = reg(FRP);
7818231Slinton     frp->save_pc = reg(PROGCTR);
799678Slinton     for (i = 0; i < NSAVEREG; i++) {
809678Slinton 	frp->save_reg[i] = reg(i);
819678Slinton     }
829678Slinton }
839678Slinton 
849678Slinton /*
8518231Slinton  * Get the saved registers from one frame to another
8618231Slinton  * given mask specifying which registers were actually saved.
8718231Slinton  */
8818231Slinton 
8918231Slinton #define bis(b, n) ((b & (1 << (n))) != 0)
9018231Slinton 
getsaveregs(newfrp,frp,mask)9118231Slinton private getsaveregs (newfrp, frp, mask)
9218231Slinton Frame newfrp, frp;
9318231Slinton integer mask;
9418231Slinton {
9518231Slinton     integer i, j;
9618231Slinton 
9718231Slinton     j = 0;
9818231Slinton     for (i = 0; i < NSAVEREG; i++) {
9918231Slinton 	if (bis(mask, i)) {
10018231Slinton 	    newfrp->save_reg[i] = frp->save_reg[j];
10118231Slinton 	    ++j;
10218231Slinton 	}
10318231Slinton     }
10418231Slinton }
10518231Slinton 
10618231Slinton /*
1079678Slinton  * Return a pointer to the next activation record up the stack.
1089678Slinton  * Return nil if there is none.
1099678Slinton  * Writes over space pointed to by given argument.
1109678Slinton  */
1119678Slinton 
nextframe(frp)1129678Slinton private Frame nextframe(frp)
1139678Slinton Frame frp;
1149678Slinton {
11518231Slinton     Frame newfrp;
1169678Slinton     struct Frame frame;
11718231Slinton     integer mask;
11812546Scsvaf     Address prev_frame, callpc;
11918231Slinton     static integer ntramp = 0;
1209678Slinton 
1219678Slinton     newfrp = frp;
12212546Scsvaf     prev_frame = frp->save_fp;
12312546Scsvaf 
12413937Slinton /*
12513937Slinton  *  The check for interrupt generated frames is taken from adb with only
12613937Slinton  *  partial understanding.  If you're in "sub" and on a sigxxx "sigsub"
12713937Slinton  *  gets control, then the stack does NOT look like <main, sub, sigsub>.
12812546Scsvaf  *
12912546Scsvaf  *  As best I can make out it looks like:
13012546Scsvaf  *
13113937Slinton  *     <main, (machine check exception block + sub), sysframe, sigsub>.
13213937Slinton  *
13313937Slinton  *  When the signal occurs an exception block and a frame for the routine
13413937Slinton  *  in which it occured are pushed on the user stack.  Then another frame
13513937Slinton  *  is pushed corresponding to a call from the kernel to sigsub.
13613937Slinton  *
13712546Scsvaf  *  The addr in sub at which the exception occured is not in sub.save_pc
13813937Slinton  *  but in the machine check exception block.  It is at the magic address
13914620Ssam  *  fp + 84.
14012546Scsvaf  *
14112546Scsvaf  *  The current approach ignores the sys_frame (what adb reports as sigtramp)
14213937Slinton  *  and takes the pc for sub from the exception block.  This allows the
14313937Slinton  *  "where" command to report <main, sub, sigsub>, which seems reasonable.
14412546Scsvaf  */
14512546Scsvaf 
14613937Slinton nextf:
14713937Slinton     dread(&frame, prev_frame, sizeof(struct Frame));
14813937Slinton     if (ntramp == 1) {
14914620Ssam 	dread(&callpc, prev_frame + 84, sizeof(callpc));
15013937Slinton     } else {
15113937Slinton 	callpc = frame.save_pc;
15213937Slinton     }
15318231Slinton     if (frame.save_fp == nil or frame.save_pc == (Address) -1) {
1549678Slinton 	newfrp = nil;
15518231Slinton     } else if (isstackaddr(callpc)) {
15618231Slinton 	ntramp++;
15718231Slinton 	prev_frame = frame.save_fp;
15818231Slinton 	goto nextf;
15913937Slinton     } else {
16012546Scsvaf 	frame.save_pc = callpc;
16113937Slinton         ntramp = 0;
1629678Slinton 	mask = ((frame.mask >> 16) & 0x0fff);
16318231Slinton 	getsaveregs(newfrp, &frame, mask);
1649678Slinton 	newfrp->condition_handler = frame.condition_handler;
1659678Slinton 	newfrp->mask = mask;
1669678Slinton 	newfrp->save_ap = frame.save_ap;
1679678Slinton 	newfrp->save_fp = frame.save_fp;
1689678Slinton 	newfrp->save_pc = frame.save_pc;
1699678Slinton     }
1709678Slinton     return newfrp;
1719678Slinton }
1729678Slinton 
1739678Slinton /*
17416618Ssam  * Get the current frame information in the given Frame and store the
17516618Ssam  * associated function in the given value-result parameter.
17616618Ssam  */
17716618Ssam 
getcurfunc(frp,fp)17816618Ssam private getcurfunc (frp, fp)
17916618Ssam Frame frp;
18016618Ssam Symbol *fp;
18116618Ssam {
18216618Ssam     getcurframe(frp);
18316618Ssam     *fp = whatblock(frp->save_pc);
18416618Ssam }
18516618Ssam 
18616618Ssam /*
18716618Ssam  * Return the frame associated with the next function up the call stack, or
18816618Ssam  * nil if there is none.  The function is returned in a value-result parameter.
18916618Ssam  * For "inline" functions the statically outer function and same frame
19016618Ssam  * are returned.
19116618Ssam  */
19216618Ssam 
nextfunc(frp,fp)19318231Slinton public Frame nextfunc (frp, fp)
19416618Ssam Frame frp;
19516618Ssam Symbol *fp;
19616618Ssam {
19716618Ssam     Symbol t;
19816618Ssam     Frame nfrp;
19916618Ssam 
20016618Ssam     t = *fp;
20116618Ssam     checkref(t);
20216618Ssam     if (isinline(t)) {
20316618Ssam 	t = container(t);
20416618Ssam 	nfrp = frp;
20516618Ssam     } else {
20616618Ssam 	nfrp = nextframe(frp);
20716618Ssam 	if (nfrp == nil) {
20816618Ssam 	    t = nil;
20916618Ssam 	} else {
21016618Ssam 	    t = whatblock(nfrp->save_pc);
21116618Ssam 	}
21216618Ssam     }
21316618Ssam     *fp = t;
21416618Ssam     return nfrp;
21516618Ssam }
21616618Ssam 
21716618Ssam /*
2189678Slinton  * Return the frame associated with the given function.
2199678Slinton  * If the function is nil, return the most recently activated frame.
2209678Slinton  *
2219678Slinton  * Static allocation for the frame.
2229678Slinton  */
2239678Slinton 
findframe(f)2249678Slinton public Frame findframe(f)
2259678Slinton Symbol f;
2269678Slinton {
22718231Slinton     Frame frp;
2289678Slinton     static struct Frame frame;
22911866Slinton     Symbol p;
23018231Slinton     Boolean done;
2319678Slinton 
2329678Slinton     frp = &frame;
2339678Slinton     getcurframe(frp);
23418231Slinton     if (f != nil) {
23518231Slinton 	if (f == curfunc and curframe != nil) {
23618231Slinton 	    *frp = *curframe;
23718231Slinton 	} else {
23818231Slinton 	    done = false;
23918231Slinton 	    p = whatblock(frp->save_pc);
24018231Slinton 	    do {
24118231Slinton 		if (p == f) {
24218231Slinton 		    done = true;
24318231Slinton 		} else if (p == program) {
24418231Slinton 		    done = true;
24518231Slinton 		    frp = nil;
24618231Slinton 		} else {
24718231Slinton 		    frp = nextfunc(frp, &p);
24818231Slinton 		    if (frp == nil) {
24918231Slinton 			done = true;
25018231Slinton 		    }
25118231Slinton 		}
25218231Slinton 	    } while (not done);
25315784Ssam 	}
25418231Slinton     }
25518231Slinton     return frp;
25618231Slinton }
25718231Slinton 
25818231Slinton /*
25918231Slinton  * Set the registers according to the given frame pointer.
26018231Slinton  */
26118231Slinton 
getnewregs(addr)26218231Slinton public getnewregs (addr)
26318231Slinton Address addr;
26418231Slinton {
26518231Slinton     struct Frame frame;
26618231Slinton     integer i, j, mask;
26718231Slinton 
26818231Slinton     dread(&frame, addr, sizeof(frame));
26918231Slinton     setreg(ARGP, frame.save_ap);
27018231Slinton     setreg(FRP, frame.save_fp);
27118231Slinton     setreg(PROGCTR, frame.save_pc);
27218231Slinton     mask = ((frame.mask >> 16) & 0x0fff);
27318231Slinton     j = 0;
27418231Slinton     for (i = 0; i < NSAVEREG; i++) {
27518231Slinton 	if (bis(mask, i)) {
27618231Slinton 	    setreg(i, frame.save_reg[j]);
27718231Slinton 	    ++j;
27816636Ssam 	}
2799678Slinton     }
28018231Slinton     pc = frame.save_pc;
28118231Slinton     setcurfunc(whatblock(pc));
2829678Slinton }
2839678Slinton 
2849678Slinton /*
2859678Slinton  * Find the return address of the current procedure/function.
2869678Slinton  */
2879678Slinton 
return_addr()2889678Slinton public Address return_addr()
2899678Slinton {
2909678Slinton     Frame frp;
2919678Slinton     Address addr;
2929678Slinton     struct Frame frame;
2939678Slinton 
2949678Slinton     frp = &frame;
2959678Slinton     getcurframe(frp);
2969678Slinton     frp = nextframe(frp);
2979678Slinton     if (frp == nil) {
2989678Slinton 	addr = 0;
2999678Slinton     } else {
3009678Slinton 	addr = frp->save_pc;
3019678Slinton     }
3029678Slinton     return addr;
3039678Slinton }
3049678Slinton 
3059678Slinton /*
3069678Slinton  * Push the value associated with the current function.
3079678Slinton  */
3089678Slinton 
pushretval(len,isindirect)3099678Slinton public pushretval(len, isindirect)
31018231Slinton integer len;
31118231Slinton boolean isindirect;
3129678Slinton {
3139678Slinton     Word r0;
3149678Slinton 
3159678Slinton     r0 = reg(0);
3169678Slinton     if (isindirect) {
3179678Slinton 	rpush((Address) r0, len);
3189678Slinton     } else {
3199678Slinton 	switch (len) {
3209678Slinton 	    case sizeof(char):
3219678Slinton 		push(char, r0);
3229678Slinton 		break;
3239678Slinton 
3249678Slinton 	    case sizeof(short):
3259678Slinton 		push(short, r0);
3269678Slinton 		break;
3279678Slinton 
3289678Slinton 	    default:
3299678Slinton 		if (len == sizeof(Word)) {
3309678Slinton 		    push(Word, r0);
3319678Slinton 		} else if (len == 2*sizeof(Word)) {
3329678Slinton 		    push(Word, r0);
3339678Slinton 		    push(Word, reg(1));
3349678Slinton 		} else {
33518231Slinton 		    error("[internal error: bad size %d in pushretval]", len);
3369678Slinton 		}
3379678Slinton 		break;
3389678Slinton 	}
3399678Slinton     }
3409678Slinton }
3419678Slinton 
3429678Slinton /*
3439678Slinton  * Return the base address for locals in the given frame.
3449678Slinton  */
3459678Slinton 
locals_base(frp)3469678Slinton public Address locals_base(frp)
34718231Slinton Frame frp;
3489678Slinton {
3499678Slinton     return (frp == nil) ? reg(FRP) : frp->save_fp;
3509678Slinton }
3519678Slinton 
3529678Slinton /*
3539678Slinton  * Return the base address for arguments in the given frame.
3549678Slinton  */
3559678Slinton 
args_base(frp)3569678Slinton public Address args_base(frp)
35718231Slinton Frame frp;
3589678Slinton {
3599678Slinton     return (frp == nil) ? reg(ARGP) : frp->save_ap;
3609678Slinton }
3619678Slinton 
3629678Slinton /*
3639678Slinton  * Return saved register n from the given frame.
3649678Slinton  */
3659678Slinton 
savereg(n,frp)3669678Slinton public Word savereg(n, frp)
36718231Slinton integer n;
36818231Slinton Frame frp;
3699678Slinton {
37018231Slinton     Word w;
3719678Slinton 
3729678Slinton     if (frp == nil) {
3739678Slinton 	w = reg(n);
3749678Slinton     } else {
3759678Slinton 	switch (n) {
3769678Slinton 	    case ARGP:
3779678Slinton 		w = frp->save_ap;
3789678Slinton 		break;
3799678Slinton 
3809678Slinton 	    case FRP:
3819678Slinton 		w = frp->save_fp;
3829678Slinton 		break;
3839678Slinton 
3849678Slinton 	    case STKP:
3859678Slinton 		w = reg(STKP);
3869678Slinton 		break;
3879678Slinton 
3889678Slinton 	    case PROGCTR:
3899678Slinton 		w = frp->save_pc;
3909678Slinton 		break;
3919678Slinton 
3929678Slinton 	    default:
3939678Slinton 		assert(n >= 0 and n < NSAVEREG);
3949678Slinton 		w = frp->save_reg[n];
3959678Slinton 		break;
3969678Slinton 	}
3979678Slinton     }
3989678Slinton     return w;
3999678Slinton }
4009678Slinton 
4019678Slinton /*
4029678Slinton  * Return the nth argument to the current procedure.
4039678Slinton  */
4049678Slinton 
argn(n,frp)4059678Slinton public Word argn(n, frp)
40618231Slinton integer n;
4079678Slinton Frame frp;
4089678Slinton {
4099678Slinton     Word w;
4109678Slinton 
4119678Slinton     dread(&w, args_base(frp) + (n * sizeof(Word)), sizeof(w));
4129678Slinton     return w;
4139678Slinton }
4149678Slinton 
4159678Slinton /*
41618231Slinton  * Print a list of currently active blocks starting with most recent.
4179678Slinton  */
4189678Slinton 
wherecmd()41918231Slinton public wherecmd()
4209678Slinton {
42118231Slinton     walkstack(false);
4229678Slinton }
4239678Slinton 
4249678Slinton /*
42518231Slinton  * Print the variables in the given frame or the current one if nil.
4269678Slinton  */
4279678Slinton 
dump(func)42818231Slinton public dump (func)
42918231Slinton Symbol func;
4309678Slinton {
43118231Slinton     Symbol f;
43218231Slinton     Frame frp;
43318231Slinton 
43418231Slinton     if (func == nil) {
43518231Slinton 	f = curfunc;
43618231Slinton 	if (curframe != nil) {
43718231Slinton 	    frp = curframe;
43818231Slinton 	} else {
43918231Slinton 	    frp = findframe(f);
44018231Slinton 	}
44118231Slinton     } else {
44218231Slinton 	f = func;
44318231Slinton 	frp = findframe(f);
44418231Slinton     }
44518231Slinton     showaggrs = true;
44618231Slinton     printcallinfo(f, frp);
44718231Slinton     dumpvars(f, frp);
4489678Slinton }
4499678Slinton 
4509678Slinton /*
45118231Slinton  * Dump all values.
4529678Slinton  */
4539678Slinton 
dumpall()45418231Slinton public dumpall ()
4559678Slinton {
4569678Slinton     walkstack(true);
4579678Slinton }
4589678Slinton 
4599678Slinton /*
4609678Slinton  * Walk the stack of active procedures printing information
4619678Slinton  * about each active procedure.
4629678Slinton  */
4639678Slinton 
walkstack(dumpvariables)4649678Slinton private walkstack(dumpvariables)
4659678Slinton Boolean dumpvariables;
4669678Slinton {
46718231Slinton     Frame frp;
46818231Slinton     boolean save;
46916618Ssam     Symbol f;
4709678Slinton     struct Frame frame;
4719678Slinton 
47218231Slinton     if (notstarted(process) or isfinished(process)) {
4739678Slinton 	error("program is not active");
4749678Slinton     } else {
4759678Slinton 	save = walkingstack;
4769678Slinton 	walkingstack = true;
47718231Slinton 	showaggrs = dumpvariables;
4789678Slinton 	frp = &frame;
47916618Ssam 	getcurfunc(frp, &f);
48018231Slinton 	for (;;) {
48118231Slinton 	    printcallinfo(f, frp);
4829678Slinton 	    if (dumpvariables) {
4839678Slinton 		dumpvars(f, frp);
4849678Slinton 		putchar('\n');
4859678Slinton 	    }
48616618Ssam 	    frp = nextfunc(frp, &f);
48718231Slinton 	    if (frp == nil or f == program) {
48818231Slinton 		break;
48918231Slinton 	    }
49018231Slinton 	}
4919678Slinton 	if (dumpvariables) {
4929678Slinton 	    printf("in \"%s\":\n", symname(program));
4939678Slinton 	    dumpvars(program, nil);
4949678Slinton 	    putchar('\n');
4959678Slinton 	}
4969678Slinton 	walkingstack = save;
4979678Slinton     }
4989678Slinton }
4999678Slinton 
5009678Slinton /*
50118231Slinton  * Print out the information about a call, i.e.,
50218231Slinton  * routine name, parameter values, and source location.
50318231Slinton  */
50418231Slinton 
printcallinfo(f,frp)50518231Slinton private printcallinfo (f, frp)
50618231Slinton Symbol f;
50718231Slinton Frame frp;
50818231Slinton {
50918231Slinton     Lineno line;
51018231Slinton     Address savepc;
51118231Slinton 
51218231Slinton     savepc = frp->save_pc;
51318231Slinton     if (frp->save_fp != reg(FRP)) {
51418231Slinton 	savepc -= 1;
51518231Slinton     }
51618231Slinton     printname(stdout, f);
51718231Slinton     if (not isinline(f)) {
51818231Slinton 	printparams(f, frp);
51918231Slinton     }
52018231Slinton     line = srcline(savepc);
52118231Slinton     if (line != 0) {
52218231Slinton 	printf(", line %d", line);
52318231Slinton 	printf(" in \"%s\"\n", srcfilename(savepc));
52418231Slinton     } else {
52518231Slinton 	printf(" at 0x%x\n", savepc);
52618231Slinton     }
52718231Slinton }
52818231Slinton 
52918231Slinton /*
53016618Ssam  * Set the current function to the given symbol.
53116618Ssam  * We must adjust "curframe" so that subsequent operations are
53216618Ssam  * not confused; for simplicity we simply clear it.
53316618Ssam  */
53416618Ssam 
setcurfunc(f)53516618Ssam public setcurfunc (f)
53616618Ssam Symbol f;
53716618Ssam {
53816618Ssam     curfunc = f;
53916618Ssam     curframe = nil;
54016618Ssam }
54116618Ssam 
54216618Ssam /*
54318231Slinton  * Return the frame for the current function.
54418231Slinton  * The space for the frame is allocated statically.
54518231Slinton  */
54618231Slinton 
curfuncframe()54718231Slinton public Frame curfuncframe ()
54818231Slinton {
54918231Slinton     static struct Frame frame;
55018231Slinton     Frame frp;
55118231Slinton 
55218231Slinton     if (curframe == nil) {
55318231Slinton 	frp = findframe(curfunc);
55418231Slinton 	curframe = &curframerec;
55518231Slinton 	*curframe = *frp;
55618231Slinton     } else {
55718231Slinton 	frp = &frame;
55818231Slinton 	*frp = *curframe;
55918231Slinton     }
56018231Slinton     return frp;
56118231Slinton }
56218231Slinton 
56318231Slinton /*
56416618Ssam  * Set curfunc to be N up/down the stack from its current value.
56516618Ssam  */
56616618Ssam 
up(n)56716618Ssam public up (n)
56816618Ssam integer n;
56916618Ssam {
57016618Ssam     integer i;
57116618Ssam     Symbol f;
57216618Ssam     Frame frp;
57316618Ssam     boolean done;
57416618Ssam 
57516618Ssam     if (not isactive(program)) {
57616618Ssam 	error("program is not active");
57716618Ssam     } else if (curfunc == nil) {
57816618Ssam 	error("no current function");
57916618Ssam     } else {
58016618Ssam 	i = 0;
58116618Ssam 	f = curfunc;
58218231Slinton 	frp = curfuncframe();
58316618Ssam 	done = false;
58416618Ssam 	do {
58516618Ssam 	    if (frp == nil) {
58616618Ssam 		done = true;
58716618Ssam 		error("not that many levels");
58816618Ssam 	    } else if (i >= n) {
58916618Ssam 		done = true;
59016618Ssam 		curfunc = f;
59116618Ssam 		curframe = &curframerec;
59216618Ssam 		*curframe = *frp;
59318231Slinton 		showaggrs = false;
59418231Slinton 		printcallinfo(curfunc, curframe);
59516618Ssam 	    } else if (f == program) {
59616618Ssam 		done = true;
59716618Ssam 		error("not that many levels");
59816618Ssam 	    } else {
59916618Ssam 		frp = nextfunc(frp, &f);
60016618Ssam 	    }
60116618Ssam 	    ++i;
60216618Ssam 	} while (not done);
60316618Ssam     }
60416618Ssam }
60516618Ssam 
down(n)60616618Ssam public down (n)
60716618Ssam integer n;
60816618Ssam {
60916618Ssam     integer i, depth;
61018231Slinton     Frame frp, curfrp;
61116618Ssam     Symbol f;
61216618Ssam     struct Frame frame;
61316618Ssam 
61416618Ssam     if (not isactive(program)) {
61516618Ssam 	error("program is not active");
61616618Ssam     } else if (curfunc == nil) {
61716618Ssam 	error("no current function");
61816618Ssam     } else {
61916618Ssam 	depth = 0;
62016618Ssam 	frp = &frame;
62116618Ssam 	getcurfunc(frp, &f);
62216618Ssam 	if (curframe == nil) {
62318231Slinton 	    curfrp = findframe(curfunc);
62416618Ssam 	    curframe = &curframerec;
62518231Slinton 	    *curframe = *curfrp;
62616618Ssam 	}
62716618Ssam 	while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) {
62816618Ssam 	    frp = nextfunc(frp, &f);
62916618Ssam 	    ++depth;
63016618Ssam 	}
63116618Ssam 	if (f == nil or n > depth) {
63216618Ssam 	    error("not that many levels");
63316618Ssam 	} else {
63416618Ssam 	    depth -= n;
63516618Ssam 	    frp = &frame;
63616618Ssam 	    getcurfunc(frp, &f);
63716618Ssam 	    for (i = 0; i < depth; i++) {
63816618Ssam 		frp = nextfunc(frp, &f);
63916618Ssam 		assert(frp != nil);
64016618Ssam 	    }
64116618Ssam 	    curfunc = f;
64216618Ssam 	    *curframe = *frp;
64318231Slinton 	    showaggrs = false;
64418231Slinton 	    printcallinfo(curfunc, curframe);
64516618Ssam 	}
64616618Ssam     }
64716618Ssam }
64816618Ssam 
64916618Ssam /*
6509678Slinton  * Find the entry point of a procedure or function.
6519678Slinton  */
6529678Slinton 
findbeginning(f)65318231Slinton public findbeginning (f)
6549678Slinton Symbol f;
6559678Slinton {
65616618Ssam     if (isinternal(f)) {
65716618Ssam 	f->symvalue.funcv.beginaddr += 15;
65816618Ssam     } else {
65916618Ssam 	f->symvalue.funcv.beginaddr += 2;
66016618Ssam     }
6619678Slinton }
6629678Slinton 
6639678Slinton /*
6649678Slinton  * Return the address corresponding to the first line in a function.
6659678Slinton  */
6669678Slinton 
firstline(f)6679678Slinton public Address firstline(f)
6689678Slinton Symbol f;
6699678Slinton {
6709678Slinton     Address addr;
6719678Slinton 
6729678Slinton     addr = codeloc(f);
6739678Slinton     while (linelookup(addr) == 0 and addr < objsize) {
6749678Slinton 	++addr;
6759678Slinton     }
6769678Slinton     if (addr == objsize) {
6779678Slinton 	addr = -1;
6789678Slinton     }
6799678Slinton     return addr;
6809678Slinton }
6819678Slinton 
6829678Slinton /*
6839678Slinton  * Catcher drops strike three ...
6849678Slinton  */
6859678Slinton 
runtofirst()6869678Slinton public runtofirst()
6879678Slinton {
6889678Slinton     Address addr;
6899678Slinton 
6909678Slinton     addr = pc;
6919678Slinton     while (linelookup(addr) == 0 and addr < objsize) {
6929678Slinton 	++addr;
6939678Slinton     }
6949678Slinton     if (addr < objsize) {
6959678Slinton 	stepto(addr);
6969678Slinton     }
6979678Slinton }
6989678Slinton 
6999678Slinton /*
7009678Slinton  * Return the address corresponding to the end of the program.
7019678Slinton  *
7029678Slinton  * We look for the entry to "exit".
7039678Slinton  */
7049678Slinton 
lastaddr()7059678Slinton public Address lastaddr()
7069678Slinton {
70718231Slinton     Symbol s;
7089678Slinton 
7099678Slinton     s = lookup(identname("exit", true));
7109678Slinton     if (s == nil) {
7119678Slinton 	panic("can't find exit");
7129678Slinton     }
7139678Slinton     return codeloc(s);
7149678Slinton }
7159678Slinton 
7169678Slinton /*
7179678Slinton  * Decide if the given function is currently active.
7189678Slinton  *
7199678Slinton  * We avoid calls to "findframe" during a stack trace for efficiency.
7209678Slinton  * Presumably information evaluated while walking the stack is active.
7219678Slinton  */
7229678Slinton 
isactive(f)7239678Slinton public Boolean isactive(f)
7249678Slinton Symbol f;
7259678Slinton {
72618231Slinton     Boolean b;
7279678Slinton 
7289678Slinton     if (isfinished(process)) {
7299678Slinton 	b = false;
7309678Slinton     } else {
7319678Slinton 	if (walkingstack or f == program or
7329678Slinton 	  (ismodule(f) and isactive(container(f)))) {
7339678Slinton 	    b = true;
7349678Slinton 	} else {
7359678Slinton 	    b = (Boolean) (findframe(f) != nil);
7369678Slinton 	}
7379678Slinton     }
7389678Slinton     return b;
7399678Slinton }
7409678Slinton 
7419678Slinton /*
7429678Slinton  * Evaluate a call to a procedure.
7439678Slinton  */
7449678Slinton 
callproc(exprnode,isfunc)74518231Slinton public callproc(exprnode, isfunc)
74618231Slinton Node exprnode;
74718231Slinton boolean isfunc;
7489678Slinton {
74918231Slinton     Node procnode, arglist;
7509678Slinton     Symbol proc;
75118231Slinton     integer argc;
7529678Slinton 
75318231Slinton     procnode = exprnode->value.arg[0];
75418231Slinton     arglist = exprnode->value.arg[1];
7559678Slinton     if (procnode->op != O_SYM) {
7569678Slinton 	beginerrmsg();
7579678Slinton 	fprintf(stderr, "can't call \"");
7589678Slinton 	prtree(stderr, procnode);
7599678Slinton 	fprintf(stderr, "\"");
7609678Slinton 	enderrmsg();
7619678Slinton     }
7629678Slinton     assert(procnode->op == O_SYM);
7639678Slinton     proc = procnode->value.sym;
7649678Slinton     if (not isblock(proc)) {
7659678Slinton 	error("\"%s\" is not a procedure or function", symname(proc));
7669678Slinton     }
76718231Slinton     endproc.isfunc = isfunc;
76818231Slinton     endproc.callnode = exprnode;
76918231Slinton     endproc.cmdnode = topnode;
7709678Slinton     pushenv();
7719678Slinton     pc = codeloc(proc);
7729678Slinton     argc = pushargs(proc, arglist);
7739678Slinton     beginproc(proc, argc);
77418231Slinton     event_once(
77518231Slinton 	build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)),
77618231Slinton 	buildcmdlist(build(O_PROCRTN, proc))
77718231Slinton     );
77818231Slinton     isstopped = false;
77918231Slinton     if (not bpact()) {
78018231Slinton 	isstopped = true;
78118231Slinton 	cont(0);
78218231Slinton     }
78318231Slinton     /*
78418231Slinton      * bpact() won't return true, it will call printstatus() and go back
78518231Slinton      * to command input if a breakpoint is found.
78618231Slinton      */
7879678Slinton     /* NOTREACHED */
7889678Slinton }
7899678Slinton 
7909678Slinton /*
7919678Slinton  * Push the arguments on the process' stack.  We do this by first
7929678Slinton  * evaluating them on the "eval" stack, then copying into the process'
7939678Slinton  * space.
7949678Slinton  */
7959678Slinton 
pushargs(proc,arglist)79618231Slinton private integer pushargs(proc, arglist)
7979678Slinton Symbol proc;
7989678Slinton Node arglist;
7999678Slinton {
8009678Slinton     Stack *savesp;
8019678Slinton     int argc, args_size;
8029678Slinton 
8039678Slinton     savesp = sp;
80425807Sdonn     if (varIsSet("$unsafecall")) {
80525807Sdonn 	argc = unsafe_evalargs(proc, arglist);
80625807Sdonn     } else {
80725807Sdonn 	argc = evalargs(proc, arglist);
80825807Sdonn     }
8099678Slinton     args_size = sp - savesp;
8109678Slinton     setreg(STKP, reg(STKP) - args_size);
8119678Slinton     dwrite(savesp, reg(STKP), args_size);
8129678Slinton     sp = savesp;
8139678Slinton     return argc;
8149678Slinton }
8159678Slinton 
8169678Slinton /*
81716618Ssam  * Check to see if an expression is correct for a given parameter.
81816618Ssam  * If the given parameter is false, don't worry about type inconsistencies.
81916618Ssam  *
82016618Ssam  * Return whether or not it is ok.
8219678Slinton  */
8229678Slinton 
chkparam(actual,formal,chk)82316618Ssam private boolean chkparam (actual, formal, chk)
82416618Ssam Node actual;
82516618Ssam Symbol formal;
82616618Ssam boolean chk;
82716618Ssam {
82816618Ssam     boolean b;
82916618Ssam 
83016618Ssam     b = true;
83116618Ssam     if (chk) {
83216618Ssam 	if (formal == nil) {
83316618Ssam 	    beginerrmsg();
83416618Ssam 	    fprintf(stderr, "too many parameters");
83516618Ssam 	    b = false;
83616618Ssam 	} else if (not compatible(formal->type, actual->nodetype)) {
83716618Ssam 	    beginerrmsg();
83816618Ssam 	    fprintf(stderr, "type mismatch for %s", symname(formal));
83916618Ssam 	    b = false;
84016618Ssam 	}
84116618Ssam     }
84218231Slinton     if (b and formal != nil and
84318231Slinton 	isvarparam(formal) and not isopenarray(formal->type) and
84418231Slinton 	not (
84518231Slinton 	    actual->op == O_RVAL or actual->nodetype == t_addr or
84618231Slinton 	    (
84718231Slinton 		actual->op == O_TYPERENAME and
84818231Slinton 		(
84918231Slinton 		    actual->value.arg[0]->op == O_RVAL or
85018231Slinton 		    actual->value.arg[0]->nodetype == t_addr
85118231Slinton 		)
85218231Slinton 	    )
85318231Slinton 	)
85418231Slinton     ) {
85516618Ssam 	beginerrmsg();
85616618Ssam 	fprintf(stderr, "expected variable, found \"");
85716618Ssam 	prtree(stderr, actual);
85816618Ssam 	fprintf(stderr, "\"");
85916618Ssam 	b = false;
86016618Ssam     }
86116618Ssam     return b;
86216618Ssam }
86316618Ssam 
86416618Ssam /*
86516618Ssam  * Pass an expression to a particular parameter.
86616618Ssam  *
86716618Ssam  * Normally we pass either the address or value, but in some cases
86816618Ssam  * (such as C strings) we want to copy the value onto the stack and
86916618Ssam  * pass its address.
87018231Slinton  *
87118231Slinton  * Another special case raised by strings is the possibility that
87218231Slinton  * the actual parameter will be larger than the formal, even with
87318231Slinton  * appropriate type-checking.  This occurs because we assume during
87418231Slinton  * evaluation that strings are null-terminated, whereas some languages,
87518231Slinton  * notably Pascal, do not work under that assumption.
87616618Ssam  */
87716618Ssam 
passparam(actual,formal)87816618Ssam private passparam (actual, formal)
87916618Ssam Node actual;
88016618Ssam Symbol formal;
88116618Ssam {
88216618Ssam     boolean b;
88316618Ssam     Address addr;
88416618Ssam     Stack *savesp;
88518231Slinton     integer actsize, formsize;
88616618Ssam 
88718231Slinton     if (formal != nil and isvarparam(formal) and
88818231Slinton 	(not isopenarray(formal->type))
88918231Slinton     ) {
89016618Ssam 	addr = lval(actual->value.arg[0]);
89116618Ssam 	push(Address, addr);
89216618Ssam     } else if (passaddr(formal, actual->nodetype)) {
89316618Ssam 	savesp = sp;
89416618Ssam 	eval(actual);
89518231Slinton 	actsize = sp - savesp;
89618231Slinton 	setreg(STKP,
89718231Slinton 	    reg(STKP) - ((actsize + sizeof(Word) - 1) & ~(sizeof(Word) - 1))
89818231Slinton 	);
89918231Slinton 	dwrite(savesp, reg(STKP), actsize);
90016618Ssam 	sp = savesp;
90116618Ssam 	push(Address, reg(STKP));
90216618Ssam 	if (formal != nil and isopenarray(formal->type)) {
90318231Slinton 	    push(integer, actsize div size(formal->type->type));
90416618Ssam 	}
90518231Slinton     } else if (formal != nil) {
90618231Slinton 	formsize = size(formal);
90718231Slinton 	savesp = sp;
90818231Slinton 	eval(actual);
90918231Slinton 	actsize = sp - savesp;
91018231Slinton 	if (actsize > formsize) {
91118231Slinton 	    sp -= (actsize - formsize);
91218231Slinton 	}
91316618Ssam     } else {
91416618Ssam 	eval(actual);
91516618Ssam     }
91616618Ssam }
91716618Ssam 
91816618Ssam /*
91916618Ssam  * Evaluate an argument list left-to-right.
92016618Ssam  */
92116618Ssam 
evalargs(proc,arglist)92218231Slinton private integer evalargs(proc, arglist)
9239678Slinton Symbol proc;
9249678Slinton Node arglist;
9259678Slinton {
92616618Ssam     Node p, actual;
92716618Ssam     Symbol formal;
9289678Slinton     Stack *savesp;
92918231Slinton     integer count;
93016618Ssam     boolean chk;
9319678Slinton 
9329678Slinton     savesp = sp;
9339678Slinton     count = 0;
93416618Ssam     formal = proc->chain;
93516618Ssam     chk = (boolean) (not nosource(proc));
9369678Slinton     for (p = arglist; p != nil; p = p->value.arg[1]) {
93716618Ssam 	assert(p->op == O_COMMA);
93816618Ssam 	actual = p->value.arg[0];
93916618Ssam 	if (not chkparam(actual, formal, chk)) {
94016618Ssam 	    fprintf(stderr, " in call to %s", symname(proc));
9419678Slinton 	    sp = savesp;
94216618Ssam 	    enderrmsg();
9439678Slinton 	}
94416618Ssam 	passparam(actual, formal);
94516618Ssam 	if (formal != nil) {
94616618Ssam 	    formal = formal->chain;
9479678Slinton 	}
9489678Slinton 	++count;
9499678Slinton     }
95016618Ssam     if (chk) {
95116618Ssam 	if (formal != nil) {
95216618Ssam 	    sp = savesp;
95316618Ssam 	    error("not enough parameters to %s", symname(proc));
95416618Ssam 	}
9559678Slinton     }
9569678Slinton     return count;
9579678Slinton }
9589678Slinton 
95925807Sdonn /*
96025807Sdonn  * Evaluate an argument list without concern for matching the formal
96125807Sdonn  * parameters of a function in type or quantity.  Useful for functions
96225807Sdonn  * like C's printf().
96325807Sdonn  */
96425807Sdonn 
unsafe_evalargs(proc,arglist)96525807Sdonn private integer unsafe_evalargs(proc, arglist)
96625807Sdonn Symbol proc;
96725807Sdonn Node arglist;
96825807Sdonn {
96925807Sdonn     Node p;
97025807Sdonn     Integer count;
97125807Sdonn 
97225807Sdonn     count = 0;
97325807Sdonn     for (p = arglist; p != nil; p = p->value.arg[1]) {
97425807Sdonn 	assert(p->op == O_COMMA);
97525807Sdonn 	eval(p->value.arg[0]);
97625807Sdonn 	++count;
97725807Sdonn     }
97825807Sdonn     return count;
97925807Sdonn }
98025807Sdonn 
procreturn(f)9819678Slinton public procreturn(f)
9829678Slinton Symbol f;
9839678Slinton {
98418231Slinton     integer retvalsize;
98518231Slinton     Node tmp;
98618231Slinton     char *copy;
98718231Slinton 
9889678Slinton     flushoutput();
9899678Slinton     popenv();
99018231Slinton     if (endproc.isfunc) {
99118231Slinton 	retvalsize = size(f->type);
99218231Slinton 	if (retvalsize > sizeof(long)) {
99318231Slinton 	    pushretval(retvalsize, true);
99418231Slinton 	    copy = newarr(char, retvalsize);
99518231Slinton 	    popn(retvalsize, copy);
99618231Slinton 	    tmp = build(O_SCON, copy);
99718231Slinton 	} else {
99818231Slinton 	    tmp = build(O_LCON, (long) (reg(0)));
99918231Slinton 	}
100018231Slinton 	tmp->nodetype = f->type;
100118231Slinton 	tfree(endproc.callnode);
100218231Slinton 	*(endproc.callnode) = *(tmp);
100318231Slinton 	dispose(tmp);
100418231Slinton 	eval(endproc.cmdnode);
100518231Slinton     } else {
100618231Slinton 	putchar('\n');
100718231Slinton 	printname(stdout, f);
1008*30797Sbostic 	printf("%s returns successfully\n", symname(f));
100918231Slinton     }
10109678Slinton     erecover();
10119678Slinton }
10129678Slinton 
10139678Slinton /*
10149678Slinton  * Push the current environment.
10159678Slinton  */
10169678Slinton 
pushenv()10179678Slinton private pushenv()
10189678Slinton {
10199678Slinton     push(Address, pc);
10209678Slinton     push(Lineno, curline);
10219678Slinton     push(String, cursource);
10229678Slinton     push(Boolean, isstopped);
10239678Slinton     push(Symbol, curfunc);
102416618Ssam     push(Frame, curframe);
102516618Ssam     push(struct Frame, curframerec);
102618231Slinton     push(CallEnv, endproc);
10279678Slinton     push(Word, reg(PROGCTR));
10289678Slinton     push(Word, reg(STKP));
10299678Slinton }
10309678Slinton 
10319678Slinton /*
10329678Slinton  * Pop back to the real world.
10339678Slinton  */
10349678Slinton 
popenv()10359678Slinton public popenv()
10369678Slinton {
103718231Slinton     String filename;
10389678Slinton 
10399678Slinton     setreg(STKP, pop(Word));
10409678Slinton     setreg(PROGCTR, pop(Word));
104118231Slinton     endproc = pop(CallEnv);
104216618Ssam     curframerec = pop(struct Frame);
104316618Ssam     curframe = pop(Frame);
10449678Slinton     curfunc = pop(Symbol);
10459678Slinton     isstopped = pop(Boolean);
10469678Slinton     filename = pop(String);
10479678Slinton     curline = pop(Lineno);
10489678Slinton     pc = pop(Address);
10499678Slinton     setsource(filename);
10509678Slinton }
10519678Slinton 
10529678Slinton /*
10539678Slinton  * Flush the debuggee's standard output.
10549678Slinton  *
10559678Slinton  * This is VERY dependent on the use of stdio.
10569678Slinton  */
10579678Slinton 
flushoutput()10589678Slinton public flushoutput()
10599678Slinton {
106018231Slinton     Symbol p, iob;
106118231Slinton     Stack *savesp;
10629678Slinton 
10639678Slinton     p = lookup(identname("fflush", true));
10649678Slinton     while (p != nil and not isblock(p)) {
10659678Slinton 	p = p->next_sym;
10669678Slinton     }
10679678Slinton     if (p != nil) {
10689678Slinton 	iob = lookup(identname("_iob", true));
10699678Slinton 	if (iob != nil) {
10709678Slinton 	    pushenv();
10719678Slinton 	    pc = codeloc(p);
10729678Slinton 	    savesp = sp;
10739678Slinton 	    push(long, address(iob, nil) + sizeof(struct _iobuf));
10749678Slinton 	    setreg(STKP, reg(STKP) - sizeof(long));
10759678Slinton 	    dwrite(savesp, reg(STKP), sizeof(long));
10769678Slinton 	    sp = savesp;
10779678Slinton 	    beginproc(p, 1);
10789678Slinton 	    stepto(return_addr());
10799678Slinton 	    popenv();
10809678Slinton 	}
10819678Slinton     }
10829678Slinton }
1083