xref: /csrg-svn/old/dbx/runtime.tahoe.c (revision 42685)
126329Ssam /*
238105Sbostic  * Copyright (c) 1985 The Regents of the University of California.
338105Sbostic  * All rights reserved.
438105Sbostic  *
5*42685Sbostic  * %sccs.include.redist.c%
626329Ssam  */
726329Ssam 
826329Ssam #ifndef lint
9*42685Sbostic static char sccsid[] = "@(#)runtime.tahoe.c	5.5 (Berkeley) 06/01/90";
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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;
79826329Ssam     argc = evalargs(proc, arglist);
79926329Ssam     args_size = sp - savesp;
80026329Ssam     setreg(STKP, reg(STKP) - args_size);
80126329Ssam     dwrite(savesp, reg(STKP), args_size);
80226329Ssam     sp = savesp;
80326329Ssam     return argc;
80426329Ssam }
80526329Ssam 
80626329Ssam /*
80726329Ssam  * Check to see if an expression is correct for a given parameter.
80826329Ssam  * If the given parameter is false, don't worry about type inconsistencies.
80926329Ssam  *
81026329Ssam  * Return whether or not it is ok.
81126329Ssam  */
81226329Ssam 
81326329Ssam private boolean chkparam (actual, formal, chk)
81426329Ssam Node actual;
81526329Ssam Symbol formal;
81626329Ssam boolean chk;
81726329Ssam {
81826329Ssam     boolean b;
81926329Ssam 
82026329Ssam     b = true;
82126329Ssam     if (chk) {
82226329Ssam 	if (formal == nil) {
82326329Ssam 	    beginerrmsg();
82426329Ssam 	    fprintf(stderr, "too many parameters");
82526329Ssam 	    b = false;
82626329Ssam 	} else if (not compatible(formal->type, actual->nodetype)) {
82726329Ssam 	    beginerrmsg();
82826329Ssam 	    fprintf(stderr, "type mismatch for %s", symname(formal));
82926329Ssam 	    b = false;
83026329Ssam 	}
83126329Ssam     }
83226329Ssam     if (b and formal != nil and
83326329Ssam 	isvarparam(formal) and not isopenarray(formal->type) and
83426329Ssam 	not (
83526329Ssam 	    actual->op == O_RVAL or actual->nodetype == t_addr or
83626329Ssam 	    (
83726329Ssam 		actual->op == O_TYPERENAME and
83826329Ssam 		(
83926329Ssam 		    actual->value.arg[0]->op == O_RVAL or
84026329Ssam 		    actual->value.arg[0]->nodetype == t_addr
84126329Ssam 		)
84226329Ssam 	    )
84326329Ssam 	)
84426329Ssam     ) {
84526329Ssam 	beginerrmsg();
84626329Ssam 	fprintf(stderr, "expected variable, found \"");
84726329Ssam 	prtree(stderr, actual);
84826329Ssam 	fprintf(stderr, "\"");
84926329Ssam 	b = false;
85026329Ssam     }
85126329Ssam     return b;
85226329Ssam }
85326329Ssam 
85426329Ssam /*
85526329Ssam  * Pass an expression to a particular parameter.
85626329Ssam  *
85726329Ssam  * Normally we pass either the address or value, but in some cases
85826329Ssam  * (such as C strings) we want to copy the value onto the stack and
85926329Ssam  * pass its address.
86026329Ssam  *
86126329Ssam  * Another special case raised by strings is the possibility that
86226329Ssam  * the actual parameter will be larger than the formal, even with
86326329Ssam  * appropriate type-checking.  This occurs because we assume during
86426329Ssam  * evaluation that strings are null-terminated, whereas some languages,
86526329Ssam  * notably Pascal, do not work under that assumption.
86626329Ssam  */
86726329Ssam 
86826329Ssam private passparam (actual, formal)
86926329Ssam Node actual;
87026329Ssam Symbol formal;
87126329Ssam {
87226329Ssam     boolean b;
87326329Ssam     Address addr;
87426329Ssam     Stack *savesp;
87526329Ssam     integer actsize, formsize;
87626329Ssam 
87726329Ssam     if (formal != nil and isvarparam(formal) and
87826329Ssam 	(not isopenarray(formal->type))
87926329Ssam     ) {
88026329Ssam 	addr = lval(actual->value.arg[0]);
88126329Ssam 	push(Address, addr);
88226329Ssam     } else if (passaddr(formal, actual->nodetype)) {
88326329Ssam 	savesp = sp;
88426329Ssam 	eval(actual);
88526329Ssam 	actsize = sp - savesp;
88626329Ssam 	setreg(STKP, reg(STKP) - roundup(actsize, sizeof (Word)));
88726329Ssam 	dwrite(savesp, reg(STKP), actsize);
88826329Ssam 	sp = savesp;
88926329Ssam 	push(Address, reg(STKP));
89026329Ssam 	if (formal != nil and isopenarray(formal->type)) {
89126329Ssam 	    push(integer, actsize div size(formal->type->type));
89226329Ssam 	}
89326329Ssam     } else if (formal != nil) {
89426329Ssam 	formsize = size(formal);
89526329Ssam 	savesp = sp;
89626329Ssam 	eval(actual);
89726329Ssam 	actsize = sp - savesp;
89826329Ssam 	if (actsize > formsize) {
89926329Ssam 	    sp -= (actsize - formsize);
90026329Ssam 	}
90126329Ssam     } else {
90226329Ssam 	eval(actual);
90326329Ssam     }
90426329Ssam }
90526329Ssam 
90626329Ssam /*
90726329Ssam  * Evaluate an argument list left-to-right.
90826329Ssam  */
90926329Ssam 
91026329Ssam private integer evalargs(proc, arglist)
91126329Ssam Symbol proc;
91226329Ssam Node arglist;
91326329Ssam {
91426329Ssam     Node p, actual;
91526329Ssam     Symbol formal;
91626329Ssam     Stack *savesp;
91726329Ssam     integer count;
91826329Ssam     boolean chk;
91926329Ssam 
92026329Ssam     savesp = sp;
92126329Ssam     count = 0;
92226329Ssam     formal = proc->chain;
92326329Ssam     chk = (boolean) (not nosource(proc));
92426329Ssam     for (p = arglist; p != nil; p = p->value.arg[1]) {
92526329Ssam 	assert(p->op == O_COMMA);
92626329Ssam 	actual = p->value.arg[0];
92726329Ssam 	if (not chkparam(actual, formal, chk)) {
92826329Ssam 	    fprintf(stderr, " in call to %s", symname(proc));
92926329Ssam 	    sp = savesp;
93026329Ssam 	    enderrmsg();
93126329Ssam 	}
93226329Ssam 	passparam(actual, formal);
93326329Ssam 	if (formal != nil) {
93426329Ssam 	    formal = formal->chain;
93526329Ssam 	}
93626329Ssam 	++count;
93726329Ssam     }
93826329Ssam     if (chk) {
93926329Ssam 	if (formal != nil) {
94026329Ssam 	    sp = savesp;
94126329Ssam 	    error("not enough parameters to %s", symname(proc));
94226329Ssam 	}
94326329Ssam     }
94426329Ssam     return count;
94526329Ssam }
94626329Ssam 
94733333Sdonn /*
94833333Sdonn  * Evaluate an argument list without any type checking.
94933333Sdonn  * This is only useful for procedures with a varying number of
95033333Sdonn  * arguments that are compiled -g.
95133333Sdonn  */
95233333Sdonn 
95333333Sdonn private integer unsafe_evalargs (proc, arglist)
95433333Sdonn Symbol proc;
95533333Sdonn Node arglist;
95633333Sdonn {
95733333Sdonn     Node p;
95833333Sdonn     integer count;
95933333Sdonn 
96033333Sdonn     count = 0;
96133333Sdonn     for (p = arglist; p != nil; p = p->value.arg[1]) {
96233333Sdonn 	assert(p->op == O_COMMA);
96333333Sdonn 	eval(p->value.arg[0]);
96433333Sdonn 	++count;
96533333Sdonn     }
96633333Sdonn     return count;
96733333Sdonn }
96833333Sdonn 
96926329Ssam public procreturn(f)
97026329Ssam Symbol f;
97126329Ssam {
97226329Ssam     integer retvalsize;
97326329Ssam     Node tmp;
97426329Ssam     char *copy;
97526329Ssam 
97626329Ssam     flushoutput();
97726329Ssam     popenv();
97826329Ssam     if (endproc.isfunc) {
97926329Ssam 	retvalsize = size(f->type);
98026329Ssam 	if (retvalsize > sizeof(long)) {
98126329Ssam 	    pushretval(retvalsize, true);
98226329Ssam 	    copy = newarr(char, retvalsize);
98326329Ssam 	    popn(retvalsize, copy);
98426329Ssam 	    tmp = build(O_SCON, copy);
98526329Ssam 	} else {
98626329Ssam 	    tmp = build(O_LCON, (long) (reg(0)));
98726329Ssam 	}
98826329Ssam 	tmp->nodetype = f->type;
98926329Ssam 	tfree(endproc.callnode);
99026329Ssam 	*(endproc.callnode) = *(tmp);
99126329Ssam 	dispose(tmp);
99226329Ssam 	eval(endproc.cmdnode);
99326329Ssam     } else {
99426329Ssam 	putchar('\n');
99526329Ssam 	printname(stdout, f);
99633333Sdonn 	printf(" returns successfully\n");
99726329Ssam     }
99826329Ssam     erecover();
99926329Ssam }
100026329Ssam 
100126329Ssam /*
100226329Ssam  * Push the current environment.
100326329Ssam  */
100426329Ssam 
100526329Ssam private pushenv()
100626329Ssam {
100726329Ssam     push(Address, pc);
100826329Ssam     push(Lineno, curline);
100926329Ssam     push(String, cursource);
101026329Ssam     push(Boolean, isstopped);
101126329Ssam     push(Symbol, curfunc);
101226329Ssam     push(Frame, curframe);
101326329Ssam     push(struct Frame, curframerec);
101426329Ssam     push(CallEnv, endproc);
101526329Ssam     push(Word, reg(PROGCTR));
101626329Ssam     push(Word, reg(STKP));
101726329Ssam }
101826329Ssam 
101926329Ssam /*
102026329Ssam  * Pop back to the real world.
102126329Ssam  */
102226329Ssam 
102326329Ssam public popenv()
102426329Ssam {
102526329Ssam     String filename;
102626329Ssam 
102726329Ssam     setreg(STKP, pop(Word));
102826329Ssam     setreg(PROGCTR, pop(Word));
102926329Ssam     endproc = pop(CallEnv);
103026329Ssam     curframerec = pop(struct Frame);
103126329Ssam     curframe = pop(Frame);
103226329Ssam     curfunc = pop(Symbol);
103326329Ssam     isstopped = pop(Boolean);
103426329Ssam     filename = pop(String);
103526329Ssam     curline = pop(Lineno);
103626329Ssam     pc = pop(Address);
103726329Ssam     setsource(filename);
103826329Ssam }
103926329Ssam 
104026329Ssam /*
104126329Ssam  * Flush the debuggee's standard output.
104226329Ssam  *
104326329Ssam  * This is VERY dependent on the use of stdio.
104426329Ssam  */
104526329Ssam 
104626329Ssam public flushoutput()
104726329Ssam {
104826329Ssam     Symbol p, iob;
104926329Ssam     Stack *savesp;
105026329Ssam 
105126329Ssam     p = lookup(identname("fflush", true));
105226329Ssam     while (p != nil and not isblock(p)) {
105326329Ssam 	p = p->next_sym;
105426329Ssam     }
105526329Ssam     if (p != nil) {
105626329Ssam 	iob = lookup(identname("_iob", true));
105726329Ssam 	if (iob != nil) {
105826329Ssam 	    pushenv();
105926329Ssam 	    pc = codeloc(p);
106026329Ssam 	    savesp = sp;
106126329Ssam 	    push(long, address(iob, nil) + sizeof(struct _iobuf));
106226329Ssam 	    setreg(STKP, reg(STKP) - sizeof(long));
106326329Ssam 	    dwrite(savesp, reg(STKP), sizeof(long));
106426329Ssam 	    sp = savesp;
106526329Ssam 	    beginproc(p, 1);
106626329Ssam 	    stepto(return_addr());
106726329Ssam 	    popenv();
106826329Ssam 	}
106926329Ssam     }
107026329Ssam }
1071