xref: /csrg-svn/old/dbx/runtime.vax.c (revision 38105)
121621Sdist /*
2*38105Sbostic  * Copyright (c) 1983 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.
1621621Sdist  */
179678Slinton 
1821621Sdist #ifndef lint
19*38105Sbostic static char sccsid[] = "@(#)runtime.vax.c	5.4 (Berkeley) 05/23/89";
20*38105Sbostic #endif /* not lint */
219678Slinton 
229678Slinton /*
239678Slinton  * Runtime organization dependent routines, mostly dealing with
249678Slinton  * activation records.
259678Slinton  */
269678Slinton 
279678Slinton #include "defs.h"
289678Slinton #include "runtime.h"
299678Slinton #include "process.h"
309678Slinton #include "machine.h"
319678Slinton #include "events.h"
329678Slinton #include "mappings.h"
339678Slinton #include "symbols.h"
349678Slinton #include "tree.h"
359678Slinton #include "eval.h"
369678Slinton #include "operators.h"
379678Slinton #include "object.h"
3812546Scsvaf #include <sys/param.h>
3933334Sdonn #include <signal.h>
409678Slinton 
419678Slinton #ifndef public
429678Slinton typedef struct Frame *Frame;
439678Slinton 
449678Slinton #include "machine.h"
459678Slinton #endif
469678Slinton 
479678Slinton #define NSAVEREG 12
489678Slinton 
499678Slinton struct Frame {
5018231Slinton     integer condition_handler;
5118231Slinton     integer mask;
529678Slinton     Address save_ap;		/* argument pointer */
539678Slinton     Address save_fp;		/* frame pointer */
549678Slinton     Address save_pc;		/* program counter */
559678Slinton     Word save_reg[NSAVEREG];	/* not necessarily there */
569678Slinton };
579678Slinton 
5816618Ssam private Frame curframe = nil;
5916618Ssam private struct Frame curframerec;
609678Slinton private Boolean walkingstack = false;
619678Slinton 
6216618Ssam #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp)
6316618Ssam 
6433334Sdonn #define inSignalHandler(addr) \
6533334Sdonn     (((addr) < 0x80000000) and ((addr) > 0x80000000 - ctob(UPAGES)))
6618231Slinton 
6718231Slinton typedef struct {
6818231Slinton     Node callnode;
6918231Slinton     Node cmdnode;
7018231Slinton     boolean isfunc;
7118231Slinton } CallEnv;
7218231Slinton 
7318231Slinton private CallEnv endproc;
7418231Slinton 
759678Slinton /*
769678Slinton  * Set a frame to the current activation record.
779678Slinton  */
789678Slinton 
799678Slinton private getcurframe(frp)
8018231Slinton Frame frp;
819678Slinton {
829678Slinton     register int i;
839678Slinton 
849678Slinton     checkref(frp);
859678Slinton     frp->mask = reg(NREG);
869678Slinton     frp->save_ap = reg(ARGP);
879678Slinton     frp->save_fp = reg(FRP);
8818231Slinton     frp->save_pc = reg(PROGCTR);
899678Slinton     for (i = 0; i < NSAVEREG; i++) {
909678Slinton 	frp->save_reg[i] = reg(i);
919678Slinton     }
929678Slinton }
939678Slinton 
949678Slinton /*
9518231Slinton  * Get the saved registers from one frame to another
9618231Slinton  * given mask specifying which registers were actually saved.
9718231Slinton  */
9818231Slinton 
9918231Slinton #define bis(b, n) ((b & (1 << (n))) != 0)
10018231Slinton 
10118231Slinton private getsaveregs (newfrp, frp, mask)
10218231Slinton Frame newfrp, frp;
10318231Slinton integer mask;
10418231Slinton {
10518231Slinton     integer i, j;
10618231Slinton 
10718231Slinton     j = 0;
10818231Slinton     for (i = 0; i < NSAVEREG; i++) {
10918231Slinton 	if (bis(mask, i)) {
11018231Slinton 	    newfrp->save_reg[i] = frp->save_reg[j];
11118231Slinton 	    ++j;
11218231Slinton 	}
11318231Slinton     }
11418231Slinton }
11518231Slinton 
11618231Slinton /*
1179678Slinton  * Return a pointer to the next activation record up the stack.
1189678Slinton  * Return nil if there is none.
1199678Slinton  * Writes over space pointed to by given argument.
1209678Slinton  */
1219678Slinton 
1229678Slinton private Frame nextframe(frp)
1239678Slinton Frame frp;
1249678Slinton {
12518231Slinton     Frame newfrp;
1269678Slinton     struct Frame frame;
12718231Slinton     integer mask;
12833334Sdonn     Address prev_frame, callpc;
12918231Slinton     static integer ntramp = 0;
1309678Slinton 
1319678Slinton     newfrp = frp;
13212546Scsvaf     prev_frame = frp->save_fp;
13312546Scsvaf 
13413937Slinton /*
13513937Slinton  *  The check for interrupt generated frames is taken from adb with only
13613937Slinton  *  partial understanding.  If you're in "sub" and on a sigxxx "sigsub"
13713937Slinton  *  gets control, then the stack does NOT look like <main, sub, sigsub>.
13812546Scsvaf  *
13912546Scsvaf  *  As best I can make out it looks like:
14012546Scsvaf  *
14113937Slinton  *     <main, (machine check exception block + sub), sysframe, sigsub>.
14213937Slinton  *
14313937Slinton  *  When the signal occurs an exception block and a frame for the routine
14413937Slinton  *  in which it occured are pushed on the user stack.  Then another frame
14513937Slinton  *  is pushed corresponding to a call from the kernel to sigsub.
14613937Slinton  *
14712546Scsvaf  *  The addr in sub at which the exception occured is not in sub.save_pc
14813937Slinton  *  but in the machine check exception block.  It is at the magic address
14914620Ssam  *  fp + 84.
15012546Scsvaf  *
15112546Scsvaf  *  The current approach ignores the sys_frame (what adb reports as sigtramp)
15213937Slinton  *  and takes the pc for sub from the exception block.  This allows the
15313937Slinton  *  "where" command to report <main, sub, sigsub>, which seems reasonable.
15412546Scsvaf  */
15512546Scsvaf 
15613937Slinton nextf:
15733334Sdonn     if (prev_frame + sizeof(struct Frame) <= USRSTACK) {
15833334Sdonn 	dread(&frame, prev_frame, sizeof(struct Frame));
15933334Sdonn     } else if (USRSTACK - prev_frame > 2 * sizeof(Word)) {
16033334Sdonn 	dread(&frame, prev_frame, USRSTACK - prev_frame);
16133334Sdonn     } else {
16233334Sdonn 	frame.save_fp = nil;
16333334Sdonn     }
16413937Slinton     if (ntramp == 1) {
16533334Sdonn 	dread(&callpc, prev_frame + 92, sizeof(callpc));
16613937Slinton     } else {
16713937Slinton 	callpc = frame.save_pc;
16813937Slinton     }
16918231Slinton     if (frame.save_fp == nil or frame.save_pc == (Address) -1) {
1709678Slinton 	newfrp = nil;
17113937Slinton     } else {
17233334Sdonn 	if (inSignalHandler(callpc)) {
17333334Sdonn 	    ntramp++;
17433334Sdonn 	    prev_frame = frame.save_fp;
17533334Sdonn 	    goto nextf;
17633334Sdonn 	}
17712546Scsvaf 	frame.save_pc = callpc;
17813937Slinton         ntramp = 0;
17933334Sdonn 	newfrp->save_fp = frame.save_fp;
18033334Sdonn 	newfrp->save_pc = frame.save_pc;
1819678Slinton 	mask = ((frame.mask >> 16) & 0x0fff);
18218231Slinton 	getsaveregs(newfrp, &frame, mask);
1839678Slinton 	newfrp->condition_handler = frame.condition_handler;
1849678Slinton 	newfrp->mask = mask;
1859678Slinton 	newfrp->save_ap = frame.save_ap;
1869678Slinton     }
1879678Slinton     return newfrp;
1889678Slinton }
1899678Slinton 
1909678Slinton /*
19116618Ssam  * Get the current frame information in the given Frame and store the
19216618Ssam  * associated function in the given value-result parameter.
19316618Ssam  */
19416618Ssam 
19516618Ssam private getcurfunc (frp, fp)
19616618Ssam Frame frp;
19716618Ssam Symbol *fp;
19816618Ssam {
19916618Ssam     getcurframe(frp);
20016618Ssam     *fp = whatblock(frp->save_pc);
20116618Ssam }
20216618Ssam 
20316618Ssam /*
20416618Ssam  * Return the frame associated with the next function up the call stack, or
20516618Ssam  * nil if there is none.  The function is returned in a value-result parameter.
20616618Ssam  * For "inline" functions the statically outer function and same frame
20716618Ssam  * are returned.
20816618Ssam  */
20916618Ssam 
21018231Slinton public Frame nextfunc (frp, fp)
21116618Ssam Frame frp;
21216618Ssam Symbol *fp;
21316618Ssam {
21416618Ssam     Symbol t;
21516618Ssam     Frame nfrp;
21616618Ssam 
21716618Ssam     t = *fp;
21816618Ssam     checkref(t);
21916618Ssam     if (isinline(t)) {
22016618Ssam 	t = container(t);
22116618Ssam 	nfrp = frp;
22216618Ssam     } else {
22316618Ssam 	nfrp = nextframe(frp);
22416618Ssam 	if (nfrp == nil) {
22516618Ssam 	    t = nil;
22616618Ssam 	} else {
22716618Ssam 	    t = whatblock(nfrp->save_pc);
22816618Ssam 	}
22916618Ssam     }
23016618Ssam     *fp = t;
23116618Ssam     return nfrp;
23216618Ssam }
23316618Ssam 
23416618Ssam /*
2359678Slinton  * Return the frame associated with the given function.
2369678Slinton  * If the function is nil, return the most recently activated frame.
2379678Slinton  *
2389678Slinton  * Static allocation for the frame.
2399678Slinton  */
2409678Slinton 
2419678Slinton public Frame findframe(f)
2429678Slinton Symbol f;
2439678Slinton {
24418231Slinton     Frame frp;
2459678Slinton     static struct Frame frame;
24611866Slinton     Symbol p;
24718231Slinton     Boolean done;
2489678Slinton 
2499678Slinton     frp = &frame;
2509678Slinton     getcurframe(frp);
25118231Slinton     if (f != nil) {
25218231Slinton 	if (f == curfunc and curframe != nil) {
25318231Slinton 	    *frp = *curframe;
25418231Slinton 	} else {
25518231Slinton 	    done = false;
25618231Slinton 	    p = whatblock(frp->save_pc);
25718231Slinton 	    do {
25818231Slinton 		if (p == f) {
25918231Slinton 		    done = true;
26018231Slinton 		} else if (p == program) {
26118231Slinton 		    done = true;
26218231Slinton 		    frp = nil;
26318231Slinton 		} else {
26418231Slinton 		    frp = nextfunc(frp, &p);
26518231Slinton 		    if (frp == nil) {
26618231Slinton 			done = true;
26718231Slinton 		    }
26818231Slinton 		}
26918231Slinton 	    } while (not done);
27015784Ssam 	}
27118231Slinton     }
27218231Slinton     return frp;
27318231Slinton }
27418231Slinton 
27518231Slinton /*
27618231Slinton  * Set the registers according to the given frame pointer.
27718231Slinton  */
27818231Slinton 
27918231Slinton public getnewregs (addr)
28018231Slinton Address addr;
28118231Slinton {
28218231Slinton     struct Frame frame;
28318231Slinton     integer i, j, mask;
28418231Slinton 
28518231Slinton     dread(&frame, addr, sizeof(frame));
28618231Slinton     setreg(FRP, frame.save_fp);
28718231Slinton     setreg(PROGCTR, frame.save_pc);
28833334Sdonn     setreg(ARGP, frame.save_ap);
28918231Slinton     mask = ((frame.mask >> 16) & 0x0fff);
29018231Slinton     j = 0;
29118231Slinton     for (i = 0; i < NSAVEREG; i++) {
29218231Slinton 	if (bis(mask, i)) {
29333334Sdonn 	setreg(i, frame.save_reg[j]);
29433334Sdonn 	++j;
29516636Ssam 	}
2969678Slinton     }
29718231Slinton     pc = frame.save_pc;
29818231Slinton     setcurfunc(whatblock(pc));
2999678Slinton }
3009678Slinton 
3019678Slinton /*
3029678Slinton  * Find the return address of the current procedure/function.
3039678Slinton  */
3049678Slinton 
3059678Slinton public Address return_addr()
3069678Slinton {
3079678Slinton     Frame frp;
3089678Slinton     Address addr;
3099678Slinton     struct Frame frame;
3109678Slinton 
3119678Slinton     frp = &frame;
3129678Slinton     getcurframe(frp);
3139678Slinton     frp = nextframe(frp);
3149678Slinton     if (frp == nil) {
3159678Slinton 	addr = 0;
3169678Slinton     } else {
3179678Slinton 	addr = frp->save_pc;
3189678Slinton     }
3199678Slinton     return addr;
3209678Slinton }
3219678Slinton 
3229678Slinton /*
3239678Slinton  * Push the value associated with the current function.
3249678Slinton  */
3259678Slinton 
3269678Slinton public pushretval(len, isindirect)
32718231Slinton integer len;
32818231Slinton boolean isindirect;
3299678Slinton {
3309678Slinton     Word r0;
3319678Slinton 
3329678Slinton     r0 = reg(0);
3339678Slinton     if (isindirect) {
3349678Slinton 	rpush((Address) r0, len);
3359678Slinton     } else {
3369678Slinton 	switch (len) {
3379678Slinton 	    case sizeof(char):
3389678Slinton 		push(char, r0);
3399678Slinton 		break;
3409678Slinton 
3419678Slinton 	    case sizeof(short):
3429678Slinton 		push(short, r0);
3439678Slinton 		break;
3449678Slinton 
3459678Slinton 	    default:
3469678Slinton 		if (len == sizeof(Word)) {
3479678Slinton 		    push(Word, r0);
3489678Slinton 		} else if (len == 2*sizeof(Word)) {
3499678Slinton 		    push(Word, r0);
3509678Slinton 		    push(Word, reg(1));
3519678Slinton 		} else {
35218231Slinton 		    error("[internal error: bad size %d in pushretval]", len);
3539678Slinton 		}
3549678Slinton 		break;
3559678Slinton 	}
3569678Slinton     }
3579678Slinton }
3589678Slinton 
3599678Slinton /*
3609678Slinton  * Return the base address for locals in the given frame.
3619678Slinton  */
3629678Slinton 
3639678Slinton public Address locals_base(frp)
36418231Slinton Frame frp;
3659678Slinton {
3669678Slinton     return (frp == nil) ? reg(FRP) : frp->save_fp;
3679678Slinton }
3689678Slinton 
3699678Slinton /*
3709678Slinton  * Return the base address for arguments in the given frame.
3719678Slinton  */
3729678Slinton 
3739678Slinton public Address args_base(frp)
37418231Slinton Frame frp;
3759678Slinton {
3769678Slinton     return (frp == nil) ? reg(ARGP) : frp->save_ap;
3779678Slinton }
3789678Slinton 
3799678Slinton /*
3809678Slinton  * Return saved register n from the given frame.
3819678Slinton  */
3829678Slinton 
3839678Slinton public Word savereg(n, frp)
38418231Slinton integer n;
38518231Slinton Frame frp;
3869678Slinton {
38718231Slinton     Word w;
3889678Slinton 
3899678Slinton     if (frp == nil) {
3909678Slinton 	w = reg(n);
3919678Slinton     } else {
3929678Slinton 	switch (n) {
3939678Slinton 	    case ARGP:
3949678Slinton 		w = frp->save_ap;
3959678Slinton 		break;
3969678Slinton 
3979678Slinton 	    case FRP:
3989678Slinton 		w = frp->save_fp;
3999678Slinton 		break;
4009678Slinton 
4019678Slinton 	    case STKP:
4029678Slinton 		w = reg(STKP);
4039678Slinton 		break;
4049678Slinton 
4059678Slinton 	    case PROGCTR:
4069678Slinton 		w = frp->save_pc;
4079678Slinton 		break;
4089678Slinton 
4099678Slinton 	    default:
4109678Slinton 		assert(n >= 0 and n < NSAVEREG);
4119678Slinton 		w = frp->save_reg[n];
4129678Slinton 		break;
4139678Slinton 	}
4149678Slinton     }
4159678Slinton     return w;
4169678Slinton }
4179678Slinton 
4189678Slinton /*
4199678Slinton  * Return the nth argument to the current procedure.
4209678Slinton  */
4219678Slinton 
4229678Slinton public Word argn(n, frp)
42318231Slinton integer n;
4249678Slinton Frame frp;
4259678Slinton {
42633334Sdonn     Address argaddr;
4279678Slinton     Word w;
4289678Slinton 
42933334Sdonn     argaddr = args_base(frp) + (n * sizeof(Word));
43033334Sdonn     dread(&w, argaddr, sizeof(w));
4319678Slinton     return w;
4329678Slinton }
4339678Slinton 
4349678Slinton /*
43518231Slinton  * Print a list of currently active blocks starting with most recent.
4369678Slinton  */
4379678Slinton 
43818231Slinton public wherecmd()
4399678Slinton {
44018231Slinton     walkstack(false);
4419678Slinton }
4429678Slinton 
4439678Slinton /*
44418231Slinton  * Print the variables in the given frame or the current one if nil.
4459678Slinton  */
4469678Slinton 
44718231Slinton public dump (func)
44818231Slinton Symbol func;
4499678Slinton {
45018231Slinton     Symbol f;
45118231Slinton     Frame frp;
45218231Slinton 
45318231Slinton     if (func == nil) {
45418231Slinton 	f = curfunc;
45518231Slinton 	if (curframe != nil) {
45618231Slinton 	    frp = curframe;
45718231Slinton 	} else {
45818231Slinton 	    frp = findframe(f);
45918231Slinton 	}
46018231Slinton     } else {
46118231Slinton 	f = func;
46218231Slinton 	frp = findframe(f);
46318231Slinton     }
46418231Slinton     showaggrs = true;
46518231Slinton     printcallinfo(f, frp);
46618231Slinton     dumpvars(f, frp);
4679678Slinton }
4689678Slinton 
4699678Slinton /*
47018231Slinton  * Dump all values.
4719678Slinton  */
4729678Slinton 
47318231Slinton public dumpall ()
4749678Slinton {
4759678Slinton     walkstack(true);
4769678Slinton }
4779678Slinton 
4789678Slinton /*
4799678Slinton  * Walk the stack of active procedures printing information
4809678Slinton  * about each active procedure.
4819678Slinton  */
4829678Slinton 
4839678Slinton private walkstack(dumpvariables)
4849678Slinton Boolean dumpvariables;
4859678Slinton {
48618231Slinton     Frame frp;
48718231Slinton     boolean save;
48816618Ssam     Symbol f;
4899678Slinton     struct Frame frame;
4909678Slinton 
49118231Slinton     if (notstarted(process) or isfinished(process)) {
4929678Slinton 	error("program is not active");
4939678Slinton     } else {
4949678Slinton 	save = walkingstack;
4959678Slinton 	walkingstack = true;
49618231Slinton 	showaggrs = dumpvariables;
4979678Slinton 	frp = &frame;
49816618Ssam 	getcurfunc(frp, &f);
49918231Slinton 	for (;;) {
50018231Slinton 	    printcallinfo(f, frp);
5019678Slinton 	    if (dumpvariables) {
5029678Slinton 		dumpvars(f, frp);
5039678Slinton 		putchar('\n');
5049678Slinton 	    }
50516618Ssam 	    frp = nextfunc(frp, &f);
50618231Slinton 	    if (frp == nil or f == program) {
50718231Slinton 		break;
50818231Slinton 	    }
50918231Slinton 	}
5109678Slinton 	if (dumpvariables) {
5119678Slinton 	    printf("in \"%s\":\n", symname(program));
5129678Slinton 	    dumpvars(program, nil);
5139678Slinton 	    putchar('\n');
5149678Slinton 	}
5159678Slinton 	walkingstack = save;
5169678Slinton     }
5179678Slinton }
5189678Slinton 
5199678Slinton /*
52018231Slinton  * Print out the information about a call, i.e.,
52118231Slinton  * routine name, parameter values, and source location.
52218231Slinton  */
52318231Slinton 
52418231Slinton private printcallinfo (f, frp)
52518231Slinton Symbol f;
52618231Slinton Frame frp;
52718231Slinton {
52818231Slinton     Lineno line;
52918231Slinton     Address savepc;
53018231Slinton 
53118231Slinton     savepc = frp->save_pc;
53218231Slinton     if (frp->save_fp != reg(FRP)) {
53318231Slinton 	savepc -= 1;
53418231Slinton     }
53518231Slinton     printname(stdout, f);
53618231Slinton     if (not isinline(f)) {
53718231Slinton 	printparams(f, frp);
53818231Slinton     }
53918231Slinton     line = srcline(savepc);
54018231Slinton     if (line != 0) {
54118231Slinton 	printf(", line %d", line);
54218231Slinton 	printf(" in \"%s\"\n", srcfilename(savepc));
54318231Slinton     } else {
54418231Slinton 	printf(" at 0x%x\n", savepc);
54518231Slinton     }
54618231Slinton }
54718231Slinton 
54818231Slinton /*
54916618Ssam  * Set the current function to the given symbol.
55016618Ssam  * We must adjust "curframe" so that subsequent operations are
55116618Ssam  * not confused; for simplicity we simply clear it.
55216618Ssam  */
55316618Ssam 
55416618Ssam public setcurfunc (f)
55516618Ssam Symbol f;
55616618Ssam {
55716618Ssam     curfunc = f;
55816618Ssam     curframe = nil;
55916618Ssam }
56016618Ssam 
56116618Ssam /*
56218231Slinton  * Return the frame for the current function.
56318231Slinton  * The space for the frame is allocated statically.
56418231Slinton  */
56518231Slinton 
56618231Slinton public Frame curfuncframe ()
56718231Slinton {
56818231Slinton     static struct Frame frame;
56918231Slinton     Frame frp;
57018231Slinton 
57118231Slinton     if (curframe == nil) {
57218231Slinton 	frp = findframe(curfunc);
57318231Slinton 	curframe = &curframerec;
57418231Slinton 	*curframe = *frp;
57518231Slinton     } else {
57618231Slinton 	frp = &frame;
57718231Slinton 	*frp = *curframe;
57818231Slinton     }
57918231Slinton     return frp;
58018231Slinton }
58118231Slinton 
58218231Slinton /*
58316618Ssam  * Set curfunc to be N up/down the stack from its current value.
58416618Ssam  */
58516618Ssam 
58616618Ssam public up (n)
58716618Ssam integer n;
58816618Ssam {
58916618Ssam     integer i;
59016618Ssam     Symbol f;
59116618Ssam     Frame frp;
59216618Ssam     boolean done;
59316618Ssam 
59416618Ssam     if (not isactive(program)) {
59516618Ssam 	error("program is not active");
59616618Ssam     } else if (curfunc == nil) {
59716618Ssam 	error("no current function");
59816618Ssam     } else {
59916618Ssam 	i = 0;
60016618Ssam 	f = curfunc;
60118231Slinton 	frp = curfuncframe();
60216618Ssam 	done = false;
60316618Ssam 	do {
60416618Ssam 	    if (frp == nil) {
60516618Ssam 		done = true;
60616618Ssam 		error("not that many levels");
60716618Ssam 	    } else if (i >= n) {
60816618Ssam 		done = true;
60916618Ssam 		curfunc = f;
61016618Ssam 		curframe = &curframerec;
61116618Ssam 		*curframe = *frp;
61218231Slinton 		showaggrs = false;
61318231Slinton 		printcallinfo(curfunc, curframe);
61416618Ssam 	    } else if (f == program) {
61516618Ssam 		done = true;
61616618Ssam 		error("not that many levels");
61716618Ssam 	    } else {
61816618Ssam 		frp = nextfunc(frp, &f);
61916618Ssam 	    }
62016618Ssam 	    ++i;
62116618Ssam 	} while (not done);
62216618Ssam     }
62316618Ssam }
62416618Ssam 
62516618Ssam public down (n)
62616618Ssam integer n;
62716618Ssam {
62816618Ssam     integer i, depth;
62918231Slinton     Frame frp, curfrp;
63016618Ssam     Symbol f;
63116618Ssam     struct Frame frame;
63216618Ssam 
63316618Ssam     if (not isactive(program)) {
63416618Ssam 	error("program is not active");
63516618Ssam     } else if (curfunc == nil) {
63616618Ssam 	error("no current function");
63716618Ssam     } else {
63816618Ssam 	depth = 0;
63916618Ssam 	frp = &frame;
64016618Ssam 	getcurfunc(frp, &f);
64116618Ssam 	if (curframe == nil) {
64218231Slinton 	    curfrp = findframe(curfunc);
64316618Ssam 	    curframe = &curframerec;
64418231Slinton 	    *curframe = *curfrp;
64516618Ssam 	}
64616618Ssam 	while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) {
64716618Ssam 	    frp = nextfunc(frp, &f);
64816618Ssam 	    ++depth;
64916618Ssam 	}
65016618Ssam 	if (f == nil or n > depth) {
65116618Ssam 	    error("not that many levels");
65216618Ssam 	} else {
65316618Ssam 	    depth -= n;
65416618Ssam 	    frp = &frame;
65516618Ssam 	    getcurfunc(frp, &f);
65616618Ssam 	    for (i = 0; i < depth; i++) {
65716618Ssam 		frp = nextfunc(frp, &f);
65816618Ssam 		assert(frp != nil);
65916618Ssam 	    }
66016618Ssam 	    curfunc = f;
66116618Ssam 	    *curframe = *frp;
66218231Slinton 	    showaggrs = false;
66318231Slinton 	    printcallinfo(curfunc, curframe);
66416618Ssam 	}
66516618Ssam     }
66616618Ssam }
66716618Ssam 
66816618Ssam /*
6699678Slinton  * Find the entry point of a procedure or function.
67033334Sdonn  *
67133334Sdonn  * On the VAX we add the size of the register mask (FUNCOFFSET) or
67233334Sdonn  * the size of the Modula-2 internal entry sequence, on other machines
67333334Sdonn  * (68000's) we add the entry sequence size (FUNCOFFSET) unless
67433334Sdonn  * we're right at the beginning of the program.
6759678Slinton  */
6769678Slinton 
67718231Slinton public findbeginning (f)
6789678Slinton Symbol f;
6799678Slinton {
68016618Ssam     if (isinternal(f)) {
68133334Sdonn 	f->symvalue.funcv.beginaddr += 18;	/* VAX only */
68216618Ssam     } else {
68333334Sdonn 	f->symvalue.funcv.beginaddr += FUNCOFFSET;
68416618Ssam     }
6859678Slinton }
6869678Slinton 
6879678Slinton /*
6889678Slinton  * Return the address corresponding to the first line in a function.
6899678Slinton  */
6909678Slinton 
6919678Slinton public Address firstline(f)
6929678Slinton Symbol f;
6939678Slinton {
6949678Slinton     Address addr;
6959678Slinton 
6969678Slinton     addr = codeloc(f);
6979678Slinton     while (linelookup(addr) == 0 and addr < objsize) {
6989678Slinton 	++addr;
6999678Slinton     }
7009678Slinton     if (addr == objsize) {
7019678Slinton 	addr = -1;
7029678Slinton     }
7039678Slinton     return addr;
7049678Slinton }
7059678Slinton 
7069678Slinton /*
7079678Slinton  * Catcher drops strike three ...
7089678Slinton  */
7099678Slinton 
7109678Slinton public runtofirst()
7119678Slinton {
71233334Sdonn     Address addr, endaddr;
7139678Slinton 
7149678Slinton     addr = pc;
71533334Sdonn     endaddr = objsize + CODESTART;
71633334Sdonn     while (linelookup(addr) == 0 and addr < endaddr) {
7179678Slinton 	++addr;
7189678Slinton     }
71933334Sdonn     if (addr < endaddr) {
7209678Slinton 	stepto(addr);
7219678Slinton     }
7229678Slinton }
7239678Slinton 
7249678Slinton /*
7259678Slinton  * Return the address corresponding to the end of the program.
7269678Slinton  *
7279678Slinton  * We look for the entry to "exit".
7289678Slinton  */
7299678Slinton 
7309678Slinton public Address lastaddr()
7319678Slinton {
73218231Slinton     Symbol s;
7339678Slinton 
7349678Slinton     s = lookup(identname("exit", true));
7359678Slinton     if (s == nil) {
7369678Slinton 	panic("can't find exit");
7379678Slinton     }
7389678Slinton     return codeloc(s);
7399678Slinton }
7409678Slinton 
7419678Slinton /*
7429678Slinton  * Decide if the given function is currently active.
7439678Slinton  *
7449678Slinton  * We avoid calls to "findframe" during a stack trace for efficiency.
7459678Slinton  * Presumably information evaluated while walking the stack is active.
7469678Slinton  */
7479678Slinton 
74833334Sdonn public Boolean isactive (f)
7499678Slinton Symbol f;
7509678Slinton {
75118231Slinton     Boolean b;
7529678Slinton 
7539678Slinton     if (isfinished(process)) {
7549678Slinton 	b = false;
7559678Slinton     } else {
75633334Sdonn 	if (walkingstack or f == program or f == nil or
7579678Slinton 	  (ismodule(f) and isactive(container(f)))) {
7589678Slinton 	    b = true;
7599678Slinton 	} else {
7609678Slinton 	    b = (Boolean) (findframe(f) != nil);
7619678Slinton 	}
7629678Slinton     }
7639678Slinton     return b;
7649678Slinton }
7659678Slinton 
7669678Slinton /*
7679678Slinton  * Evaluate a call to a procedure.
7689678Slinton  */
7699678Slinton 
77018231Slinton public callproc(exprnode, isfunc)
77118231Slinton Node exprnode;
77218231Slinton boolean isfunc;
7739678Slinton {
77418231Slinton     Node procnode, arglist;
7759678Slinton     Symbol proc;
77618231Slinton     integer argc;
7779678Slinton 
77818231Slinton     procnode = exprnode->value.arg[0];
77918231Slinton     arglist = exprnode->value.arg[1];
7809678Slinton     if (procnode->op != O_SYM) {
7819678Slinton 	beginerrmsg();
7829678Slinton 	fprintf(stderr, "can't call \"");
7839678Slinton 	prtree(stderr, procnode);
7849678Slinton 	fprintf(stderr, "\"");
7859678Slinton 	enderrmsg();
7869678Slinton     }
7879678Slinton     assert(procnode->op == O_SYM);
7889678Slinton     proc = procnode->value.sym;
7899678Slinton     if (not isblock(proc)) {
7909678Slinton 	error("\"%s\" is not a procedure or function", symname(proc));
7919678Slinton     }
79218231Slinton     endproc.isfunc = isfunc;
79318231Slinton     endproc.callnode = exprnode;
79418231Slinton     endproc.cmdnode = topnode;
7959678Slinton     pushenv();
7969678Slinton     pc = codeloc(proc);
7979678Slinton     argc = pushargs(proc, arglist);
79833334Sdonn     setreg(FRP, 1);	/* have to ensure it's non-zero for return_addr() */
7999678Slinton     beginproc(proc, argc);
80018231Slinton     event_once(
80118231Slinton 	build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)),
80218231Slinton 	buildcmdlist(build(O_PROCRTN, proc))
80318231Slinton     );
80418231Slinton     isstopped = false;
80518231Slinton     if (not bpact()) {
80618231Slinton 	isstopped = true;
80718231Slinton 	cont(0);
80818231Slinton     }
80918231Slinton     /*
81018231Slinton      * bpact() won't return true, it will call printstatus() and go back
81118231Slinton      * to command input if a breakpoint is found.
81218231Slinton      */
8139678Slinton     /* NOTREACHED */
8149678Slinton }
8159678Slinton 
8169678Slinton /*
8179678Slinton  * Push the arguments on the process' stack.  We do this by first
8189678Slinton  * evaluating them on the "eval" stack, then copying into the process'
8199678Slinton  * space.
8209678Slinton  */
8219678Slinton 
82218231Slinton private integer pushargs(proc, arglist)
8239678Slinton Symbol proc;
8249678Slinton Node arglist;
8259678Slinton {
8269678Slinton     Stack *savesp;
8279678Slinton     int argc, args_size;
8289678Slinton 
8299678Slinton     savesp = sp;
83026324Ssam     if (varIsSet("$unsafecall")) {
83126324Ssam 	argc = unsafe_evalargs(proc, arglist);
83226324Ssam     } else {
83326324Ssam 	argc = evalargs(proc, arglist);
83426324Ssam     }
8359678Slinton     args_size = sp - savesp;
8369678Slinton     setreg(STKP, reg(STKP) - args_size);
8379678Slinton     dwrite(savesp, reg(STKP), args_size);
8389678Slinton     sp = savesp;
8399678Slinton     return argc;
8409678Slinton }
8419678Slinton 
8429678Slinton /*
84316618Ssam  * Check to see if an expression is correct for a given parameter.
84416618Ssam  * If the given parameter is false, don't worry about type inconsistencies.
84516618Ssam  *
84616618Ssam  * Return whether or not it is ok.
8479678Slinton  */
8489678Slinton 
84916618Ssam private boolean chkparam (actual, formal, chk)
85016618Ssam Node actual;
85116618Ssam Symbol formal;
85216618Ssam boolean chk;
85316618Ssam {
85416618Ssam     boolean b;
85516618Ssam 
85616618Ssam     b = true;
85716618Ssam     if (chk) {
85816618Ssam 	if (formal == nil) {
85916618Ssam 	    beginerrmsg();
86016618Ssam 	    fprintf(stderr, "too many parameters");
86116618Ssam 	    b = false;
86216618Ssam 	} else if (not compatible(formal->type, actual->nodetype)) {
86316618Ssam 	    beginerrmsg();
86416618Ssam 	    fprintf(stderr, "type mismatch for %s", symname(formal));
86516618Ssam 	    b = false;
86616618Ssam 	}
86716618Ssam     }
86818231Slinton     if (b and formal != nil and
86918231Slinton 	isvarparam(formal) and not isopenarray(formal->type) and
87018231Slinton 	not (
87118231Slinton 	    actual->op == O_RVAL or actual->nodetype == t_addr or
87218231Slinton 	    (
87318231Slinton 		actual->op == O_TYPERENAME and
87418231Slinton 		(
87518231Slinton 		    actual->value.arg[0]->op == O_RVAL or
87618231Slinton 		    actual->value.arg[0]->nodetype == t_addr
87718231Slinton 		)
87818231Slinton 	    )
87918231Slinton 	)
88018231Slinton     ) {
88116618Ssam 	beginerrmsg();
88216618Ssam 	fprintf(stderr, "expected variable, found \"");
88316618Ssam 	prtree(stderr, actual);
88416618Ssam 	fprintf(stderr, "\"");
88516618Ssam 	b = false;
88616618Ssam     }
88716618Ssam     return b;
88816618Ssam }
88916618Ssam 
89016618Ssam /*
89116618Ssam  * Pass an expression to a particular parameter.
89216618Ssam  *
89316618Ssam  * Normally we pass either the address or value, but in some cases
89416618Ssam  * (such as C strings) we want to copy the value onto the stack and
89516618Ssam  * pass its address.
89618231Slinton  *
89718231Slinton  * Another special case raised by strings is the possibility that
89818231Slinton  * the actual parameter will be larger than the formal, even with
89918231Slinton  * appropriate type-checking.  This occurs because we assume during
90018231Slinton  * evaluation that strings are null-terminated, whereas some languages,
90118231Slinton  * notably Pascal, do not work under that assumption.
90216618Ssam  */
90316618Ssam 
90416618Ssam private passparam (actual, formal)
90516618Ssam Node actual;
90616618Ssam Symbol formal;
90716618Ssam {
90816618Ssam     boolean b;
90916618Ssam     Address addr;
91016618Ssam     Stack *savesp;
91118231Slinton     integer actsize, formsize;
91216618Ssam 
91318231Slinton     if (formal != nil and isvarparam(formal) and
91418231Slinton 	(not isopenarray(formal->type))
91518231Slinton     ) {
91616618Ssam 	addr = lval(actual->value.arg[0]);
91716618Ssam 	push(Address, addr);
91816618Ssam     } else if (passaddr(formal, actual->nodetype)) {
91916618Ssam 	savesp = sp;
92016618Ssam 	eval(actual);
92118231Slinton 	actsize = sp - savesp;
92218231Slinton 	setreg(STKP,
92318231Slinton 	    reg(STKP) - ((actsize + sizeof(Word) - 1) & ~(sizeof(Word) - 1))
92418231Slinton 	);
92518231Slinton 	dwrite(savesp, reg(STKP), actsize);
92616618Ssam 	sp = savesp;
92716618Ssam 	push(Address, reg(STKP));
92816618Ssam 	if (formal != nil and isopenarray(formal->type)) {
92918231Slinton 	    push(integer, actsize div size(formal->type->type));
93016618Ssam 	}
93118231Slinton     } else if (formal != nil) {
93218231Slinton 	formsize = size(formal);
93318231Slinton 	savesp = sp;
93418231Slinton 	eval(actual);
93518231Slinton 	actsize = sp - savesp;
93618231Slinton 	if (actsize > formsize) {
93718231Slinton 	    sp -= (actsize - formsize);
93818231Slinton 	}
93916618Ssam     } else {
94016618Ssam 	eval(actual);
94116618Ssam     }
94216618Ssam }
94316618Ssam 
94416618Ssam /*
94516618Ssam  * Evaluate an argument list left-to-right.
94616618Ssam  */
94716618Ssam 
94818231Slinton private integer evalargs(proc, arglist)
9499678Slinton Symbol proc;
9509678Slinton Node arglist;
9519678Slinton {
95216618Ssam     Node p, actual;
95316618Ssam     Symbol formal;
9549678Slinton     Stack *savesp;
95518231Slinton     integer count;
95616618Ssam     boolean chk;
9579678Slinton 
9589678Slinton     savesp = sp;
9599678Slinton     count = 0;
96016618Ssam     formal = proc->chain;
96116618Ssam     chk = (boolean) (not nosource(proc));
9629678Slinton     for (p = arglist; p != nil; p = p->value.arg[1]) {
96316618Ssam 	assert(p->op == O_COMMA);
96416618Ssam 	actual = p->value.arg[0];
96516618Ssam 	if (not chkparam(actual, formal, chk)) {
96616618Ssam 	    fprintf(stderr, " in call to %s", symname(proc));
9679678Slinton 	    sp = savesp;
96816618Ssam 	    enderrmsg();
9699678Slinton 	}
97016618Ssam 	passparam(actual, formal);
97116618Ssam 	if (formal != nil) {
97216618Ssam 	    formal = formal->chain;
9739678Slinton 	}
9749678Slinton 	++count;
9759678Slinton     }
97616618Ssam     if (chk) {
97716618Ssam 	if (formal != nil) {
97816618Ssam 	    sp = savesp;
97916618Ssam 	    error("not enough parameters to %s", symname(proc));
98016618Ssam 	}
9819678Slinton     }
9829678Slinton     return count;
9839678Slinton }
9849678Slinton 
98526324Ssam /*
98633334Sdonn  * Evaluate an argument list without any type checking.
98733334Sdonn  * This is only useful for procedures with a varying number of
98833334Sdonn  * arguments that are compiled -g.
98926324Ssam  */
99026324Ssam 
99133334Sdonn private integer unsafe_evalargs (proc, arglist)
99226324Ssam Symbol proc;
99326324Ssam Node arglist;
99426324Ssam {
99526324Ssam     Node p;
99633334Sdonn     integer count;
99726324Ssam 
99826324Ssam     count = 0;
99926324Ssam     for (p = arglist; p != nil; p = p->value.arg[1]) {
100026324Ssam 	assert(p->op == O_COMMA);
100126324Ssam 	eval(p->value.arg[0]);
100226324Ssam 	++count;
100326324Ssam     }
100426324Ssam     return count;
100526324Ssam }
100626324Ssam 
10079678Slinton public procreturn(f)
10089678Slinton Symbol f;
10099678Slinton {
101018231Slinton     integer retvalsize;
101118231Slinton     Node tmp;
101218231Slinton     char *copy;
101318231Slinton 
10149678Slinton     flushoutput();
10159678Slinton     popenv();
101618231Slinton     if (endproc.isfunc) {
101718231Slinton 	retvalsize = size(f->type);
101818231Slinton 	if (retvalsize > sizeof(long)) {
101918231Slinton 	    pushretval(retvalsize, true);
102018231Slinton 	    copy = newarr(char, retvalsize);
102118231Slinton 	    popn(retvalsize, copy);
102218231Slinton 	    tmp = build(O_SCON, copy);
102318231Slinton 	} else {
102418231Slinton 	    tmp = build(O_LCON, (long) (reg(0)));
102518231Slinton 	}
102618231Slinton 	tmp->nodetype = f->type;
102718231Slinton 	tfree(endproc.callnode);
102818231Slinton 	*(endproc.callnode) = *(tmp);
102918231Slinton 	dispose(tmp);
103018231Slinton 	eval(endproc.cmdnode);
103118231Slinton     } else {
103218231Slinton 	putchar('\n');
103318231Slinton 	printname(stdout, f);
103433334Sdonn 	printf(" returns successfully\n");
103518231Slinton     }
10369678Slinton     erecover();
10379678Slinton }
10389678Slinton 
10399678Slinton /*
10409678Slinton  * Push the current environment.
10419678Slinton  */
10429678Slinton 
10439678Slinton private pushenv()
10449678Slinton {
10459678Slinton     push(Address, pc);
10469678Slinton     push(Lineno, curline);
10479678Slinton     push(String, cursource);
10489678Slinton     push(Boolean, isstopped);
10499678Slinton     push(Symbol, curfunc);
105016618Ssam     push(Frame, curframe);
105116618Ssam     push(struct Frame, curframerec);
105218231Slinton     push(CallEnv, endproc);
10539678Slinton     push(Word, reg(PROGCTR));
10549678Slinton     push(Word, reg(STKP));
105533334Sdonn     push(Word, reg(FRP));
10569678Slinton }
10579678Slinton 
10589678Slinton /*
10599678Slinton  * Pop back to the real world.
10609678Slinton  */
10619678Slinton 
10629678Slinton public popenv()
10639678Slinton {
106418231Slinton     String filename;
10659678Slinton 
106633334Sdonn     setreg(FRP, pop(Word));
10679678Slinton     setreg(STKP, pop(Word));
10689678Slinton     setreg(PROGCTR, pop(Word));
106918231Slinton     endproc = pop(CallEnv);
107016618Ssam     curframerec = pop(struct Frame);
107116618Ssam     curframe = pop(Frame);
10729678Slinton     curfunc = pop(Symbol);
10739678Slinton     isstopped = pop(Boolean);
10749678Slinton     filename = pop(String);
10759678Slinton     curline = pop(Lineno);
10769678Slinton     pc = pop(Address);
10779678Slinton     setsource(filename);
10789678Slinton }
10799678Slinton 
10809678Slinton /*
10819678Slinton  * Flush the debuggee's standard output.
10829678Slinton  *
10839678Slinton  * This is VERY dependent on the use of stdio.
10849678Slinton  */
10859678Slinton 
10869678Slinton public flushoutput()
10879678Slinton {
108818231Slinton     Symbol p, iob;
108918231Slinton     Stack *savesp;
10909678Slinton 
10919678Slinton     p = lookup(identname("fflush", true));
10929678Slinton     while (p != nil and not isblock(p)) {
10939678Slinton 	p = p->next_sym;
10949678Slinton     }
10959678Slinton     if (p != nil) {
10969678Slinton 	iob = lookup(identname("_iob", true));
10979678Slinton 	if (iob != nil) {
10989678Slinton 	    pushenv();
109933334Sdonn 	    pc = codeloc(p) - FUNCOFFSET;
11009678Slinton 	    savesp = sp;
110133334Sdonn 	    push(long, address(iob, nil) + sizeof(*stdout));
11029678Slinton 	    setreg(STKP, reg(STKP) - sizeof(long));
11039678Slinton 	    dwrite(savesp, reg(STKP), sizeof(long));
11049678Slinton 	    sp = savesp;
11059678Slinton 	    beginproc(p, 1);
11069678Slinton 	    stepto(return_addr());
11079678Slinton 	    popenv();
11089678Slinton 	}
11099678Slinton     }
11109678Slinton }
1111