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