xref: /csrg-svn/old/dbx/runtime.vax.c (revision 33334)
121621Sdist /*
221621Sdist  * Copyright (c) 1983 Regents of the University of California.
321621Sdist  * All rights reserved.  The Berkeley software License Agreement
421621Sdist  * specifies the terms and conditions for redistribution.
521621Sdist  */
69678Slinton 
721621Sdist #ifndef lint
8*33334Sdonn static char sccsid[] = "@(#)runtime.vax.c	5.3 (Berkeley) 01/12/88";
921621Sdist #endif not lint
109678Slinton 
11*33334Sdonn static char rcsid[] = "$Header: runtime.vax.c,v 1.3 88/01/11 21:27:00 donn Exp $";
1218231Slinton 
139678Slinton /*
149678Slinton  * Runtime organization dependent routines, mostly dealing with
159678Slinton  * activation records.
169678Slinton  */
179678Slinton 
189678Slinton #include "defs.h"
199678Slinton #include "runtime.h"
209678Slinton #include "process.h"
219678Slinton #include "machine.h"
229678Slinton #include "events.h"
239678Slinton #include "mappings.h"
249678Slinton #include "symbols.h"
259678Slinton #include "tree.h"
269678Slinton #include "eval.h"
279678Slinton #include "operators.h"
289678Slinton #include "object.h"
2912546Scsvaf #include <sys/param.h>
30*33334Sdonn #include <signal.h>
319678Slinton 
329678Slinton #ifndef public
339678Slinton typedef struct Frame *Frame;
349678Slinton 
359678Slinton #include "machine.h"
369678Slinton #endif
379678Slinton 
389678Slinton #define NSAVEREG 12
399678Slinton 
409678Slinton struct Frame {
4118231Slinton     integer condition_handler;
4218231Slinton     integer mask;
439678Slinton     Address save_ap;		/* argument pointer */
449678Slinton     Address save_fp;		/* frame pointer */
459678Slinton     Address save_pc;		/* program counter */
469678Slinton     Word save_reg[NSAVEREG];	/* not necessarily there */
479678Slinton };
489678Slinton 
4916618Ssam private Frame curframe = nil;
5016618Ssam private struct Frame curframerec;
519678Slinton private Boolean walkingstack = false;
529678Slinton 
5316618Ssam #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp)
5416618Ssam 
55*33334Sdonn #define inSignalHandler(addr) \
56*33334Sdonn     (((addr) < 0x80000000) and ((addr) > 0x80000000 - ctob(UPAGES)))
5718231Slinton 
5818231Slinton typedef struct {
5918231Slinton     Node callnode;
6018231Slinton     Node cmdnode;
6118231Slinton     boolean isfunc;
6218231Slinton } CallEnv;
6318231Slinton 
6418231Slinton private CallEnv endproc;
6518231Slinton 
669678Slinton /*
679678Slinton  * Set a frame to the current activation record.
689678Slinton  */
699678Slinton 
709678Slinton private getcurframe(frp)
7118231Slinton Frame frp;
729678Slinton {
739678Slinton     register int i;
749678Slinton 
759678Slinton     checkref(frp);
769678Slinton     frp->mask = reg(NREG);
779678Slinton     frp->save_ap = reg(ARGP);
789678Slinton     frp->save_fp = reg(FRP);
7918231Slinton     frp->save_pc = reg(PROGCTR);
809678Slinton     for (i = 0; i < NSAVEREG; i++) {
819678Slinton 	frp->save_reg[i] = reg(i);
829678Slinton     }
839678Slinton }
849678Slinton 
859678Slinton /*
8618231Slinton  * Get the saved registers from one frame to another
8718231Slinton  * given mask specifying which registers were actually saved.
8818231Slinton  */
8918231Slinton 
9018231Slinton #define bis(b, n) ((b & (1 << (n))) != 0)
9118231Slinton 
9218231Slinton private getsaveregs (newfrp, frp, mask)
9318231Slinton Frame newfrp, frp;
9418231Slinton integer mask;
9518231Slinton {
9618231Slinton     integer i, j;
9718231Slinton 
9818231Slinton     j = 0;
9918231Slinton     for (i = 0; i < NSAVEREG; i++) {
10018231Slinton 	if (bis(mask, i)) {
10118231Slinton 	    newfrp->save_reg[i] = frp->save_reg[j];
10218231Slinton 	    ++j;
10318231Slinton 	}
10418231Slinton     }
10518231Slinton }
10618231Slinton 
10718231Slinton /*
1089678Slinton  * Return a pointer to the next activation record up the stack.
1099678Slinton  * Return nil if there is none.
1109678Slinton  * Writes over space pointed to by given argument.
1119678Slinton  */
1129678Slinton 
1139678Slinton private Frame nextframe(frp)
1149678Slinton Frame frp;
1159678Slinton {
11618231Slinton     Frame newfrp;
1179678Slinton     struct Frame frame;
11818231Slinton     integer mask;
119*33334Sdonn     Address prev_frame, callpc;
12018231Slinton     static integer ntramp = 0;
1219678Slinton 
1229678Slinton     newfrp = frp;
12312546Scsvaf     prev_frame = frp->save_fp;
12412546Scsvaf 
12513937Slinton /*
12613937Slinton  *  The check for interrupt generated frames is taken from adb with only
12713937Slinton  *  partial understanding.  If you're in "sub" and on a sigxxx "sigsub"
12813937Slinton  *  gets control, then the stack does NOT look like <main, sub, sigsub>.
12912546Scsvaf  *
13012546Scsvaf  *  As best I can make out it looks like:
13112546Scsvaf  *
13213937Slinton  *     <main, (machine check exception block + sub), sysframe, sigsub>.
13313937Slinton  *
13413937Slinton  *  When the signal occurs an exception block and a frame for the routine
13513937Slinton  *  in which it occured are pushed on the user stack.  Then another frame
13613937Slinton  *  is pushed corresponding to a call from the kernel to sigsub.
13713937Slinton  *
13812546Scsvaf  *  The addr in sub at which the exception occured is not in sub.save_pc
13913937Slinton  *  but in the machine check exception block.  It is at the magic address
14014620Ssam  *  fp + 84.
14112546Scsvaf  *
14212546Scsvaf  *  The current approach ignores the sys_frame (what adb reports as sigtramp)
14313937Slinton  *  and takes the pc for sub from the exception block.  This allows the
14413937Slinton  *  "where" command to report <main, sub, sigsub>, which seems reasonable.
14512546Scsvaf  */
14612546Scsvaf 
14713937Slinton nextf:
148*33334Sdonn     if (prev_frame + sizeof(struct Frame) <= USRSTACK) {
149*33334Sdonn 	dread(&frame, prev_frame, sizeof(struct Frame));
150*33334Sdonn     } else if (USRSTACK - prev_frame > 2 * sizeof(Word)) {
151*33334Sdonn 	dread(&frame, prev_frame, USRSTACK - prev_frame);
152*33334Sdonn     } else {
153*33334Sdonn 	frame.save_fp = nil;
154*33334Sdonn     }
15513937Slinton     if (ntramp == 1) {
156*33334Sdonn 	dread(&callpc, prev_frame + 92, sizeof(callpc));
15713937Slinton     } else {
15813937Slinton 	callpc = frame.save_pc;
15913937Slinton     }
16018231Slinton     if (frame.save_fp == nil or frame.save_pc == (Address) -1) {
1619678Slinton 	newfrp = nil;
16213937Slinton     } else {
163*33334Sdonn 	if (inSignalHandler(callpc)) {
164*33334Sdonn 	    ntramp++;
165*33334Sdonn 	    prev_frame = frame.save_fp;
166*33334Sdonn 	    goto nextf;
167*33334Sdonn 	}
16812546Scsvaf 	frame.save_pc = callpc;
16913937Slinton         ntramp = 0;
170*33334Sdonn 	newfrp->save_fp = frame.save_fp;
171*33334Sdonn 	newfrp->save_pc = frame.save_pc;
1729678Slinton 	mask = ((frame.mask >> 16) & 0x0fff);
17318231Slinton 	getsaveregs(newfrp, &frame, mask);
1749678Slinton 	newfrp->condition_handler = frame.condition_handler;
1759678Slinton 	newfrp->mask = mask;
1769678Slinton 	newfrp->save_ap = frame.save_ap;
1779678Slinton     }
1789678Slinton     return newfrp;
1799678Slinton }
1809678Slinton 
1819678Slinton /*
18216618Ssam  * Get the current frame information in the given Frame and store the
18316618Ssam  * associated function in the given value-result parameter.
18416618Ssam  */
18516618Ssam 
18616618Ssam private getcurfunc (frp, fp)
18716618Ssam Frame frp;
18816618Ssam Symbol *fp;
18916618Ssam {
19016618Ssam     getcurframe(frp);
19116618Ssam     *fp = whatblock(frp->save_pc);
19216618Ssam }
19316618Ssam 
19416618Ssam /*
19516618Ssam  * Return the frame associated with the next function up the call stack, or
19616618Ssam  * nil if there is none.  The function is returned in a value-result parameter.
19716618Ssam  * For "inline" functions the statically outer function and same frame
19816618Ssam  * are returned.
19916618Ssam  */
20016618Ssam 
20118231Slinton public Frame nextfunc (frp, fp)
20216618Ssam Frame frp;
20316618Ssam Symbol *fp;
20416618Ssam {
20516618Ssam     Symbol t;
20616618Ssam     Frame nfrp;
20716618Ssam 
20816618Ssam     t = *fp;
20916618Ssam     checkref(t);
21016618Ssam     if (isinline(t)) {
21116618Ssam 	t = container(t);
21216618Ssam 	nfrp = frp;
21316618Ssam     } else {
21416618Ssam 	nfrp = nextframe(frp);
21516618Ssam 	if (nfrp == nil) {
21616618Ssam 	    t = nil;
21716618Ssam 	} else {
21816618Ssam 	    t = whatblock(nfrp->save_pc);
21916618Ssam 	}
22016618Ssam     }
22116618Ssam     *fp = t;
22216618Ssam     return nfrp;
22316618Ssam }
22416618Ssam 
22516618Ssam /*
2269678Slinton  * Return the frame associated with the given function.
2279678Slinton  * If the function is nil, return the most recently activated frame.
2289678Slinton  *
2299678Slinton  * Static allocation for the frame.
2309678Slinton  */
2319678Slinton 
2329678Slinton public Frame findframe(f)
2339678Slinton Symbol f;
2349678Slinton {
23518231Slinton     Frame frp;
2369678Slinton     static struct Frame frame;
23711866Slinton     Symbol p;
23818231Slinton     Boolean done;
2399678Slinton 
2409678Slinton     frp = &frame;
2419678Slinton     getcurframe(frp);
24218231Slinton     if (f != nil) {
24318231Slinton 	if (f == curfunc and curframe != nil) {
24418231Slinton 	    *frp = *curframe;
24518231Slinton 	} else {
24618231Slinton 	    done = false;
24718231Slinton 	    p = whatblock(frp->save_pc);
24818231Slinton 	    do {
24918231Slinton 		if (p == f) {
25018231Slinton 		    done = true;
25118231Slinton 		} else if (p == program) {
25218231Slinton 		    done = true;
25318231Slinton 		    frp = nil;
25418231Slinton 		} else {
25518231Slinton 		    frp = nextfunc(frp, &p);
25618231Slinton 		    if (frp == nil) {
25718231Slinton 			done = true;
25818231Slinton 		    }
25918231Slinton 		}
26018231Slinton 	    } while (not done);
26115784Ssam 	}
26218231Slinton     }
26318231Slinton     return frp;
26418231Slinton }
26518231Slinton 
26618231Slinton /*
26718231Slinton  * Set the registers according to the given frame pointer.
26818231Slinton  */
26918231Slinton 
27018231Slinton public getnewregs (addr)
27118231Slinton Address addr;
27218231Slinton {
27318231Slinton     struct Frame frame;
27418231Slinton     integer i, j, mask;
27518231Slinton 
27618231Slinton     dread(&frame, addr, sizeof(frame));
27718231Slinton     setreg(FRP, frame.save_fp);
27818231Slinton     setreg(PROGCTR, frame.save_pc);
279*33334Sdonn     setreg(ARGP, frame.save_ap);
28018231Slinton     mask = ((frame.mask >> 16) & 0x0fff);
28118231Slinton     j = 0;
28218231Slinton     for (i = 0; i < NSAVEREG; i++) {
28318231Slinton 	if (bis(mask, i)) {
284*33334Sdonn 	setreg(i, frame.save_reg[j]);
285*33334Sdonn 	++j;
28616636Ssam 	}
2879678Slinton     }
28818231Slinton     pc = frame.save_pc;
28918231Slinton     setcurfunc(whatblock(pc));
2909678Slinton }
2919678Slinton 
2929678Slinton /*
2939678Slinton  * Find the return address of the current procedure/function.
2949678Slinton  */
2959678Slinton 
2969678Slinton public Address return_addr()
2979678Slinton {
2989678Slinton     Frame frp;
2999678Slinton     Address addr;
3009678Slinton     struct Frame frame;
3019678Slinton 
3029678Slinton     frp = &frame;
3039678Slinton     getcurframe(frp);
3049678Slinton     frp = nextframe(frp);
3059678Slinton     if (frp == nil) {
3069678Slinton 	addr = 0;
3079678Slinton     } else {
3089678Slinton 	addr = frp->save_pc;
3099678Slinton     }
3109678Slinton     return addr;
3119678Slinton }
3129678Slinton 
3139678Slinton /*
3149678Slinton  * Push the value associated with the current function.
3159678Slinton  */
3169678Slinton 
3179678Slinton public pushretval(len, isindirect)
31818231Slinton integer len;
31918231Slinton boolean isindirect;
3209678Slinton {
3219678Slinton     Word r0;
3229678Slinton 
3239678Slinton     r0 = reg(0);
3249678Slinton     if (isindirect) {
3259678Slinton 	rpush((Address) r0, len);
3269678Slinton     } else {
3279678Slinton 	switch (len) {
3289678Slinton 	    case sizeof(char):
3299678Slinton 		push(char, r0);
3309678Slinton 		break;
3319678Slinton 
3329678Slinton 	    case sizeof(short):
3339678Slinton 		push(short, r0);
3349678Slinton 		break;
3359678Slinton 
3369678Slinton 	    default:
3379678Slinton 		if (len == sizeof(Word)) {
3389678Slinton 		    push(Word, r0);
3399678Slinton 		} else if (len == 2*sizeof(Word)) {
3409678Slinton 		    push(Word, r0);
3419678Slinton 		    push(Word, reg(1));
3429678Slinton 		} else {
34318231Slinton 		    error("[internal error: bad size %d in pushretval]", len);
3449678Slinton 		}
3459678Slinton 		break;
3469678Slinton 	}
3479678Slinton     }
3489678Slinton }
3499678Slinton 
3509678Slinton /*
3519678Slinton  * Return the base address for locals in the given frame.
3529678Slinton  */
3539678Slinton 
3549678Slinton public Address locals_base(frp)
35518231Slinton Frame frp;
3569678Slinton {
3579678Slinton     return (frp == nil) ? reg(FRP) : frp->save_fp;
3589678Slinton }
3599678Slinton 
3609678Slinton /*
3619678Slinton  * Return the base address for arguments in the given frame.
3629678Slinton  */
3639678Slinton 
3649678Slinton public Address args_base(frp)
36518231Slinton Frame frp;
3669678Slinton {
3679678Slinton     return (frp == nil) ? reg(ARGP) : frp->save_ap;
3689678Slinton }
3699678Slinton 
3709678Slinton /*
3719678Slinton  * Return saved register n from the given frame.
3729678Slinton  */
3739678Slinton 
3749678Slinton public Word savereg(n, frp)
37518231Slinton integer n;
37618231Slinton Frame frp;
3779678Slinton {
37818231Slinton     Word w;
3799678Slinton 
3809678Slinton     if (frp == nil) {
3819678Slinton 	w = reg(n);
3829678Slinton     } else {
3839678Slinton 	switch (n) {
3849678Slinton 	    case ARGP:
3859678Slinton 		w = frp->save_ap;
3869678Slinton 		break;
3879678Slinton 
3889678Slinton 	    case FRP:
3899678Slinton 		w = frp->save_fp;
3909678Slinton 		break;
3919678Slinton 
3929678Slinton 	    case STKP:
3939678Slinton 		w = reg(STKP);
3949678Slinton 		break;
3959678Slinton 
3969678Slinton 	    case PROGCTR:
3979678Slinton 		w = frp->save_pc;
3989678Slinton 		break;
3999678Slinton 
4009678Slinton 	    default:
4019678Slinton 		assert(n >= 0 and n < NSAVEREG);
4029678Slinton 		w = frp->save_reg[n];
4039678Slinton 		break;
4049678Slinton 	}
4059678Slinton     }
4069678Slinton     return w;
4079678Slinton }
4089678Slinton 
4099678Slinton /*
4109678Slinton  * Return the nth argument to the current procedure.
4119678Slinton  */
4129678Slinton 
4139678Slinton public Word argn(n, frp)
41418231Slinton integer n;
4159678Slinton Frame frp;
4169678Slinton {
417*33334Sdonn     Address argaddr;
4189678Slinton     Word w;
4199678Slinton 
420*33334Sdonn     argaddr = args_base(frp) + (n * sizeof(Word));
421*33334Sdonn     dread(&w, argaddr, sizeof(w));
4229678Slinton     return w;
4239678Slinton }
4249678Slinton 
4259678Slinton /*
42618231Slinton  * Print a list of currently active blocks starting with most recent.
4279678Slinton  */
4289678Slinton 
42918231Slinton public wherecmd()
4309678Slinton {
43118231Slinton     walkstack(false);
4329678Slinton }
4339678Slinton 
4349678Slinton /*
43518231Slinton  * Print the variables in the given frame or the current one if nil.
4369678Slinton  */
4379678Slinton 
43818231Slinton public dump (func)
43918231Slinton Symbol func;
4409678Slinton {
44118231Slinton     Symbol f;
44218231Slinton     Frame frp;
44318231Slinton 
44418231Slinton     if (func == nil) {
44518231Slinton 	f = curfunc;
44618231Slinton 	if (curframe != nil) {
44718231Slinton 	    frp = curframe;
44818231Slinton 	} else {
44918231Slinton 	    frp = findframe(f);
45018231Slinton 	}
45118231Slinton     } else {
45218231Slinton 	f = func;
45318231Slinton 	frp = findframe(f);
45418231Slinton     }
45518231Slinton     showaggrs = true;
45618231Slinton     printcallinfo(f, frp);
45718231Slinton     dumpvars(f, frp);
4589678Slinton }
4599678Slinton 
4609678Slinton /*
46118231Slinton  * Dump all values.
4629678Slinton  */
4639678Slinton 
46418231Slinton public dumpall ()
4659678Slinton {
4669678Slinton     walkstack(true);
4679678Slinton }
4689678Slinton 
4699678Slinton /*
4709678Slinton  * Walk the stack of active procedures printing information
4719678Slinton  * about each active procedure.
4729678Slinton  */
4739678Slinton 
4749678Slinton private walkstack(dumpvariables)
4759678Slinton Boolean dumpvariables;
4769678Slinton {
47718231Slinton     Frame frp;
47818231Slinton     boolean save;
47916618Ssam     Symbol f;
4809678Slinton     struct Frame frame;
4819678Slinton 
48218231Slinton     if (notstarted(process) or isfinished(process)) {
4839678Slinton 	error("program is not active");
4849678Slinton     } else {
4859678Slinton 	save = walkingstack;
4869678Slinton 	walkingstack = true;
48718231Slinton 	showaggrs = dumpvariables;
4889678Slinton 	frp = &frame;
48916618Ssam 	getcurfunc(frp, &f);
49018231Slinton 	for (;;) {
49118231Slinton 	    printcallinfo(f, frp);
4929678Slinton 	    if (dumpvariables) {
4939678Slinton 		dumpvars(f, frp);
4949678Slinton 		putchar('\n');
4959678Slinton 	    }
49616618Ssam 	    frp = nextfunc(frp, &f);
49718231Slinton 	    if (frp == nil or f == program) {
49818231Slinton 		break;
49918231Slinton 	    }
50018231Slinton 	}
5019678Slinton 	if (dumpvariables) {
5029678Slinton 	    printf("in \"%s\":\n", symname(program));
5039678Slinton 	    dumpvars(program, nil);
5049678Slinton 	    putchar('\n');
5059678Slinton 	}
5069678Slinton 	walkingstack = save;
5079678Slinton     }
5089678Slinton }
5099678Slinton 
5109678Slinton /*
51118231Slinton  * Print out the information about a call, i.e.,
51218231Slinton  * routine name, parameter values, and source location.
51318231Slinton  */
51418231Slinton 
51518231Slinton private printcallinfo (f, frp)
51618231Slinton Symbol f;
51718231Slinton Frame frp;
51818231Slinton {
51918231Slinton     Lineno line;
52018231Slinton     Address savepc;
52118231Slinton 
52218231Slinton     savepc = frp->save_pc;
52318231Slinton     if (frp->save_fp != reg(FRP)) {
52418231Slinton 	savepc -= 1;
52518231Slinton     }
52618231Slinton     printname(stdout, f);
52718231Slinton     if (not isinline(f)) {
52818231Slinton 	printparams(f, frp);
52918231Slinton     }
53018231Slinton     line = srcline(savepc);
53118231Slinton     if (line != 0) {
53218231Slinton 	printf(", line %d", line);
53318231Slinton 	printf(" in \"%s\"\n", srcfilename(savepc));
53418231Slinton     } else {
53518231Slinton 	printf(" at 0x%x\n", savepc);
53618231Slinton     }
53718231Slinton }
53818231Slinton 
53918231Slinton /*
54016618Ssam  * Set the current function to the given symbol.
54116618Ssam  * We must adjust "curframe" so that subsequent operations are
54216618Ssam  * not confused; for simplicity we simply clear it.
54316618Ssam  */
54416618Ssam 
54516618Ssam public setcurfunc (f)
54616618Ssam Symbol f;
54716618Ssam {
54816618Ssam     curfunc = f;
54916618Ssam     curframe = nil;
55016618Ssam }
55116618Ssam 
55216618Ssam /*
55318231Slinton  * Return the frame for the current function.
55418231Slinton  * The space for the frame is allocated statically.
55518231Slinton  */
55618231Slinton 
55718231Slinton public Frame curfuncframe ()
55818231Slinton {
55918231Slinton     static struct Frame frame;
56018231Slinton     Frame frp;
56118231Slinton 
56218231Slinton     if (curframe == nil) {
56318231Slinton 	frp = findframe(curfunc);
56418231Slinton 	curframe = &curframerec;
56518231Slinton 	*curframe = *frp;
56618231Slinton     } else {
56718231Slinton 	frp = &frame;
56818231Slinton 	*frp = *curframe;
56918231Slinton     }
57018231Slinton     return frp;
57118231Slinton }
57218231Slinton 
57318231Slinton /*
57416618Ssam  * Set curfunc to be N up/down the stack from its current value.
57516618Ssam  */
57616618Ssam 
57716618Ssam public up (n)
57816618Ssam integer n;
57916618Ssam {
58016618Ssam     integer i;
58116618Ssam     Symbol f;
58216618Ssam     Frame frp;
58316618Ssam     boolean done;
58416618Ssam 
58516618Ssam     if (not isactive(program)) {
58616618Ssam 	error("program is not active");
58716618Ssam     } else if (curfunc == nil) {
58816618Ssam 	error("no current function");
58916618Ssam     } else {
59016618Ssam 	i = 0;
59116618Ssam 	f = curfunc;
59218231Slinton 	frp = curfuncframe();
59316618Ssam 	done = false;
59416618Ssam 	do {
59516618Ssam 	    if (frp == nil) {
59616618Ssam 		done = true;
59716618Ssam 		error("not that many levels");
59816618Ssam 	    } else if (i >= n) {
59916618Ssam 		done = true;
60016618Ssam 		curfunc = f;
60116618Ssam 		curframe = &curframerec;
60216618Ssam 		*curframe = *frp;
60318231Slinton 		showaggrs = false;
60418231Slinton 		printcallinfo(curfunc, curframe);
60516618Ssam 	    } else if (f == program) {
60616618Ssam 		done = true;
60716618Ssam 		error("not that many levels");
60816618Ssam 	    } else {
60916618Ssam 		frp = nextfunc(frp, &f);
61016618Ssam 	    }
61116618Ssam 	    ++i;
61216618Ssam 	} while (not done);
61316618Ssam     }
61416618Ssam }
61516618Ssam 
61616618Ssam public down (n)
61716618Ssam integer n;
61816618Ssam {
61916618Ssam     integer i, depth;
62018231Slinton     Frame frp, curfrp;
62116618Ssam     Symbol f;
62216618Ssam     struct Frame frame;
62316618Ssam 
62416618Ssam     if (not isactive(program)) {
62516618Ssam 	error("program is not active");
62616618Ssam     } else if (curfunc == nil) {
62716618Ssam 	error("no current function");
62816618Ssam     } else {
62916618Ssam 	depth = 0;
63016618Ssam 	frp = &frame;
63116618Ssam 	getcurfunc(frp, &f);
63216618Ssam 	if (curframe == nil) {
63318231Slinton 	    curfrp = findframe(curfunc);
63416618Ssam 	    curframe = &curframerec;
63518231Slinton 	    *curframe = *curfrp;
63616618Ssam 	}
63716618Ssam 	while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) {
63816618Ssam 	    frp = nextfunc(frp, &f);
63916618Ssam 	    ++depth;
64016618Ssam 	}
64116618Ssam 	if (f == nil or n > depth) {
64216618Ssam 	    error("not that many levels");
64316618Ssam 	} else {
64416618Ssam 	    depth -= n;
64516618Ssam 	    frp = &frame;
64616618Ssam 	    getcurfunc(frp, &f);
64716618Ssam 	    for (i = 0; i < depth; i++) {
64816618Ssam 		frp = nextfunc(frp, &f);
64916618Ssam 		assert(frp != nil);
65016618Ssam 	    }
65116618Ssam 	    curfunc = f;
65216618Ssam 	    *curframe = *frp;
65318231Slinton 	    showaggrs = false;
65418231Slinton 	    printcallinfo(curfunc, curframe);
65516618Ssam 	}
65616618Ssam     }
65716618Ssam }
65816618Ssam 
65916618Ssam /*
6609678Slinton  * Find the entry point of a procedure or function.
661*33334Sdonn  *
662*33334Sdonn  * On the VAX we add the size of the register mask (FUNCOFFSET) or
663*33334Sdonn  * the size of the Modula-2 internal entry sequence, on other machines
664*33334Sdonn  * (68000's) we add the entry sequence size (FUNCOFFSET) unless
665*33334Sdonn  * we're right at the beginning of the program.
6669678Slinton  */
6679678Slinton 
66818231Slinton public findbeginning (f)
6699678Slinton Symbol f;
6709678Slinton {
67116618Ssam     if (isinternal(f)) {
672*33334Sdonn 	f->symvalue.funcv.beginaddr += 18;	/* VAX only */
67316618Ssam     } else {
674*33334Sdonn 	f->symvalue.funcv.beginaddr += FUNCOFFSET;
67516618Ssam     }
6769678Slinton }
6779678Slinton 
6789678Slinton /*
6799678Slinton  * Return the address corresponding to the first line in a function.
6809678Slinton  */
6819678Slinton 
6829678Slinton public Address firstline(f)
6839678Slinton Symbol f;
6849678Slinton {
6859678Slinton     Address addr;
6869678Slinton 
6879678Slinton     addr = codeloc(f);
6889678Slinton     while (linelookup(addr) == 0 and addr < objsize) {
6899678Slinton 	++addr;
6909678Slinton     }
6919678Slinton     if (addr == objsize) {
6929678Slinton 	addr = -1;
6939678Slinton     }
6949678Slinton     return addr;
6959678Slinton }
6969678Slinton 
6979678Slinton /*
6989678Slinton  * Catcher drops strike three ...
6999678Slinton  */
7009678Slinton 
7019678Slinton public runtofirst()
7029678Slinton {
703*33334Sdonn     Address addr, endaddr;
7049678Slinton 
7059678Slinton     addr = pc;
706*33334Sdonn     endaddr = objsize + CODESTART;
707*33334Sdonn     while (linelookup(addr) == 0 and addr < endaddr) {
7089678Slinton 	++addr;
7099678Slinton     }
710*33334Sdonn     if (addr < endaddr) {
7119678Slinton 	stepto(addr);
7129678Slinton     }
7139678Slinton }
7149678Slinton 
7159678Slinton /*
7169678Slinton  * Return the address corresponding to the end of the program.
7179678Slinton  *
7189678Slinton  * We look for the entry to "exit".
7199678Slinton  */
7209678Slinton 
7219678Slinton public Address lastaddr()
7229678Slinton {
72318231Slinton     Symbol s;
7249678Slinton 
7259678Slinton     s = lookup(identname("exit", true));
7269678Slinton     if (s == nil) {
7279678Slinton 	panic("can't find exit");
7289678Slinton     }
7299678Slinton     return codeloc(s);
7309678Slinton }
7319678Slinton 
7329678Slinton /*
7339678Slinton  * Decide if the given function is currently active.
7349678Slinton  *
7359678Slinton  * We avoid calls to "findframe" during a stack trace for efficiency.
7369678Slinton  * Presumably information evaluated while walking the stack is active.
7379678Slinton  */
7389678Slinton 
739*33334Sdonn public Boolean isactive (f)
7409678Slinton Symbol f;
7419678Slinton {
74218231Slinton     Boolean b;
7439678Slinton 
7449678Slinton     if (isfinished(process)) {
7459678Slinton 	b = false;
7469678Slinton     } else {
747*33334Sdonn 	if (walkingstack or f == program or f == nil or
7489678Slinton 	  (ismodule(f) and isactive(container(f)))) {
7499678Slinton 	    b = true;
7509678Slinton 	} else {
7519678Slinton 	    b = (Boolean) (findframe(f) != nil);
7529678Slinton 	}
7539678Slinton     }
7549678Slinton     return b;
7559678Slinton }
7569678Slinton 
7579678Slinton /*
7589678Slinton  * Evaluate a call to a procedure.
7599678Slinton  */
7609678Slinton 
76118231Slinton public callproc(exprnode, isfunc)
76218231Slinton Node exprnode;
76318231Slinton boolean isfunc;
7649678Slinton {
76518231Slinton     Node procnode, arglist;
7669678Slinton     Symbol proc;
76718231Slinton     integer argc;
7689678Slinton 
76918231Slinton     procnode = exprnode->value.arg[0];
77018231Slinton     arglist = exprnode->value.arg[1];
7719678Slinton     if (procnode->op != O_SYM) {
7729678Slinton 	beginerrmsg();
7739678Slinton 	fprintf(stderr, "can't call \"");
7749678Slinton 	prtree(stderr, procnode);
7759678Slinton 	fprintf(stderr, "\"");
7769678Slinton 	enderrmsg();
7779678Slinton     }
7789678Slinton     assert(procnode->op == O_SYM);
7799678Slinton     proc = procnode->value.sym;
7809678Slinton     if (not isblock(proc)) {
7819678Slinton 	error("\"%s\" is not a procedure or function", symname(proc));
7829678Slinton     }
78318231Slinton     endproc.isfunc = isfunc;
78418231Slinton     endproc.callnode = exprnode;
78518231Slinton     endproc.cmdnode = topnode;
7869678Slinton     pushenv();
7879678Slinton     pc = codeloc(proc);
7889678Slinton     argc = pushargs(proc, arglist);
789*33334Sdonn     setreg(FRP, 1);	/* have to ensure it's non-zero for return_addr() */
7909678Slinton     beginproc(proc, argc);
79118231Slinton     event_once(
79218231Slinton 	build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)),
79318231Slinton 	buildcmdlist(build(O_PROCRTN, proc))
79418231Slinton     );
79518231Slinton     isstopped = false;
79618231Slinton     if (not bpact()) {
79718231Slinton 	isstopped = true;
79818231Slinton 	cont(0);
79918231Slinton     }
80018231Slinton     /*
80118231Slinton      * bpact() won't return true, it will call printstatus() and go back
80218231Slinton      * to command input if a breakpoint is found.
80318231Slinton      */
8049678Slinton     /* NOTREACHED */
8059678Slinton }
8069678Slinton 
8079678Slinton /*
8089678Slinton  * Push the arguments on the process' stack.  We do this by first
8099678Slinton  * evaluating them on the "eval" stack, then copying into the process'
8109678Slinton  * space.
8119678Slinton  */
8129678Slinton 
81318231Slinton private integer pushargs(proc, arglist)
8149678Slinton Symbol proc;
8159678Slinton Node arglist;
8169678Slinton {
8179678Slinton     Stack *savesp;
8189678Slinton     int argc, args_size;
8199678Slinton 
8209678Slinton     savesp = sp;
82126324Ssam     if (varIsSet("$unsafecall")) {
82226324Ssam 	argc = unsafe_evalargs(proc, arglist);
82326324Ssam     } else {
82426324Ssam 	argc = evalargs(proc, arglist);
82526324Ssam     }
8269678Slinton     args_size = sp - savesp;
8279678Slinton     setreg(STKP, reg(STKP) - args_size);
8289678Slinton     dwrite(savesp, reg(STKP), args_size);
8299678Slinton     sp = savesp;
8309678Slinton     return argc;
8319678Slinton }
8329678Slinton 
8339678Slinton /*
83416618Ssam  * Check to see if an expression is correct for a given parameter.
83516618Ssam  * If the given parameter is false, don't worry about type inconsistencies.
83616618Ssam  *
83716618Ssam  * Return whether or not it is ok.
8389678Slinton  */
8399678Slinton 
84016618Ssam private boolean chkparam (actual, formal, chk)
84116618Ssam Node actual;
84216618Ssam Symbol formal;
84316618Ssam boolean chk;
84416618Ssam {
84516618Ssam     boolean b;
84616618Ssam 
84716618Ssam     b = true;
84816618Ssam     if (chk) {
84916618Ssam 	if (formal == nil) {
85016618Ssam 	    beginerrmsg();
85116618Ssam 	    fprintf(stderr, "too many parameters");
85216618Ssam 	    b = false;
85316618Ssam 	} else if (not compatible(formal->type, actual->nodetype)) {
85416618Ssam 	    beginerrmsg();
85516618Ssam 	    fprintf(stderr, "type mismatch for %s", symname(formal));
85616618Ssam 	    b = false;
85716618Ssam 	}
85816618Ssam     }
85918231Slinton     if (b and formal != nil and
86018231Slinton 	isvarparam(formal) and not isopenarray(formal->type) and
86118231Slinton 	not (
86218231Slinton 	    actual->op == O_RVAL or actual->nodetype == t_addr or
86318231Slinton 	    (
86418231Slinton 		actual->op == O_TYPERENAME and
86518231Slinton 		(
86618231Slinton 		    actual->value.arg[0]->op == O_RVAL or
86718231Slinton 		    actual->value.arg[0]->nodetype == t_addr
86818231Slinton 		)
86918231Slinton 	    )
87018231Slinton 	)
87118231Slinton     ) {
87216618Ssam 	beginerrmsg();
87316618Ssam 	fprintf(stderr, "expected variable, found \"");
87416618Ssam 	prtree(stderr, actual);
87516618Ssam 	fprintf(stderr, "\"");
87616618Ssam 	b = false;
87716618Ssam     }
87816618Ssam     return b;
87916618Ssam }
88016618Ssam 
88116618Ssam /*
88216618Ssam  * Pass an expression to a particular parameter.
88316618Ssam  *
88416618Ssam  * Normally we pass either the address or value, but in some cases
88516618Ssam  * (such as C strings) we want to copy the value onto the stack and
88616618Ssam  * pass its address.
88718231Slinton  *
88818231Slinton  * Another special case raised by strings is the possibility that
88918231Slinton  * the actual parameter will be larger than the formal, even with
89018231Slinton  * appropriate type-checking.  This occurs because we assume during
89118231Slinton  * evaluation that strings are null-terminated, whereas some languages,
89218231Slinton  * notably Pascal, do not work under that assumption.
89316618Ssam  */
89416618Ssam 
89516618Ssam private passparam (actual, formal)
89616618Ssam Node actual;
89716618Ssam Symbol formal;
89816618Ssam {
89916618Ssam     boolean b;
90016618Ssam     Address addr;
90116618Ssam     Stack *savesp;
90218231Slinton     integer actsize, formsize;
90316618Ssam 
90418231Slinton     if (formal != nil and isvarparam(formal) and
90518231Slinton 	(not isopenarray(formal->type))
90618231Slinton     ) {
90716618Ssam 	addr = lval(actual->value.arg[0]);
90816618Ssam 	push(Address, addr);
90916618Ssam     } else if (passaddr(formal, actual->nodetype)) {
91016618Ssam 	savesp = sp;
91116618Ssam 	eval(actual);
91218231Slinton 	actsize = sp - savesp;
91318231Slinton 	setreg(STKP,
91418231Slinton 	    reg(STKP) - ((actsize + sizeof(Word) - 1) & ~(sizeof(Word) - 1))
91518231Slinton 	);
91618231Slinton 	dwrite(savesp, reg(STKP), actsize);
91716618Ssam 	sp = savesp;
91816618Ssam 	push(Address, reg(STKP));
91916618Ssam 	if (formal != nil and isopenarray(formal->type)) {
92018231Slinton 	    push(integer, actsize div size(formal->type->type));
92116618Ssam 	}
92218231Slinton     } else if (formal != nil) {
92318231Slinton 	formsize = size(formal);
92418231Slinton 	savesp = sp;
92518231Slinton 	eval(actual);
92618231Slinton 	actsize = sp - savesp;
92718231Slinton 	if (actsize > formsize) {
92818231Slinton 	    sp -= (actsize - formsize);
92918231Slinton 	}
93016618Ssam     } else {
93116618Ssam 	eval(actual);
93216618Ssam     }
93316618Ssam }
93416618Ssam 
93516618Ssam /*
93616618Ssam  * Evaluate an argument list left-to-right.
93716618Ssam  */
93816618Ssam 
93918231Slinton private integer evalargs(proc, arglist)
9409678Slinton Symbol proc;
9419678Slinton Node arglist;
9429678Slinton {
94316618Ssam     Node p, actual;
94416618Ssam     Symbol formal;
9459678Slinton     Stack *savesp;
94618231Slinton     integer count;
94716618Ssam     boolean chk;
9489678Slinton 
9499678Slinton     savesp = sp;
9509678Slinton     count = 0;
95116618Ssam     formal = proc->chain;
95216618Ssam     chk = (boolean) (not nosource(proc));
9539678Slinton     for (p = arglist; p != nil; p = p->value.arg[1]) {
95416618Ssam 	assert(p->op == O_COMMA);
95516618Ssam 	actual = p->value.arg[0];
95616618Ssam 	if (not chkparam(actual, formal, chk)) {
95716618Ssam 	    fprintf(stderr, " in call to %s", symname(proc));
9589678Slinton 	    sp = savesp;
95916618Ssam 	    enderrmsg();
9609678Slinton 	}
96116618Ssam 	passparam(actual, formal);
96216618Ssam 	if (formal != nil) {
96316618Ssam 	    formal = formal->chain;
9649678Slinton 	}
9659678Slinton 	++count;
9669678Slinton     }
96716618Ssam     if (chk) {
96816618Ssam 	if (formal != nil) {
96916618Ssam 	    sp = savesp;
97016618Ssam 	    error("not enough parameters to %s", symname(proc));
97116618Ssam 	}
9729678Slinton     }
9739678Slinton     return count;
9749678Slinton }
9759678Slinton 
97626324Ssam /*
977*33334Sdonn  * Evaluate an argument list without any type checking.
978*33334Sdonn  * This is only useful for procedures with a varying number of
979*33334Sdonn  * arguments that are compiled -g.
98026324Ssam  */
98126324Ssam 
982*33334Sdonn private integer unsafe_evalargs (proc, arglist)
98326324Ssam Symbol proc;
98426324Ssam Node arglist;
98526324Ssam {
98626324Ssam     Node p;
987*33334Sdonn     integer count;
98826324Ssam 
98926324Ssam     count = 0;
99026324Ssam     for (p = arglist; p != nil; p = p->value.arg[1]) {
99126324Ssam 	assert(p->op == O_COMMA);
99226324Ssam 	eval(p->value.arg[0]);
99326324Ssam 	++count;
99426324Ssam     }
99526324Ssam     return count;
99626324Ssam }
99726324Ssam 
9989678Slinton public procreturn(f)
9999678Slinton Symbol f;
10009678Slinton {
100118231Slinton     integer retvalsize;
100218231Slinton     Node tmp;
100318231Slinton     char *copy;
100418231Slinton 
10059678Slinton     flushoutput();
10069678Slinton     popenv();
100718231Slinton     if (endproc.isfunc) {
100818231Slinton 	retvalsize = size(f->type);
100918231Slinton 	if (retvalsize > sizeof(long)) {
101018231Slinton 	    pushretval(retvalsize, true);
101118231Slinton 	    copy = newarr(char, retvalsize);
101218231Slinton 	    popn(retvalsize, copy);
101318231Slinton 	    tmp = build(O_SCON, copy);
101418231Slinton 	} else {
101518231Slinton 	    tmp = build(O_LCON, (long) (reg(0)));
101618231Slinton 	}
101718231Slinton 	tmp->nodetype = f->type;
101818231Slinton 	tfree(endproc.callnode);
101918231Slinton 	*(endproc.callnode) = *(tmp);
102018231Slinton 	dispose(tmp);
102118231Slinton 	eval(endproc.cmdnode);
102218231Slinton     } else {
102318231Slinton 	putchar('\n');
102418231Slinton 	printname(stdout, f);
1025*33334Sdonn 	printf(" returns successfully\n");
102618231Slinton     }
10279678Slinton     erecover();
10289678Slinton }
10299678Slinton 
10309678Slinton /*
10319678Slinton  * Push the current environment.
10329678Slinton  */
10339678Slinton 
10349678Slinton private pushenv()
10359678Slinton {
10369678Slinton     push(Address, pc);
10379678Slinton     push(Lineno, curline);
10389678Slinton     push(String, cursource);
10399678Slinton     push(Boolean, isstopped);
10409678Slinton     push(Symbol, curfunc);
104116618Ssam     push(Frame, curframe);
104216618Ssam     push(struct Frame, curframerec);
104318231Slinton     push(CallEnv, endproc);
10449678Slinton     push(Word, reg(PROGCTR));
10459678Slinton     push(Word, reg(STKP));
1046*33334Sdonn     push(Word, reg(FRP));
10479678Slinton }
10489678Slinton 
10499678Slinton /*
10509678Slinton  * Pop back to the real world.
10519678Slinton  */
10529678Slinton 
10539678Slinton public popenv()
10549678Slinton {
105518231Slinton     String filename;
10569678Slinton 
1057*33334Sdonn     setreg(FRP, pop(Word));
10589678Slinton     setreg(STKP, pop(Word));
10599678Slinton     setreg(PROGCTR, pop(Word));
106018231Slinton     endproc = pop(CallEnv);
106116618Ssam     curframerec = pop(struct Frame);
106216618Ssam     curframe = pop(Frame);
10639678Slinton     curfunc = pop(Symbol);
10649678Slinton     isstopped = pop(Boolean);
10659678Slinton     filename = pop(String);
10669678Slinton     curline = pop(Lineno);
10679678Slinton     pc = pop(Address);
10689678Slinton     setsource(filename);
10699678Slinton }
10709678Slinton 
10719678Slinton /*
10729678Slinton  * Flush the debuggee's standard output.
10739678Slinton  *
10749678Slinton  * This is VERY dependent on the use of stdio.
10759678Slinton  */
10769678Slinton 
10779678Slinton public flushoutput()
10789678Slinton {
107918231Slinton     Symbol p, iob;
108018231Slinton     Stack *savesp;
10819678Slinton 
10829678Slinton     p = lookup(identname("fflush", true));
10839678Slinton     while (p != nil and not isblock(p)) {
10849678Slinton 	p = p->next_sym;
10859678Slinton     }
10869678Slinton     if (p != nil) {
10879678Slinton 	iob = lookup(identname("_iob", true));
10889678Slinton 	if (iob != nil) {
10899678Slinton 	    pushenv();
1090*33334Sdonn 	    pc = codeloc(p) - FUNCOFFSET;
10919678Slinton 	    savesp = sp;
1092*33334Sdonn 	    push(long, address(iob, nil) + sizeof(*stdout));
10939678Slinton 	    setreg(STKP, reg(STKP) - sizeof(long));
10949678Slinton 	    dwrite(savesp, reg(STKP), sizeof(long));
10959678Slinton 	    sp = savesp;
10969678Slinton 	    beginproc(p, 1);
10979678Slinton 	    stepto(return_addr());
10989678Slinton 	    popenv();
10999678Slinton 	}
11009678Slinton     }
11019678Slinton }
1102