xref: /csrg-svn/old/dbx/runtime.tahoe.c (revision 50684)
126329Ssam /*
238105Sbostic  * Copyright (c) 1985 The Regents of the University of California.
338105Sbostic  * All rights reserved.
438105Sbostic  *
542685Sbostic  * %sccs.include.redist.c%
626329Ssam  */
726329Ssam 
826329Ssam #ifndef lint
9*50684Smckusick static char sccsid[] = "@(#)runtime.tahoe.c	5.8 (Berkeley) 07/30/91";
1038105Sbostic #endif /* not lint */
1126329Ssam 
1226329Ssam /*
1326329Ssam  * Runtime organization dependent routines, mostly dealing with
1426329Ssam  * activation records.
1526329Ssam  */
1626329Ssam 
1726329Ssam #include "defs.h"
1826329Ssam #include "runtime.h"
1926329Ssam #include "process.h"
2026329Ssam #include "machine.h"
2126329Ssam #include "events.h"
2226329Ssam #include "mappings.h"
2326329Ssam #include "symbols.h"
2426329Ssam #include "tree.h"
2526329Ssam #include "eval.h"
2626329Ssam #include "operators.h"
2726329Ssam #include "object.h"
2826329Ssam 
2926329Ssam #ifndef public
3026329Ssam #include "machine.h"
3126329Ssam 
3226329Ssam typedef struct Frame {
3326329Ssam     Address save_pc;		/* program counter */
3426329Ssam     integer mask:16;		/* register save mask */
3526329Ssam     integer removed:16;		/* 4*number of arguments + 4 */
3626329Ssam     Address save_fp;		/* frame pointer */
3726329Ssam #define NSAVEREG 13
3826329Ssam     Word save_reg[NSAVEREG];	/* not necessarily there */
3926329Ssam } *Frame;
4026329Ssam #endif
4126329Ssam 
4226329Ssam private Frame curframe = nil;
4326329Ssam private struct Frame curframerec;
4426329Ssam private Boolean walkingstack = false;
4526329Ssam 
4626329Ssam #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp)
4726329Ssam 
4833333Sdonn #define inSignalHandler(addr) \
4926329Ssam     (((addr) < 0xc0000000) and ((addr) > 0xc0000000 - 0x400 * UPAGES))
5026329Ssam 
5126329Ssam typedef struct {
5226329Ssam     Node callnode;
5326329Ssam     Node cmdnode;
5426329Ssam     boolean isfunc;
5526329Ssam } CallEnv;
5626329Ssam 
5726329Ssam private CallEnv endproc;
5826329Ssam 
5926329Ssam /*
6026329Ssam  * Set a frame to the current activation record.
6126329Ssam  */
6226329Ssam 
getcurframe(frp)6326329Ssam private getcurframe(frp)
6426329Ssam Frame frp;
6526329Ssam {
6626329Ssam     register int i;
6726329Ssam     long x;
6826329Ssam 
6926329Ssam     checkref(frp);
7026329Ssam     frp->save_fp = reg(FRP);
7126329Ssam     dread(&x, frp->save_fp-4, 4);
7226329Ssam     frp->mask = x >> 16;
7326329Ssam     frp->removed = x & 0xffff;
7426329Ssam     frp->save_pc = reg(PROGCTR);
7526329Ssam     for (i = 0; i < NSAVEREG; i++) {
7626329Ssam 	frp->save_reg[i] = reg(i);
7726329Ssam     }
7826329Ssam }
7926329Ssam 
8026329Ssam /*
8126329Ssam  * Get the saved registers from one frame to another
8226329Ssam  * given mask specifying which registers were actually saved.
8326329Ssam  */
8426329Ssam 
8526329Ssam #define bis(b, n) ((b & (1 << (n))) != 0)
8626329Ssam 
getsaveregs(newfrp,frp,mask)8726329Ssam private getsaveregs (newfrp, frp, mask)
8826329Ssam Frame newfrp, frp;
8926329Ssam integer mask;
9026329Ssam {
9126329Ssam     integer i, j;
9226329Ssam 
9326329Ssam     j = 0;
9426329Ssam     for (i = 0; i < NSAVEREG; i++) {
9526329Ssam 	if (bis(mask, i)) {
9626329Ssam 	    newfrp->save_reg[i] = frp->save_reg[j];
9726329Ssam 	    ++j;
9826329Ssam 	}
9926329Ssam     }
10026329Ssam }
10126329Ssam 
10226329Ssam /*
10326329Ssam  * Return a pointer to the next activation record up the stack.
10426329Ssam  * Return nil if there is none.
10526329Ssam  * Writes over space pointed to by given argument.
10626329Ssam  */
10726329Ssam 
nextframe(frp)10826329Ssam private Frame nextframe(frp)
10926329Ssam Frame frp;
11026329Ssam {
11126329Ssam     Frame newfrp;
11226329Ssam     struct Frame frame;
11326329Ssam     long x;
11433333Sdonn     Address prev_frame, callpc;
11526329Ssam     static integer ntramp = 0;
11626329Ssam 
11726329Ssam     newfrp = frp;
11826329Ssam     prev_frame = frp->save_fp;
11926329Ssam 
12026329Ssam /*
12126329Ssam  *  The check for interrupt generated frames is taken from adb with only
12226329Ssam  *  partial understanding.  If you're in "sub" and on a sigxxx "sigsub"
12326329Ssam  *  gets control, then the stack does NOT look like <main, sub, sigsub>.
12426329Ssam  *
12526329Ssam  *  As best I can make out it looks like:
12626329Ssam  *
12726329Ssam  *     <main, (machine check exception block + sub), sysframe, sigsub>.
12826329Ssam  *
12926329Ssam  *  When the signal occurs an exception block and a frame for the routine
13026329Ssam  *  in which it occured are pushed on the user stack.  Then another frame
13126329Ssam  *  is pushed corresponding to a call from the kernel to sigsub.
13226329Ssam  *
13326329Ssam  *  The addr in sub at which the exception occured is not in sub.save_pc
13426329Ssam  *  but in the machine check exception block.  It is at the magic address
13526329Ssam  *  fp + 84.
13626329Ssam  *
13726329Ssam  *  The current approach ignores the sys_frame (what adb reports as sigtramp)
13826329Ssam  *  and takes the pc for sub from the exception block.  This allows the
13926329Ssam  *  "where" command to report <main, sub, sigsub>, which seems reasonable.
14026329Ssam  */
14126329Ssam 
14226329Ssam nextf:
14326329Ssam     dread(&frame, prev_frame-8, sizeof(struct Frame));
14426329Ssam     if (ntramp == 1) {
14526329Ssam 	dread(&callpc, prev_frame+44, sizeof(callpc));
14626329Ssam     } else {
14726329Ssam 	callpc = frame.save_pc;
14826329Ssam     }
14926329Ssam     if (frame.save_fp == nil or frame.save_pc == (Address) -1) {
15026329Ssam 	newfrp = nil;
15133333Sdonn     } else if (inSignalHandler(callpc)) {
15226329Ssam 	ntramp++;
15326329Ssam 	prev_frame = frame.save_fp;
15426329Ssam 	goto nextf;
15526329Ssam     } else {
15626329Ssam         ntramp = 0;
15726329Ssam 	getsaveregs(newfrp, &frame, frame.mask);
15826329Ssam 	dread(&x, frame.save_fp-4, sizeof (x));
15926329Ssam 	newfrp->mask = x >> 16;
16026329Ssam 	newfrp->removed = x & 0xffff;
16126329Ssam 	newfrp->save_fp = frame.save_fp;
16226329Ssam 	newfrp->save_pc = callpc;
16326329Ssam     }
16426329Ssam     return newfrp;
16526329Ssam }
16626329Ssam 
16726329Ssam /*
16826329Ssam  * Get the current frame information in the given Frame and store the
16926329Ssam  * associated function in the given value-result parameter.
17026329Ssam  */
17126329Ssam 
getcurfunc(frp,fp)17226329Ssam private getcurfunc (frp, fp)
17326329Ssam Frame frp;
17426329Ssam Symbol *fp;
17526329Ssam {
17626329Ssam     getcurframe(frp);
17726329Ssam     *fp = whatblock(frp->save_pc);
17826329Ssam }
17926329Ssam 
18026329Ssam /*
18126329Ssam  * Return the frame associated with the next function up the call stack, or
18226329Ssam  * nil if there is none.  The function is returned in a value-result parameter.
18326329Ssam  * For "inline" functions the statically outer function and same frame
18426329Ssam  * are returned.
18526329Ssam  */
18626329Ssam 
nextfunc(frp,fp)18726329Ssam public Frame nextfunc (frp, fp)
18826329Ssam Frame frp;
18926329Ssam Symbol *fp;
19026329Ssam {
19126329Ssam     Symbol t;
19226329Ssam     Frame nfrp;
19326329Ssam 
19426329Ssam     t = *fp;
19526329Ssam     checkref(t);
19626329Ssam     if (isinline(t)) {
19726329Ssam 	t = container(t);
19826329Ssam 	nfrp = frp;
19926329Ssam     } else {
20026329Ssam 	nfrp = nextframe(frp);
20126329Ssam 	if (nfrp == nil) {
20226329Ssam 	    t = nil;
20326329Ssam 	} else {
20426329Ssam 	    t = whatblock(nfrp->save_pc);
20526329Ssam 	}
20626329Ssam     }
20726329Ssam     *fp = t;
20826329Ssam     return nfrp;
20926329Ssam }
21026329Ssam 
21126329Ssam /*
21226329Ssam  * Return the frame associated with the given function.
21326329Ssam  * If the function is nil, return the most recently activated frame.
21426329Ssam  *
21526329Ssam  * Static allocation for the frame.
21626329Ssam  */
21726329Ssam 
findframe(f)21826329Ssam public Frame findframe(f)
21926329Ssam Symbol f;
22026329Ssam {
22126329Ssam     Frame frp;
22226329Ssam     static struct Frame frame;
22326329Ssam     Symbol p;
22426329Ssam     Boolean done;
22526329Ssam 
22626329Ssam     frp = &frame;
22726329Ssam     getcurframe(frp);
22826329Ssam     if (f != nil) {
22926329Ssam 	if (f == curfunc and curframe != nil) {
23026329Ssam 	    *frp = *curframe;
23126329Ssam 	} else {
23226329Ssam 	    done = false;
23326329Ssam 	    p = whatblock(frp->save_pc);
23426329Ssam 	    do {
23526329Ssam 		if (p == f) {
23626329Ssam 		    done = true;
23726329Ssam 		} else if (p == program) {
23826329Ssam 		    done = true;
23926329Ssam 		    frp = nil;
24026329Ssam 		} else {
24126329Ssam 		    frp = nextfunc(frp, &p);
24226329Ssam 		    if (frp == nil) {
24326329Ssam 			done = true;
24426329Ssam 		    }
24526329Ssam 		}
24626329Ssam 	    } while (not done);
24726329Ssam 	}
24826329Ssam     }
24926329Ssam     return frp;
25026329Ssam }
25126329Ssam 
25226329Ssam /*
25326329Ssam  * Set the registers according to the given frame pointer.
25426329Ssam  */
25526329Ssam 
getnewregs(addr)25626329Ssam public getnewregs (addr)
25726329Ssam Address addr;
25826329Ssam {
25926329Ssam     struct Frame frame;
26026329Ssam     integer i, j, mask;
26126329Ssam 
26226329Ssam     dread(&frame, addr-8, sizeof(frame));
26326329Ssam     setreg(FRP, frame.save_fp);
26426329Ssam     setreg(PROGCTR, frame.save_pc);
26526329Ssam     mask = frame.mask;
26626329Ssam     j = 0;
26726329Ssam     for (i = 0; i < NSAVEREG; i++) {
26826329Ssam 	if (bis(mask, i)) {
26926329Ssam 	    setreg(i, frame.save_reg[j]);
27026329Ssam 	    ++j;
27126329Ssam 	}
27226329Ssam     }
27326329Ssam     pc = frame.save_pc;
27426329Ssam     setcurfunc(whatblock(pc));
27526329Ssam }
27626329Ssam 
27726329Ssam /*
27826329Ssam  * Find the return address of the current procedure/function.
27926329Ssam  */
28026329Ssam 
return_addr()28126329Ssam public Address return_addr()
28226329Ssam {
28326329Ssam     Frame frp;
28426329Ssam     Address addr;
28526329Ssam     struct Frame frame;
28626329Ssam 
28726329Ssam     frp = &frame;
28826329Ssam     getcurframe(frp);
28926329Ssam     frp = nextframe(frp);
29026329Ssam     if (frp == nil) {
29126329Ssam 	addr = 0;
29226329Ssam     } else {
29326329Ssam 	addr = frp->save_pc;
29426329Ssam     }
29526329Ssam     return addr;
29626329Ssam }
29726329Ssam 
29826329Ssam /*
29926329Ssam  * Push the value associated with the current function.
30026329Ssam  */
30126329Ssam 
pushretval(len,isindirect)30226329Ssam public pushretval(len, isindirect)
30326329Ssam integer len;
30426329Ssam boolean isindirect;
30526329Ssam {
30626329Ssam     Word r0;
30726329Ssam 
30826329Ssam     r0 = reg(0);
30926329Ssam     if (isindirect) {
31026329Ssam 	rpush((Address) r0, len);
31126329Ssam     } else {
31226329Ssam 	switch (len) {
31326329Ssam 	    case sizeof(char):
31426329Ssam 		push(char, r0);
31526329Ssam 		break;
31626329Ssam 
31726329Ssam 	    case sizeof(short):
31826329Ssam 		push(short, r0);
31926329Ssam 		break;
32026329Ssam 
32126329Ssam 	    default:
32226329Ssam 		if (len == sizeof(Word)) {
32326329Ssam 		    push(Word, r0);
32426329Ssam 		} else if (len == 2*sizeof(Word)) {
32526329Ssam 		    push(Word, r0);
32626329Ssam 		    push(Word, reg(1));
32726329Ssam 		} else {
32826329Ssam 		    error("[internal error: bad size %d in pushretval]", len);
32926329Ssam 		}
33026329Ssam 		break;
33126329Ssam 	}
33226329Ssam     }
33326329Ssam }
33426329Ssam 
33526329Ssam /*
33626329Ssam  * Return the base address for locals in the given frame.
33726329Ssam  */
33826329Ssam 
locals_base(frp)33926329Ssam public Address locals_base(frp)
34026329Ssam Frame frp;
34126329Ssam {
34226329Ssam     return (frp == nil ? reg(FRP) : frp->save_fp);
34326329Ssam }
34426329Ssam 
34526329Ssam /*
34626329Ssam  * Return the base address for arguments in the given frame.
34726329Ssam  */
34826329Ssam 
args_base(frp)34926329Ssam public Address args_base(frp)
35026329Ssam Frame frp;
35126329Ssam {
35226329Ssam     return (frp == nil ? reg(FRP) : frp->save_fp);
35326329Ssam }
35426329Ssam 
35526329Ssam /*
35626329Ssam  * Return saved register n from the given frame.
35726329Ssam  */
35826329Ssam 
savereg(n,frp)35926329Ssam public Word savereg(n, frp)
36026329Ssam integer n;
36126329Ssam Frame frp;
36226329Ssam {
36326329Ssam     Word w;
36426329Ssam 
36526329Ssam     if (frp == nil) {
36626329Ssam 	w = reg(n);
36726329Ssam     } else {
36826329Ssam 	switch (n) {
36926329Ssam 
37026329Ssam 	    case FRP:
37126329Ssam 		w = frp->save_fp;
37226329Ssam 		break;
37326329Ssam 
37426329Ssam 	    case STKP:
37526329Ssam 		w = reg(STKP);
37626329Ssam 		break;
37726329Ssam 
37826329Ssam 	    case PROGCTR:
37926329Ssam 		w = frp->save_pc;
38026329Ssam 		break;
38126329Ssam 
38226329Ssam 	    default:
38326329Ssam 		assert(n >= 0 and n < NSAVEREG);
38426329Ssam 		w = frp->save_reg[n];
38526329Ssam 		break;
38626329Ssam 	}
38726329Ssam     }
38826329Ssam     return w;
38926329Ssam }
39026329Ssam 
39126329Ssam /*
39226329Ssam  * Return the nth argument to the current procedure.
39326329Ssam  */
39426329Ssam 
argn(n,frp)39526329Ssam public Word argn(n, frp)
39626329Ssam integer n;
39726329Ssam Frame frp;
39826329Ssam {
39933333Sdonn     Address argaddr;
40026329Ssam     Word w;
40126329Ssam 
40233333Sdonn     argaddr = args_base(frp) + (n * sizeof(Word));
40333333Sdonn     dread(&w, argaddr, sizeof(w));
40426329Ssam     return w;
40526329Ssam }
40626329Ssam 
40726329Ssam /*
40826329Ssam  * Print a list of currently active blocks starting with most recent.
40926329Ssam  */
41026329Ssam 
wherecmd()41126329Ssam public wherecmd()
41226329Ssam {
41326329Ssam     walkstack(false);
41426329Ssam }
41526329Ssam 
41626329Ssam /*
41726329Ssam  * Print the variables in the given frame or the current one if nil.
41826329Ssam  */
41926329Ssam 
dump(func)42026329Ssam public dump (func)
42126329Ssam Symbol func;
42226329Ssam {
42326329Ssam     Symbol f;
42426329Ssam     Frame frp;
42526329Ssam 
42626329Ssam     if (func == nil) {
42726329Ssam 	f = curfunc;
42826329Ssam 	if (curframe != nil) {
42926329Ssam 	    frp = curframe;
43026329Ssam 	} else {
43126329Ssam 	    frp = findframe(f);
43226329Ssam 	}
43326329Ssam     } else {
43426329Ssam 	f = func;
43526329Ssam 	frp = findframe(f);
43626329Ssam     }
43726329Ssam     showaggrs = true;
43826329Ssam     printcallinfo(f, frp);
43926329Ssam     dumpvars(f, frp);
44026329Ssam }
44126329Ssam 
44226329Ssam /*
44326329Ssam  * Dump all values.
44426329Ssam  */
44526329Ssam 
dumpall()44626329Ssam public dumpall ()
44726329Ssam {
44826329Ssam     walkstack(true);
44926329Ssam }
45026329Ssam 
45126329Ssam /*
45226329Ssam  * Walk the stack of active procedures printing information
45326329Ssam  * about each active procedure.
45426329Ssam  */
45526329Ssam 
walkstack(dumpvariables)45626329Ssam private walkstack(dumpvariables)
45726329Ssam Boolean dumpvariables;
45826329Ssam {
45926329Ssam     Frame frp;
46026329Ssam     boolean save;
46126329Ssam     Symbol f;
46226329Ssam     struct Frame frame;
46326329Ssam 
46426329Ssam     if (notstarted(process) or isfinished(process)) {
46526329Ssam 	error("program is not active");
46626329Ssam     } else {
46726329Ssam 	save = walkingstack;
46826329Ssam 	walkingstack = true;
46926329Ssam 	showaggrs = dumpvariables;
47026329Ssam 	frp = &frame;
47126329Ssam 	getcurfunc(frp, &f);
47226329Ssam 	for (;;) {
47326329Ssam 	    printcallinfo(f, frp);
47426329Ssam 	    if (dumpvariables) {
47526329Ssam 		dumpvars(f, frp);
47626329Ssam 		putchar('\n');
47726329Ssam 	    }
47826329Ssam 	    frp = nextfunc(frp, &f);
47926329Ssam 	    if (frp == nil or f == program) {
48026329Ssam 		break;
48126329Ssam 	    }
48226329Ssam 	}
48326329Ssam 	if (dumpvariables) {
48426329Ssam 	    printf("in \"%s\":\n", symname(program));
48526329Ssam 	    dumpvars(program, nil);
48626329Ssam 	    putchar('\n');
48726329Ssam 	}
48826329Ssam 	walkingstack = save;
48926329Ssam     }
49026329Ssam }
49126329Ssam 
49226329Ssam /*
49326329Ssam  * Print out the information about a call, i.e.,
49426329Ssam  * routine name, parameter values, and source location.
49526329Ssam  */
49626329Ssam 
printcallinfo(f,frp)49726329Ssam private printcallinfo (f, frp)
49826329Ssam Symbol f;
49926329Ssam Frame frp;
50026329Ssam {
50126329Ssam     Lineno line;
50226329Ssam     Address savepc;
50326329Ssam 
50426329Ssam     savepc = frp->save_pc;
50526329Ssam     if (frp->save_fp != reg(FRP)) {
50626329Ssam 	savepc -= 1;
50726329Ssam     }
50826329Ssam     printname(stdout, f);
50926329Ssam     if (not isinline(f)) {
51026329Ssam 	printparams(f, frp);
51126329Ssam     }
51226329Ssam     line = srcline(savepc);
51326329Ssam     if (line != 0) {
51426329Ssam 	printf(", line %d", line);
51526329Ssam 	printf(" in \"%s\"\n", srcfilename(savepc));
51626329Ssam     } else {
51726329Ssam 	printf(" at 0x%x\n", savepc);
51826329Ssam     }
51926329Ssam }
52026329Ssam 
52126329Ssam /*
52226329Ssam  * Set the current function to the given symbol.
52326329Ssam  * We must adjust "curframe" so that subsequent operations are
52426329Ssam  * not confused; for simplicity we simply clear it.
52526329Ssam  */
52626329Ssam 
setcurfunc(f)52726329Ssam public setcurfunc (f)
52826329Ssam Symbol f;
52926329Ssam {
53026329Ssam     curfunc = f;
53126329Ssam     curframe = nil;
53226329Ssam }
53326329Ssam 
53426329Ssam /*
53526329Ssam  * Return the frame for the current function.
53626329Ssam  * The space for the frame is allocated statically.
53726329Ssam  */
53826329Ssam 
curfuncframe()53926329Ssam public Frame curfuncframe ()
54026329Ssam {
54126329Ssam     static struct Frame frame;
54226329Ssam     Frame frp;
54326329Ssam 
54426329Ssam     if (curframe == nil) {
54526329Ssam 	frp = findframe(curfunc);
54626329Ssam 	curframe = &curframerec;
54726329Ssam 	*curframe = *frp;
54826329Ssam     } else {
54926329Ssam 	frp = &frame;
55026329Ssam 	*frp = *curframe;
55126329Ssam     }
55226329Ssam     return frp;
55326329Ssam }
55426329Ssam 
55526329Ssam /*
55626329Ssam  * Set curfunc to be N up/down the stack from its current value.
55726329Ssam  */
55826329Ssam 
up(n)55926329Ssam public up (n)
56026329Ssam integer n;
56126329Ssam {
56226329Ssam     integer i;
56326329Ssam     Symbol f;
56426329Ssam     Frame frp;
56526329Ssam     boolean done;
56626329Ssam 
56726329Ssam     if (not isactive(program)) {
56826329Ssam 	error("program is not active");
56926329Ssam     } else if (curfunc == nil) {
57026329Ssam 	error("no current function");
57126329Ssam     } else {
57226329Ssam 	i = 0;
57326329Ssam 	f = curfunc;
57426329Ssam 	frp = curfuncframe();
57526329Ssam 	done = false;
57626329Ssam 	do {
57726329Ssam 	    if (frp == nil) {
57826329Ssam 		done = true;
57926329Ssam 		error("not that many levels");
58026329Ssam 	    } else if (i >= n) {
58126329Ssam 		done = true;
58226329Ssam 		curfunc = f;
58326329Ssam 		curframe = &curframerec;
58426329Ssam 		*curframe = *frp;
58526329Ssam 		showaggrs = false;
58626329Ssam 		printcallinfo(curfunc, curframe);
58726329Ssam 	    } else if (f == program) {
58826329Ssam 		done = true;
58926329Ssam 		error("not that many levels");
59026329Ssam 	    } else {
59126329Ssam 		frp = nextfunc(frp, &f);
59226329Ssam 	    }
59326329Ssam 	    ++i;
59426329Ssam 	} while (not done);
59526329Ssam     }
59626329Ssam }
59726329Ssam 
down(n)59826329Ssam public down (n)
59926329Ssam integer n;
60026329Ssam {
60126329Ssam     integer i, depth;
60226329Ssam     Frame frp, curfrp;
60326329Ssam     Symbol f;
60426329Ssam     struct Frame frame;
60526329Ssam 
60626329Ssam     if (not isactive(program)) {
60726329Ssam 	error("program is not active");
60826329Ssam     } else if (curfunc == nil) {
60926329Ssam 	error("no current function");
61026329Ssam     } else {
61126329Ssam 	depth = 0;
61226329Ssam 	frp = &frame;
61326329Ssam 	getcurfunc(frp, &f);
61426329Ssam 	if (curframe == nil) {
61526329Ssam 	    curfrp = findframe(curfunc);
61626329Ssam 	    curframe = &curframerec;
61726329Ssam 	    *curframe = *curfrp;
61826329Ssam 	}
61926329Ssam 	while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) {
62026329Ssam 	    frp = nextfunc(frp, &f);
62126329Ssam 	    ++depth;
62226329Ssam 	}
62326329Ssam 	if (f == nil or n > depth) {
62426329Ssam 	    error("not that many levels");
62526329Ssam 	} else {
62626329Ssam 	    depth -= n;
62726329Ssam 	    frp = &frame;
62826329Ssam 	    getcurfunc(frp, &f);
62926329Ssam 	    for (i = 0; i < depth; i++) {
63026329Ssam 		frp = nextfunc(frp, &f);
63126329Ssam 		assert(frp != nil);
63226329Ssam 	    }
63326329Ssam 	    curfunc = f;
63426329Ssam 	    *curframe = *frp;
63526329Ssam 	    showaggrs = false;
63626329Ssam 	    printcallinfo(curfunc, curframe);
63726329Ssam 	}
63826329Ssam     }
63926329Ssam }
64026329Ssam 
64126329Ssam /*
64226329Ssam  * Find the entry point of a procedure or function.
64326329Ssam  */
64426329Ssam 
findbeginning(f)64526329Ssam public findbeginning (f)
64626329Ssam Symbol f;
64726329Ssam {
64826329Ssam     if (isinternal(f)) {
64926329Ssam 	f->symvalue.funcv.beginaddr += 15;
65026329Ssam     } else {
65133333Sdonn 	f->symvalue.funcv.beginaddr += FUNCOFFSET;
65226329Ssam     }
65326329Ssam }
65426329Ssam 
65526329Ssam /*
65626329Ssam  * Return the address corresponding to the first line in a function.
65726329Ssam  */
65826329Ssam 
firstline(f)65926329Ssam public Address firstline(f)
66026329Ssam Symbol f;
66126329Ssam {
66226329Ssam     Address addr;
66326329Ssam 
66426329Ssam     addr = codeloc(f);
66526329Ssam     while (linelookup(addr) == 0 and addr < objsize) {
66626329Ssam 	++addr;
66726329Ssam     }
66826329Ssam     if (addr == objsize) {
66926329Ssam 	addr = -1;
67026329Ssam     }
67126329Ssam     return addr;
67226329Ssam }
67326329Ssam 
67426329Ssam /*
67526329Ssam  * Catcher drops strike three ...
67626329Ssam  */
67726329Ssam 
runtofirst()67826329Ssam public runtofirst()
67926329Ssam {
68033333Sdonn     Address addr, endaddr;
68126329Ssam 
68226329Ssam     addr = pc;
68333333Sdonn     endaddr = objsize + CODESTART;
68433333Sdonn     while (linelookup(addr) == 0 and addr < endaddr) {
68526329Ssam 	++addr;
68626329Ssam     }
68733333Sdonn     if (addr < endaddr) {
68826329Ssam 	stepto(addr);
68926329Ssam     }
69026329Ssam }
69126329Ssam 
69226329Ssam /*
69326329Ssam  * Return the address corresponding to the end of the program.
69426329Ssam  *
69526329Ssam  * We look for the entry to "exit".
69626329Ssam  */
69726329Ssam 
lastaddr()69826329Ssam public Address lastaddr()
69926329Ssam {
70026329Ssam     Symbol s;
70126329Ssam 
70226329Ssam     s = lookup(identname("exit", true));
70326329Ssam     if (s == nil) {
70426329Ssam 	panic("can't find exit");
70526329Ssam     }
70626329Ssam     return codeloc(s);
70726329Ssam }
70826329Ssam 
70926329Ssam /*
71026329Ssam  * Decide if the given function is currently active.
71126329Ssam  *
71226329Ssam  * We avoid calls to "findframe" during a stack trace for efficiency.
71326329Ssam  * Presumably information evaluated while walking the stack is active.
71426329Ssam  */
71526329Ssam 
isactive(f)71633333Sdonn public Boolean isactive (f)
71726329Ssam Symbol f;
71826329Ssam {
71926329Ssam     Boolean b;
72026329Ssam 
72126329Ssam     if (isfinished(process)) {
72226329Ssam 	b = false;
72326329Ssam     } else {
72433333Sdonn 	if (walkingstack or f == program or f == nil or
72526329Ssam 	  (ismodule(f) and isactive(container(f)))) {
72626329Ssam 	    b = true;
72726329Ssam 	} else {
72826329Ssam 	    b = (Boolean) (findframe(f) != nil);
72926329Ssam 	}
73026329Ssam     }
73126329Ssam     return b;
73226329Ssam }
73326329Ssam 
73426329Ssam /*
73526329Ssam  * Evaluate a call to a procedure.
73626329Ssam  */
73726329Ssam 
callproc(exprnode,isfunc)73826329Ssam public callproc(exprnode, isfunc)
73926329Ssam Node exprnode;
74026329Ssam boolean isfunc;
74126329Ssam {
74226329Ssam     Node procnode, arglist;
74326329Ssam     Symbol proc;
74426329Ssam     integer argc;
74526329Ssam 
74626329Ssam     procnode = exprnode->value.arg[0];
74726329Ssam     arglist = exprnode->value.arg[1];
74826329Ssam     if (procnode->op != O_SYM) {
74926329Ssam 	beginerrmsg();
75026329Ssam 	fprintf(stderr, "can't call \"");
75126329Ssam 	prtree(stderr, procnode);
75226329Ssam 	fprintf(stderr, "\"");
75326329Ssam 	enderrmsg();
75426329Ssam     }
75526329Ssam     assert(procnode->op == O_SYM);
75626329Ssam     proc = procnode->value.sym;
75726329Ssam     if (not isblock(proc)) {
75826329Ssam 	error("\"%s\" is not a procedure or function", symname(proc));
75926329Ssam     }
76026329Ssam     endproc.isfunc = isfunc;
76126329Ssam     endproc.callnode = exprnode;
76226329Ssam     endproc.cmdnode = topnode;
76326329Ssam     pushenv();
76426329Ssam     pc = codeloc(proc);
76526329Ssam     argc = pushargs(proc, arglist);
76633333Sdonn     setreg(FRP, 1);	/* have to ensure it's non-zero for return_addr() */
76726329Ssam     beginproc(proc, argc);
76826329Ssam     event_once(
76926329Ssam 	build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)),
77026329Ssam 	buildcmdlist(build(O_PROCRTN, proc))
77126329Ssam     );
77226329Ssam     isstopped = false;
77326329Ssam     if (not bpact()) {
77426329Ssam 	isstopped = true;
77526329Ssam 	cont(0);
77626329Ssam     }
77726329Ssam     /*
77826329Ssam      * bpact() won't return true, it will call printstatus() and go back
77926329Ssam      * to command input if a breakpoint is found.
78026329Ssam      */
78126329Ssam     /* NOTREACHED */
78226329Ssam }
78326329Ssam 
78426329Ssam /*
78526329Ssam  * Push the arguments on the process' stack.  We do this by first
78626329Ssam  * evaluating them on the "eval" stack, then copying into the process'
78726329Ssam  * space.
78826329Ssam  */
78926329Ssam 
pushargs(proc,arglist)79026329Ssam private integer pushargs(proc, arglist)
79126329Ssam Symbol proc;
79226329Ssam Node arglist;
79326329Ssam {
79426329Ssam     Stack *savesp;
79526329Ssam     int argc, args_size;
79626329Ssam 
79726329Ssam     savesp = sp;
798*50684Smckusick     if (varIsSet("$unsafecall")) {
799*50684Smckusick 	argc = unsafe_evalargs(proc, arglist);
800*50684Smckusick     } else {
801*50684Smckusick 	argc = evalargs(proc, arglist);
802*50684Smckusick     }
80326329Ssam     argc = evalargs(proc, arglist);
80426329Ssam     args_size = sp - savesp;
80526329Ssam     setreg(STKP, reg(STKP) - args_size);
80626329Ssam     dwrite(savesp, reg(STKP), args_size);
80726329Ssam     sp = savesp;
80826329Ssam     return argc;
80926329Ssam }
81026329Ssam 
81126329Ssam /*
81226329Ssam  * Check to see if an expression is correct for a given parameter.
81326329Ssam  * If the given parameter is false, don't worry about type inconsistencies.
81426329Ssam  *
81526329Ssam  * Return whether or not it is ok.
81626329Ssam  */
81726329Ssam 
chkparam(actual,formal,chk)81826329Ssam private boolean chkparam (actual, formal, chk)
81926329Ssam Node actual;
82026329Ssam Symbol formal;
82126329Ssam boolean chk;
82226329Ssam {
82326329Ssam     boolean b;
82426329Ssam 
82526329Ssam     b = true;
82626329Ssam     if (chk) {
82726329Ssam 	if (formal == nil) {
82826329Ssam 	    beginerrmsg();
82926329Ssam 	    fprintf(stderr, "too many parameters");
83026329Ssam 	    b = false;
83126329Ssam 	} else if (not compatible(formal->type, actual->nodetype)) {
83226329Ssam 	    beginerrmsg();
83326329Ssam 	    fprintf(stderr, "type mismatch for %s", symname(formal));
83426329Ssam 	    b = false;
83526329Ssam 	}
83626329Ssam     }
83726329Ssam     if (b and formal != nil and
83826329Ssam 	isvarparam(formal) and not isopenarray(formal->type) and
83926329Ssam 	not (
84026329Ssam 	    actual->op == O_RVAL or actual->nodetype == t_addr or
84126329Ssam 	    (
84226329Ssam 		actual->op == O_TYPERENAME and
84326329Ssam 		(
84426329Ssam 		    actual->value.arg[0]->op == O_RVAL or
84526329Ssam 		    actual->value.arg[0]->nodetype == t_addr
84626329Ssam 		)
84726329Ssam 	    )
84826329Ssam 	)
84926329Ssam     ) {
85026329Ssam 	beginerrmsg();
85126329Ssam 	fprintf(stderr, "expected variable, found \"");
85226329Ssam 	prtree(stderr, actual);
85326329Ssam 	fprintf(stderr, "\"");
85426329Ssam 	b = false;
85526329Ssam     }
85626329Ssam     return b;
85726329Ssam }
85826329Ssam 
85926329Ssam /*
86026329Ssam  * Pass an expression to a particular parameter.
86126329Ssam  *
86226329Ssam  * Normally we pass either the address or value, but in some cases
86326329Ssam  * (such as C strings) we want to copy the value onto the stack and
86426329Ssam  * pass its address.
86526329Ssam  *
86626329Ssam  * Another special case raised by strings is the possibility that
86726329Ssam  * the actual parameter will be larger than the formal, even with
86826329Ssam  * appropriate type-checking.  This occurs because we assume during
86926329Ssam  * evaluation that strings are null-terminated, whereas some languages,
87026329Ssam  * notably Pascal, do not work under that assumption.
87126329Ssam  */
87226329Ssam 
passparam(actual,formal)87326329Ssam private passparam (actual, formal)
87426329Ssam Node actual;
87526329Ssam Symbol formal;
87626329Ssam {
87726329Ssam     boolean b;
87826329Ssam     Address addr;
87926329Ssam     Stack *savesp;
88026329Ssam     integer actsize, formsize;
88126329Ssam 
88226329Ssam     if (formal != nil and isvarparam(formal) and
88326329Ssam 	(not isopenarray(formal->type))
88426329Ssam     ) {
88526329Ssam 	addr = lval(actual->value.arg[0]);
88626329Ssam 	push(Address, addr);
88726329Ssam     } else if (passaddr(formal, actual->nodetype)) {
88826329Ssam 	savesp = sp;
88926329Ssam 	eval(actual);
89026329Ssam 	actsize = sp - savesp;
89126329Ssam 	setreg(STKP, reg(STKP) - roundup(actsize, sizeof (Word)));
89226329Ssam 	dwrite(savesp, reg(STKP), actsize);
89326329Ssam 	sp = savesp;
89426329Ssam 	push(Address, reg(STKP));
89526329Ssam 	if (formal != nil and isopenarray(formal->type)) {
89626329Ssam 	    push(integer, actsize div size(formal->type->type));
89726329Ssam 	}
89826329Ssam     } else if (formal != nil) {
89926329Ssam 	formsize = size(formal);
90026329Ssam 	savesp = sp;
90126329Ssam 	eval(actual);
90226329Ssam 	actsize = sp - savesp;
90326329Ssam 	if (actsize > formsize) {
90426329Ssam 	    sp -= (actsize - formsize);
90526329Ssam 	}
90626329Ssam     } else {
90726329Ssam 	eval(actual);
90826329Ssam     }
90926329Ssam }
91026329Ssam 
91126329Ssam /*
91226329Ssam  * Evaluate an argument list left-to-right.
91326329Ssam  */
91426329Ssam 
evalargs(proc,arglist)91526329Ssam private integer evalargs(proc, arglist)
91626329Ssam Symbol proc;
91726329Ssam Node arglist;
91826329Ssam {
91926329Ssam     Node p, actual;
92026329Ssam     Symbol formal;
92126329Ssam     Stack *savesp;
92226329Ssam     integer count;
92326329Ssam     boolean chk;
92426329Ssam 
92526329Ssam     savesp = sp;
92626329Ssam     count = 0;
92726329Ssam     formal = proc->chain;
92826329Ssam     chk = (boolean) (not nosource(proc));
92926329Ssam     for (p = arglist; p != nil; p = p->value.arg[1]) {
93026329Ssam 	assert(p->op == O_COMMA);
93126329Ssam 	actual = p->value.arg[0];
93226329Ssam 	if (not chkparam(actual, formal, chk)) {
93326329Ssam 	    fprintf(stderr, " in call to %s", symname(proc));
93426329Ssam 	    sp = savesp;
93526329Ssam 	    enderrmsg();
93626329Ssam 	}
93726329Ssam 	passparam(actual, formal);
93826329Ssam 	if (formal != nil) {
93926329Ssam 	    formal = formal->chain;
94026329Ssam 	}
94126329Ssam 	++count;
94226329Ssam     }
94326329Ssam     if (chk) {
94426329Ssam 	if (formal != nil) {
94526329Ssam 	    sp = savesp;
94626329Ssam 	    error("not enough parameters to %s", symname(proc));
94726329Ssam 	}
94826329Ssam     }
94926329Ssam     return count;
95026329Ssam }
95126329Ssam 
95233333Sdonn /*
95333333Sdonn  * Evaluate an argument list without any type checking.
95433333Sdonn  * This is only useful for procedures with a varying number of
95533333Sdonn  * arguments that are compiled -g.
95633333Sdonn  */
95733333Sdonn 
unsafe_evalargs(proc,arglist)95833333Sdonn private integer unsafe_evalargs (proc, arglist)
95933333Sdonn Symbol proc;
96033333Sdonn Node arglist;
96133333Sdonn {
96233333Sdonn     Node p;
96333333Sdonn     integer count;
96433333Sdonn 
96533333Sdonn     count = 0;
96633333Sdonn     for (p = arglist; p != nil; p = p->value.arg[1]) {
96733333Sdonn 	assert(p->op == O_COMMA);
96833333Sdonn 	eval(p->value.arg[0]);
96933333Sdonn 	++count;
97033333Sdonn     }
97133333Sdonn     return count;
97233333Sdonn }
97333333Sdonn 
procreturn(f)97426329Ssam public procreturn(f)
97526329Ssam Symbol f;
97626329Ssam {
97726329Ssam     integer retvalsize;
97826329Ssam     Node tmp;
97926329Ssam     char *copy;
98026329Ssam 
98126329Ssam     flushoutput();
98226329Ssam     popenv();
98326329Ssam     if (endproc.isfunc) {
98426329Ssam 	retvalsize = size(f->type);
98526329Ssam 	if (retvalsize > sizeof(long)) {
98626329Ssam 	    pushretval(retvalsize, true);
98726329Ssam 	    copy = newarr(char, retvalsize);
98826329Ssam 	    popn(retvalsize, copy);
98926329Ssam 	    tmp = build(O_SCON, copy);
99026329Ssam 	} else {
99126329Ssam 	    tmp = build(O_LCON, (long) (reg(0)));
99226329Ssam 	}
99326329Ssam 	tmp->nodetype = f->type;
99426329Ssam 	tfree(endproc.callnode);
99526329Ssam 	*(endproc.callnode) = *(tmp);
99626329Ssam 	dispose(tmp);
99726329Ssam 	eval(endproc.cmdnode);
99826329Ssam     } else {
99926329Ssam 	putchar('\n');
100026329Ssam 	printname(stdout, f);
100133333Sdonn 	printf(" returns successfully\n");
100226329Ssam     }
100326329Ssam     erecover();
100426329Ssam }
100526329Ssam 
100626329Ssam /*
100726329Ssam  * Push the current environment.
100826329Ssam  */
100926329Ssam 
pushenv()101026329Ssam private pushenv()
101126329Ssam {
101226329Ssam     push(Address, pc);
101326329Ssam     push(Lineno, curline);
101426329Ssam     push(String, cursource);
101526329Ssam     push(Boolean, isstopped);
101626329Ssam     push(Symbol, curfunc);
101726329Ssam     push(Frame, curframe);
101826329Ssam     push(struct Frame, curframerec);
101926329Ssam     push(CallEnv, endproc);
102026329Ssam     push(Word, reg(PROGCTR));
102126329Ssam     push(Word, reg(STKP));
102250683Smckusick     push(Word, reg(FRP));
102326329Ssam }
102426329Ssam 
102526329Ssam /*
102626329Ssam  * Pop back to the real world.
102726329Ssam  */
102826329Ssam 
popenv()102926329Ssam public popenv()
103026329Ssam {
103126329Ssam     String filename;
103226329Ssam 
103350683Smckusick     setreg(FRP, pop(Word));
103426329Ssam     setreg(STKP, pop(Word));
103526329Ssam     setreg(PROGCTR, pop(Word));
103626329Ssam     endproc = pop(CallEnv);
103726329Ssam     curframerec = pop(struct Frame);
103826329Ssam     curframe = pop(Frame);
103926329Ssam     curfunc = pop(Symbol);
104026329Ssam     isstopped = pop(Boolean);
104126329Ssam     filename = pop(String);
104226329Ssam     curline = pop(Lineno);
104326329Ssam     pc = pop(Address);
104426329Ssam     setsource(filename);
104526329Ssam }
104626329Ssam 
104726329Ssam /*
104826329Ssam  * Flush the debuggee's standard output.
104926329Ssam  *
105026329Ssam  * This is VERY dependent on the use of stdio.
105126329Ssam  */
105226329Ssam 
flushoutput()105326329Ssam public flushoutput()
105426329Ssam {
105526329Ssam     Symbol p, iob;
105626329Ssam     Stack *savesp;
105726329Ssam 
105826329Ssam     p = lookup(identname("fflush", true));
105926329Ssam     while (p != nil and not isblock(p)) {
106026329Ssam 	p = p->next_sym;
106126329Ssam     }
106226329Ssam     if (p != nil) {
106346146Storek 	iob = lookup(identname("__sF", true));
106426329Ssam 	if (iob != nil) {
106526329Ssam 	    pushenv();
106626329Ssam 	    pc = codeloc(p);
106726329Ssam 	    savesp = sp;
106846146Storek 	    push(long, address(iob, nil) + sizeof(*stdout));
106926329Ssam 	    setreg(STKP, reg(STKP) - sizeof(long));
107026329Ssam 	    dwrite(savesp, reg(STKP), sizeof(long));
107126329Ssam 	    sp = savesp;
107226329Ssam 	    beginproc(p, 1);
107326329Ssam 	    stepto(return_addr());
107426329Ssam 	    popenv();
107526329Ssam 	}
107626329Ssam     }
107726329Ssam }
1078