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