121621Sdist /*
238105Sbostic * Copyright (c) 1983 The Regents of the University of California.
338105Sbostic * All rights reserved.
438105Sbostic *
542685Sbostic * %sccs.include.redist.c%
621621Sdist */
79678Slinton
821621Sdist #ifndef lint
9*46146Storek static char sccsid[] = "@(#)runtime.vax.c 5.6 (Berkeley) 01/27/91";
1038105Sbostic #endif /* not lint */
119678Slinton
129678Slinton /*
139678Slinton * Runtime organization dependent routines, mostly dealing with
149678Slinton * activation records.
159678Slinton */
169678Slinton
179678Slinton #include "defs.h"
189678Slinton #include "runtime.h"
199678Slinton #include "process.h"
209678Slinton #include "machine.h"
219678Slinton #include "events.h"
229678Slinton #include "mappings.h"
239678Slinton #include "symbols.h"
249678Slinton #include "tree.h"
259678Slinton #include "eval.h"
269678Slinton #include "operators.h"
279678Slinton #include "object.h"
2812546Scsvaf #include <sys/param.h>
2933334Sdonn #include <signal.h>
309678Slinton
319678Slinton #ifndef public
329678Slinton typedef struct Frame *Frame;
339678Slinton
349678Slinton #include "machine.h"
359678Slinton #endif
369678Slinton
379678Slinton #define NSAVEREG 12
389678Slinton
399678Slinton struct Frame {
4018231Slinton integer condition_handler;
4118231Slinton integer mask;
429678Slinton Address save_ap; /* argument pointer */
439678Slinton Address save_fp; /* frame pointer */
449678Slinton Address save_pc; /* program counter */
459678Slinton Word save_reg[NSAVEREG]; /* not necessarily there */
469678Slinton };
479678Slinton
4816618Ssam private Frame curframe = nil;
4916618Ssam private struct Frame curframerec;
509678Slinton private Boolean walkingstack = false;
519678Slinton
5216618Ssam #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp)
5316618Ssam
5433334Sdonn #define inSignalHandler(addr) \
5533334Sdonn (((addr) < 0x80000000) and ((addr) > 0x80000000 - ctob(UPAGES)))
5618231Slinton
5718231Slinton typedef struct {
5818231Slinton Node callnode;
5918231Slinton Node cmdnode;
6018231Slinton boolean isfunc;
6118231Slinton } CallEnv;
6218231Slinton
6318231Slinton private CallEnv endproc;
6418231Slinton
659678Slinton /*
669678Slinton * Set a frame to the current activation record.
679678Slinton */
689678Slinton
getcurframe(frp)699678Slinton private getcurframe(frp)
7018231Slinton Frame frp;
719678Slinton {
729678Slinton register int i;
739678Slinton
749678Slinton checkref(frp);
759678Slinton frp->mask = reg(NREG);
769678Slinton frp->save_ap = reg(ARGP);
779678Slinton frp->save_fp = reg(FRP);
7818231Slinton frp->save_pc = reg(PROGCTR);
799678Slinton for (i = 0; i < NSAVEREG; i++) {
809678Slinton frp->save_reg[i] = reg(i);
819678Slinton }
829678Slinton }
839678Slinton
849678Slinton /*
8518231Slinton * Get the saved registers from one frame to another
8618231Slinton * given mask specifying which registers were actually saved.
8718231Slinton */
8818231Slinton
8918231Slinton #define bis(b, n) ((b & (1 << (n))) != 0)
9018231Slinton
getsaveregs(newfrp,frp,mask)9118231Slinton private getsaveregs (newfrp, frp, mask)
9218231Slinton Frame newfrp, frp;
9318231Slinton integer mask;
9418231Slinton {
9518231Slinton integer i, j;
9618231Slinton
9718231Slinton j = 0;
9818231Slinton for (i = 0; i < NSAVEREG; i++) {
9918231Slinton if (bis(mask, i)) {
10018231Slinton newfrp->save_reg[i] = frp->save_reg[j];
10118231Slinton ++j;
10218231Slinton }
10318231Slinton }
10418231Slinton }
10518231Slinton
10618231Slinton /*
1079678Slinton * Return a pointer to the next activation record up the stack.
1089678Slinton * Return nil if there is none.
1099678Slinton * Writes over space pointed to by given argument.
1109678Slinton */
1119678Slinton
nextframe(frp)1129678Slinton private Frame nextframe(frp)
1139678Slinton Frame frp;
1149678Slinton {
11518231Slinton Frame newfrp;
1169678Slinton struct Frame frame;
11718231Slinton integer mask;
11833334Sdonn Address prev_frame, callpc;
11918231Slinton static integer ntramp = 0;
1209678Slinton
1219678Slinton newfrp = frp;
12212546Scsvaf prev_frame = frp->save_fp;
12312546Scsvaf
12413937Slinton /*
12513937Slinton * The check for interrupt generated frames is taken from adb with only
12613937Slinton * partial understanding. If you're in "sub" and on a sigxxx "sigsub"
12713937Slinton * gets control, then the stack does NOT look like <main, sub, sigsub>.
12812546Scsvaf *
12912546Scsvaf * As best I can make out it looks like:
13012546Scsvaf *
13113937Slinton * <main, (machine check exception block + sub), sysframe, sigsub>.
13213937Slinton *
13313937Slinton * When the signal occurs an exception block and a frame for the routine
13413937Slinton * in which it occured are pushed on the user stack. Then another frame
13513937Slinton * is pushed corresponding to a call from the kernel to sigsub.
13613937Slinton *
13712546Scsvaf * The addr in sub at which the exception occured is not in sub.save_pc
13813937Slinton * but in the machine check exception block. It is at the magic address
13914620Ssam * fp + 84.
14012546Scsvaf *
14112546Scsvaf * The current approach ignores the sys_frame (what adb reports as sigtramp)
14213937Slinton * and takes the pc for sub from the exception block. This allows the
14313937Slinton * "where" command to report <main, sub, sigsub>, which seems reasonable.
14412546Scsvaf */
14512546Scsvaf
14613937Slinton nextf:
14733334Sdonn if (prev_frame + sizeof(struct Frame) <= USRSTACK) {
14833334Sdonn dread(&frame, prev_frame, sizeof(struct Frame));
14933334Sdonn } else if (USRSTACK - prev_frame > 2 * sizeof(Word)) {
15033334Sdonn dread(&frame, prev_frame, USRSTACK - prev_frame);
15133334Sdonn } else {
15233334Sdonn frame.save_fp = nil;
15333334Sdonn }
15413937Slinton if (ntramp == 1) {
15533334Sdonn dread(&callpc, prev_frame + 92, sizeof(callpc));
15613937Slinton } else {
15713937Slinton callpc = frame.save_pc;
15813937Slinton }
15918231Slinton if (frame.save_fp == nil or frame.save_pc == (Address) -1) {
1609678Slinton newfrp = nil;
16113937Slinton } else {
16233334Sdonn if (inSignalHandler(callpc)) {
16333334Sdonn ntramp++;
16433334Sdonn prev_frame = frame.save_fp;
16533334Sdonn goto nextf;
16633334Sdonn }
16712546Scsvaf frame.save_pc = callpc;
16813937Slinton ntramp = 0;
16933334Sdonn newfrp->save_fp = frame.save_fp;
17033334Sdonn newfrp->save_pc = frame.save_pc;
1719678Slinton mask = ((frame.mask >> 16) & 0x0fff);
17218231Slinton getsaveregs(newfrp, &frame, mask);
1739678Slinton newfrp->condition_handler = frame.condition_handler;
1749678Slinton newfrp->mask = mask;
1759678Slinton newfrp->save_ap = frame.save_ap;
1769678Slinton }
1779678Slinton return newfrp;
1789678Slinton }
1799678Slinton
1809678Slinton /*
18116618Ssam * Get the current frame information in the given Frame and store the
18216618Ssam * associated function in the given value-result parameter.
18316618Ssam */
18416618Ssam
getcurfunc(frp,fp)18516618Ssam private getcurfunc (frp, fp)
18616618Ssam Frame frp;
18716618Ssam Symbol *fp;
18816618Ssam {
18916618Ssam getcurframe(frp);
19016618Ssam *fp = whatblock(frp->save_pc);
19116618Ssam }
19216618Ssam
19316618Ssam /*
19416618Ssam * Return the frame associated with the next function up the call stack, or
19516618Ssam * nil if there is none. The function is returned in a value-result parameter.
19616618Ssam * For "inline" functions the statically outer function and same frame
19716618Ssam * are returned.
19816618Ssam */
19916618Ssam
nextfunc(frp,fp)20018231Slinton public Frame nextfunc (frp, fp)
20116618Ssam Frame frp;
20216618Ssam Symbol *fp;
20316618Ssam {
20416618Ssam Symbol t;
20516618Ssam Frame nfrp;
20616618Ssam
20716618Ssam t = *fp;
20816618Ssam checkref(t);
20916618Ssam if (isinline(t)) {
21016618Ssam t = container(t);
21116618Ssam nfrp = frp;
21216618Ssam } else {
21316618Ssam nfrp = nextframe(frp);
21416618Ssam if (nfrp == nil) {
21516618Ssam t = nil;
21616618Ssam } else {
21716618Ssam t = whatblock(nfrp->save_pc);
21816618Ssam }
21916618Ssam }
22016618Ssam *fp = t;
22116618Ssam return nfrp;
22216618Ssam }
22316618Ssam
22416618Ssam /*
2259678Slinton * Return the frame associated with the given function.
2269678Slinton * If the function is nil, return the most recently activated frame.
2279678Slinton *
2289678Slinton * Static allocation for the frame.
2299678Slinton */
2309678Slinton
findframe(f)2319678Slinton public Frame findframe(f)
2329678Slinton Symbol f;
2339678Slinton {
23418231Slinton Frame frp;
2359678Slinton static struct Frame frame;
23611866Slinton Symbol p;
23718231Slinton Boolean done;
2389678Slinton
2399678Slinton frp = &frame;
2409678Slinton getcurframe(frp);
24118231Slinton if (f != nil) {
24218231Slinton if (f == curfunc and curframe != nil) {
24318231Slinton *frp = *curframe;
24418231Slinton } else {
24518231Slinton done = false;
24618231Slinton p = whatblock(frp->save_pc);
24718231Slinton do {
24818231Slinton if (p == f) {
24918231Slinton done = true;
25018231Slinton } else if (p == program) {
25118231Slinton done = true;
25218231Slinton frp = nil;
25318231Slinton } else {
25418231Slinton frp = nextfunc(frp, &p);
25518231Slinton if (frp == nil) {
25618231Slinton done = true;
25718231Slinton }
25818231Slinton }
25918231Slinton } while (not done);
26015784Ssam }
26118231Slinton }
26218231Slinton return frp;
26318231Slinton }
26418231Slinton
26518231Slinton /*
26618231Slinton * Set the registers according to the given frame pointer.
26718231Slinton */
26818231Slinton
getnewregs(addr)26918231Slinton public getnewregs (addr)
27018231Slinton Address addr;
27118231Slinton {
27218231Slinton struct Frame frame;
27318231Slinton integer i, j, mask;
27418231Slinton
27518231Slinton dread(&frame, addr, sizeof(frame));
27618231Slinton setreg(FRP, frame.save_fp);
27718231Slinton setreg(PROGCTR, frame.save_pc);
27833334Sdonn setreg(ARGP, frame.save_ap);
27918231Slinton mask = ((frame.mask >> 16) & 0x0fff);
28018231Slinton j = 0;
28118231Slinton for (i = 0; i < NSAVEREG; i++) {
28218231Slinton if (bis(mask, i)) {
28333334Sdonn setreg(i, frame.save_reg[j]);
28433334Sdonn ++j;
28516636Ssam }
2869678Slinton }
28718231Slinton pc = frame.save_pc;
28818231Slinton setcurfunc(whatblock(pc));
2899678Slinton }
2909678Slinton
2919678Slinton /*
2929678Slinton * Find the return address of the current procedure/function.
2939678Slinton */
2949678Slinton
return_addr()2959678Slinton public Address return_addr()
2969678Slinton {
2979678Slinton Frame frp;
2989678Slinton Address addr;
2999678Slinton struct Frame frame;
3009678Slinton
3019678Slinton frp = &frame;
3029678Slinton getcurframe(frp);
3039678Slinton frp = nextframe(frp);
3049678Slinton if (frp == nil) {
3059678Slinton addr = 0;
3069678Slinton } else {
3079678Slinton addr = frp->save_pc;
3089678Slinton }
3099678Slinton return addr;
3109678Slinton }
3119678Slinton
3129678Slinton /*
3139678Slinton * Push the value associated with the current function.
3149678Slinton */
3159678Slinton
pushretval(len,isindirect)3169678Slinton public pushretval(len, isindirect)
31718231Slinton integer len;
31818231Slinton boolean isindirect;
3199678Slinton {
3209678Slinton Word r0;
3219678Slinton
3229678Slinton r0 = reg(0);
3239678Slinton if (isindirect) {
3249678Slinton rpush((Address) r0, len);
3259678Slinton } else {
3269678Slinton switch (len) {
3279678Slinton case sizeof(char):
3289678Slinton push(char, r0);
3299678Slinton break;
3309678Slinton
3319678Slinton case sizeof(short):
3329678Slinton push(short, r0);
3339678Slinton break;
3349678Slinton
3359678Slinton default:
3369678Slinton if (len == sizeof(Word)) {
3379678Slinton push(Word, r0);
3389678Slinton } else if (len == 2*sizeof(Word)) {
3399678Slinton push(Word, r0);
3409678Slinton push(Word, reg(1));
3419678Slinton } else {
34218231Slinton error("[internal error: bad size %d in pushretval]", len);
3439678Slinton }
3449678Slinton break;
3459678Slinton }
3469678Slinton }
3479678Slinton }
3489678Slinton
3499678Slinton /*
3509678Slinton * Return the base address for locals in the given frame.
3519678Slinton */
3529678Slinton
locals_base(frp)3539678Slinton public Address locals_base(frp)
35418231Slinton Frame frp;
3559678Slinton {
3569678Slinton return (frp == nil) ? reg(FRP) : frp->save_fp;
3579678Slinton }
3589678Slinton
3599678Slinton /*
3609678Slinton * Return the base address for arguments in the given frame.
3619678Slinton */
3629678Slinton
args_base(frp)3639678Slinton public Address args_base(frp)
36418231Slinton Frame frp;
3659678Slinton {
3669678Slinton return (frp == nil) ? reg(ARGP) : frp->save_ap;
3679678Slinton }
3689678Slinton
3699678Slinton /*
3709678Slinton * Return saved register n from the given frame.
3719678Slinton */
3729678Slinton
savereg(n,frp)3739678Slinton public Word savereg(n, frp)
37418231Slinton integer n;
37518231Slinton Frame frp;
3769678Slinton {
37718231Slinton Word w;
3789678Slinton
3799678Slinton if (frp == nil) {
3809678Slinton w = reg(n);
3819678Slinton } else {
3829678Slinton switch (n) {
3839678Slinton case ARGP:
3849678Slinton w = frp->save_ap;
3859678Slinton break;
3869678Slinton
3879678Slinton case FRP:
3889678Slinton w = frp->save_fp;
3899678Slinton break;
3909678Slinton
3919678Slinton case STKP:
3929678Slinton w = reg(STKP);
3939678Slinton break;
3949678Slinton
3959678Slinton case PROGCTR:
3969678Slinton w = frp->save_pc;
3979678Slinton break;
3989678Slinton
3999678Slinton default:
4009678Slinton assert(n >= 0 and n < NSAVEREG);
4019678Slinton w = frp->save_reg[n];
4029678Slinton break;
4039678Slinton }
4049678Slinton }
4059678Slinton return w;
4069678Slinton }
4079678Slinton
4089678Slinton /*
4099678Slinton * Return the nth argument to the current procedure.
4109678Slinton */
4119678Slinton
argn(n,frp)4129678Slinton public Word argn(n, frp)
41318231Slinton integer n;
4149678Slinton Frame frp;
4159678Slinton {
41633334Sdonn Address argaddr;
4179678Slinton Word w;
4189678Slinton
41933334Sdonn argaddr = args_base(frp) + (n * sizeof(Word));
42033334Sdonn dread(&w, argaddr, sizeof(w));
4219678Slinton return w;
4229678Slinton }
4239678Slinton
4249678Slinton /*
42518231Slinton * Print a list of currently active blocks starting with most recent.
4269678Slinton */
4279678Slinton
wherecmd()42818231Slinton public wherecmd()
4299678Slinton {
43018231Slinton walkstack(false);
4319678Slinton }
4329678Slinton
4339678Slinton /*
43418231Slinton * Print the variables in the given frame or the current one if nil.
4359678Slinton */
4369678Slinton
dump(func)43718231Slinton public dump (func)
43818231Slinton Symbol func;
4399678Slinton {
44018231Slinton Symbol f;
44118231Slinton Frame frp;
44218231Slinton
44318231Slinton if (func == nil) {
44418231Slinton f = curfunc;
44518231Slinton if (curframe != nil) {
44618231Slinton frp = curframe;
44718231Slinton } else {
44818231Slinton frp = findframe(f);
44918231Slinton }
45018231Slinton } else {
45118231Slinton f = func;
45218231Slinton frp = findframe(f);
45318231Slinton }
45418231Slinton showaggrs = true;
45518231Slinton printcallinfo(f, frp);
45618231Slinton dumpvars(f, frp);
4579678Slinton }
4589678Slinton
4599678Slinton /*
46018231Slinton * Dump all values.
4619678Slinton */
4629678Slinton
dumpall()46318231Slinton public dumpall ()
4649678Slinton {
4659678Slinton walkstack(true);
4669678Slinton }
4679678Slinton
4689678Slinton /*
4699678Slinton * Walk the stack of active procedures printing information
4709678Slinton * about each active procedure.
4719678Slinton */
4729678Slinton
walkstack(dumpvariables)4739678Slinton private walkstack(dumpvariables)
4749678Slinton Boolean dumpvariables;
4759678Slinton {
47618231Slinton Frame frp;
47718231Slinton boolean save;
47816618Ssam Symbol f;
4799678Slinton struct Frame frame;
4809678Slinton
48118231Slinton if (notstarted(process) or isfinished(process)) {
4829678Slinton error("program is not active");
4839678Slinton } else {
4849678Slinton save = walkingstack;
4859678Slinton walkingstack = true;
48618231Slinton showaggrs = dumpvariables;
4879678Slinton frp = &frame;
48816618Ssam getcurfunc(frp, &f);
48918231Slinton for (;;) {
49018231Slinton printcallinfo(f, frp);
4919678Slinton if (dumpvariables) {
4929678Slinton dumpvars(f, frp);
4939678Slinton putchar('\n');
4949678Slinton }
49516618Ssam frp = nextfunc(frp, &f);
49618231Slinton if (frp == nil or f == program) {
49718231Slinton break;
49818231Slinton }
49918231Slinton }
5009678Slinton if (dumpvariables) {
5019678Slinton printf("in \"%s\":\n", symname(program));
5029678Slinton dumpvars(program, nil);
5039678Slinton putchar('\n');
5049678Slinton }
5059678Slinton walkingstack = save;
5069678Slinton }
5079678Slinton }
5089678Slinton
5099678Slinton /*
51018231Slinton * Print out the information about a call, i.e.,
51118231Slinton * routine name, parameter values, and source location.
51218231Slinton */
51318231Slinton
printcallinfo(f,frp)51418231Slinton private printcallinfo (f, frp)
51518231Slinton Symbol f;
51618231Slinton Frame frp;
51718231Slinton {
51818231Slinton Lineno line;
51918231Slinton Address savepc;
52018231Slinton
52118231Slinton savepc = frp->save_pc;
52218231Slinton if (frp->save_fp != reg(FRP)) {
52318231Slinton savepc -= 1;
52418231Slinton }
52518231Slinton printname(stdout, f);
52618231Slinton if (not isinline(f)) {
52718231Slinton printparams(f, frp);
52818231Slinton }
52918231Slinton line = srcline(savepc);
53018231Slinton if (line != 0) {
53118231Slinton printf(", line %d", line);
53218231Slinton printf(" in \"%s\"\n", srcfilename(savepc));
53318231Slinton } else {
53418231Slinton printf(" at 0x%x\n", savepc);
53518231Slinton }
53618231Slinton }
53718231Slinton
53818231Slinton /*
53916618Ssam * Set the current function to the given symbol.
54016618Ssam * We must adjust "curframe" so that subsequent operations are
54116618Ssam * not confused; for simplicity we simply clear it.
54216618Ssam */
54316618Ssam
setcurfunc(f)54416618Ssam public setcurfunc (f)
54516618Ssam Symbol f;
54616618Ssam {
54716618Ssam curfunc = f;
54816618Ssam curframe = nil;
54916618Ssam }
55016618Ssam
55116618Ssam /*
55218231Slinton * Return the frame for the current function.
55318231Slinton * The space for the frame is allocated statically.
55418231Slinton */
55518231Slinton
curfuncframe()55618231Slinton public Frame curfuncframe ()
55718231Slinton {
55818231Slinton static struct Frame frame;
55918231Slinton Frame frp;
56018231Slinton
56118231Slinton if (curframe == nil) {
56218231Slinton frp = findframe(curfunc);
56318231Slinton curframe = &curframerec;
56418231Slinton *curframe = *frp;
56518231Slinton } else {
56618231Slinton frp = &frame;
56718231Slinton *frp = *curframe;
56818231Slinton }
56918231Slinton return frp;
57018231Slinton }
57118231Slinton
57218231Slinton /*
57316618Ssam * Set curfunc to be N up/down the stack from its current value.
57416618Ssam */
57516618Ssam
up(n)57616618Ssam public up (n)
57716618Ssam integer n;
57816618Ssam {
57916618Ssam integer i;
58016618Ssam Symbol f;
58116618Ssam Frame frp;
58216618Ssam boolean done;
58316618Ssam
58416618Ssam if (not isactive(program)) {
58516618Ssam error("program is not active");
58616618Ssam } else if (curfunc == nil) {
58716618Ssam error("no current function");
58816618Ssam } else {
58916618Ssam i = 0;
59016618Ssam f = curfunc;
59118231Slinton frp = curfuncframe();
59216618Ssam done = false;
59316618Ssam do {
59416618Ssam if (frp == nil) {
59516618Ssam done = true;
59616618Ssam error("not that many levels");
59716618Ssam } else if (i >= n) {
59816618Ssam done = true;
59916618Ssam curfunc = f;
60016618Ssam curframe = &curframerec;
60116618Ssam *curframe = *frp;
60218231Slinton showaggrs = false;
60318231Slinton printcallinfo(curfunc, curframe);
60416618Ssam } else if (f == program) {
60516618Ssam done = true;
60616618Ssam error("not that many levels");
60716618Ssam } else {
60816618Ssam frp = nextfunc(frp, &f);
60916618Ssam }
61016618Ssam ++i;
61116618Ssam } while (not done);
61216618Ssam }
61316618Ssam }
61416618Ssam
down(n)61516618Ssam public down (n)
61616618Ssam integer n;
61716618Ssam {
61816618Ssam integer i, depth;
61918231Slinton Frame frp, curfrp;
62016618Ssam Symbol f;
62116618Ssam struct Frame frame;
62216618Ssam
62316618Ssam if (not isactive(program)) {
62416618Ssam error("program is not active");
62516618Ssam } else if (curfunc == nil) {
62616618Ssam error("no current function");
62716618Ssam } else {
62816618Ssam depth = 0;
62916618Ssam frp = &frame;
63016618Ssam getcurfunc(frp, &f);
63116618Ssam if (curframe == nil) {
63218231Slinton curfrp = findframe(curfunc);
63316618Ssam curframe = &curframerec;
63418231Slinton *curframe = *curfrp;
63516618Ssam }
63616618Ssam while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) {
63716618Ssam frp = nextfunc(frp, &f);
63816618Ssam ++depth;
63916618Ssam }
64016618Ssam if (f == nil or n > depth) {
64116618Ssam error("not that many levels");
64216618Ssam } else {
64316618Ssam depth -= n;
64416618Ssam frp = &frame;
64516618Ssam getcurfunc(frp, &f);
64616618Ssam for (i = 0; i < depth; i++) {
64716618Ssam frp = nextfunc(frp, &f);
64816618Ssam assert(frp != nil);
64916618Ssam }
65016618Ssam curfunc = f;
65116618Ssam *curframe = *frp;
65218231Slinton showaggrs = false;
65318231Slinton printcallinfo(curfunc, curframe);
65416618Ssam }
65516618Ssam }
65616618Ssam }
65716618Ssam
65816618Ssam /*
6599678Slinton * Find the entry point of a procedure or function.
66033334Sdonn *
66133334Sdonn * On the VAX we add the size of the register mask (FUNCOFFSET) or
66233334Sdonn * the size of the Modula-2 internal entry sequence, on other machines
66333334Sdonn * (68000's) we add the entry sequence size (FUNCOFFSET) unless
66433334Sdonn * we're right at the beginning of the program.
6659678Slinton */
6669678Slinton
findbeginning(f)66718231Slinton public findbeginning (f)
6689678Slinton Symbol f;
6699678Slinton {
67016618Ssam if (isinternal(f)) {
67133334Sdonn f->symvalue.funcv.beginaddr += 18; /* VAX only */
67216618Ssam } else {
67333334Sdonn f->symvalue.funcv.beginaddr += FUNCOFFSET;
67416618Ssam }
6759678Slinton }
6769678Slinton
6779678Slinton /*
6789678Slinton * Return the address corresponding to the first line in a function.
6799678Slinton */
6809678Slinton
firstline(f)6819678Slinton public Address firstline(f)
6829678Slinton Symbol f;
6839678Slinton {
6849678Slinton Address addr;
6859678Slinton
6869678Slinton addr = codeloc(f);
6879678Slinton while (linelookup(addr) == 0 and addr < objsize) {
6889678Slinton ++addr;
6899678Slinton }
6909678Slinton if (addr == objsize) {
6919678Slinton addr = -1;
6929678Slinton }
6939678Slinton return addr;
6949678Slinton }
6959678Slinton
6969678Slinton /*
6979678Slinton * Catcher drops strike three ...
6989678Slinton */
6999678Slinton
runtofirst()7009678Slinton public runtofirst()
7019678Slinton {
70233334Sdonn Address addr, endaddr;
7039678Slinton
7049678Slinton addr = pc;
70533334Sdonn endaddr = objsize + CODESTART;
70633334Sdonn while (linelookup(addr) == 0 and addr < endaddr) {
7079678Slinton ++addr;
7089678Slinton }
70933334Sdonn if (addr < endaddr) {
7109678Slinton stepto(addr);
7119678Slinton }
7129678Slinton }
7139678Slinton
7149678Slinton /*
7159678Slinton * Return the address corresponding to the end of the program.
7169678Slinton *
7179678Slinton * We look for the entry to "exit".
7189678Slinton */
7199678Slinton
lastaddr()7209678Slinton public Address lastaddr()
7219678Slinton {
72218231Slinton Symbol s;
7239678Slinton
7249678Slinton s = lookup(identname("exit", true));
7259678Slinton if (s == nil) {
7269678Slinton panic("can't find exit");
7279678Slinton }
7289678Slinton return codeloc(s);
7299678Slinton }
7309678Slinton
7319678Slinton /*
7329678Slinton * Decide if the given function is currently active.
7339678Slinton *
7349678Slinton * We avoid calls to "findframe" during a stack trace for efficiency.
7359678Slinton * Presumably information evaluated while walking the stack is active.
7369678Slinton */
7379678Slinton
isactive(f)73833334Sdonn public Boolean isactive (f)
7399678Slinton Symbol f;
7409678Slinton {
74118231Slinton Boolean b;
7429678Slinton
7439678Slinton if (isfinished(process)) {
7449678Slinton b = false;
7459678Slinton } else {
74633334Sdonn if (walkingstack or f == program or f == nil or
7479678Slinton (ismodule(f) and isactive(container(f)))) {
7489678Slinton b = true;
7499678Slinton } else {
7509678Slinton b = (Boolean) (findframe(f) != nil);
7519678Slinton }
7529678Slinton }
7539678Slinton return b;
7549678Slinton }
7559678Slinton
7569678Slinton /*
7579678Slinton * Evaluate a call to a procedure.
7589678Slinton */
7599678Slinton
callproc(exprnode,isfunc)76018231Slinton public callproc(exprnode, isfunc)
76118231Slinton Node exprnode;
76218231Slinton boolean isfunc;
7639678Slinton {
76418231Slinton Node procnode, arglist;
7659678Slinton Symbol proc;
76618231Slinton integer argc;
7679678Slinton
76818231Slinton procnode = exprnode->value.arg[0];
76918231Slinton arglist = exprnode->value.arg[1];
7709678Slinton if (procnode->op != O_SYM) {
7719678Slinton beginerrmsg();
7729678Slinton fprintf(stderr, "can't call \"");
7739678Slinton prtree(stderr, procnode);
7749678Slinton fprintf(stderr, "\"");
7759678Slinton enderrmsg();
7769678Slinton }
7779678Slinton assert(procnode->op == O_SYM);
7789678Slinton proc = procnode->value.sym;
7799678Slinton if (not isblock(proc)) {
7809678Slinton error("\"%s\" is not a procedure or function", symname(proc));
7819678Slinton }
78218231Slinton endproc.isfunc = isfunc;
78318231Slinton endproc.callnode = exprnode;
78418231Slinton endproc.cmdnode = topnode;
7859678Slinton pushenv();
7869678Slinton pc = codeloc(proc);
7879678Slinton argc = pushargs(proc, arglist);
78833334Sdonn setreg(FRP, 1); /* have to ensure it's non-zero for return_addr() */
7899678Slinton beginproc(proc, argc);
79018231Slinton event_once(
79118231Slinton build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)),
79218231Slinton buildcmdlist(build(O_PROCRTN, proc))
79318231Slinton );
79418231Slinton isstopped = false;
79518231Slinton if (not bpact()) {
79618231Slinton isstopped = true;
79718231Slinton cont(0);
79818231Slinton }
79918231Slinton /*
80018231Slinton * bpact() won't return true, it will call printstatus() and go back
80118231Slinton * to command input if a breakpoint is found.
80218231Slinton */
8039678Slinton /* NOTREACHED */
8049678Slinton }
8059678Slinton
8069678Slinton /*
8079678Slinton * Push the arguments on the process' stack. We do this by first
8089678Slinton * evaluating them on the "eval" stack, then copying into the process'
8099678Slinton * space.
8109678Slinton */
8119678Slinton
pushargs(proc,arglist)81218231Slinton private integer pushargs(proc, arglist)
8139678Slinton Symbol proc;
8149678Slinton Node arglist;
8159678Slinton {
8169678Slinton Stack *savesp;
8179678Slinton int argc, args_size;
8189678Slinton
8199678Slinton savesp = sp;
82026324Ssam if (varIsSet("$unsafecall")) {
82126324Ssam argc = unsafe_evalargs(proc, arglist);
82226324Ssam } else {
82326324Ssam argc = evalargs(proc, arglist);
82426324Ssam }
8259678Slinton args_size = sp - savesp;
8269678Slinton setreg(STKP, reg(STKP) - args_size);
8279678Slinton dwrite(savesp, reg(STKP), args_size);
8289678Slinton sp = savesp;
8299678Slinton return argc;
8309678Slinton }
8319678Slinton
8329678Slinton /*
83316618Ssam * Check to see if an expression is correct for a given parameter.
83416618Ssam * If the given parameter is false, don't worry about type inconsistencies.
83516618Ssam *
83616618Ssam * Return whether or not it is ok.
8379678Slinton */
8389678Slinton
chkparam(actual,formal,chk)83916618Ssam private boolean chkparam (actual, formal, chk)
84016618Ssam Node actual;
84116618Ssam Symbol formal;
84216618Ssam boolean chk;
84316618Ssam {
84416618Ssam boolean b;
84516618Ssam
84616618Ssam b = true;
84716618Ssam if (chk) {
84816618Ssam if (formal == nil) {
84916618Ssam beginerrmsg();
85016618Ssam fprintf(stderr, "too many parameters");
85116618Ssam b = false;
85216618Ssam } else if (not compatible(formal->type, actual->nodetype)) {
85316618Ssam beginerrmsg();
85416618Ssam fprintf(stderr, "type mismatch for %s", symname(formal));
85516618Ssam b = false;
85616618Ssam }
85716618Ssam }
85818231Slinton if (b and formal != nil and
85918231Slinton isvarparam(formal) and not isopenarray(formal->type) and
86018231Slinton not (
86118231Slinton actual->op == O_RVAL or actual->nodetype == t_addr or
86218231Slinton (
86318231Slinton actual->op == O_TYPERENAME and
86418231Slinton (
86518231Slinton actual->value.arg[0]->op == O_RVAL or
86618231Slinton actual->value.arg[0]->nodetype == t_addr
86718231Slinton )
86818231Slinton )
86918231Slinton )
87018231Slinton ) {
87116618Ssam beginerrmsg();
87216618Ssam fprintf(stderr, "expected variable, found \"");
87316618Ssam prtree(stderr, actual);
87416618Ssam fprintf(stderr, "\"");
87516618Ssam b = false;
87616618Ssam }
87716618Ssam return b;
87816618Ssam }
87916618Ssam
88016618Ssam /*
88116618Ssam * Pass an expression to a particular parameter.
88216618Ssam *
88316618Ssam * Normally we pass either the address or value, but in some cases
88416618Ssam * (such as C strings) we want to copy the value onto the stack and
88516618Ssam * pass its address.
88618231Slinton *
88718231Slinton * Another special case raised by strings is the possibility that
88818231Slinton * the actual parameter will be larger than the formal, even with
88918231Slinton * appropriate type-checking. This occurs because we assume during
89018231Slinton * evaluation that strings are null-terminated, whereas some languages,
89118231Slinton * notably Pascal, do not work under that assumption.
89216618Ssam */
89316618Ssam
passparam(actual,formal)89416618Ssam private passparam (actual, formal)
89516618Ssam Node actual;
89616618Ssam Symbol formal;
89716618Ssam {
89816618Ssam boolean b;
89916618Ssam Address addr;
90016618Ssam Stack *savesp;
90118231Slinton integer actsize, formsize;
90216618Ssam
90318231Slinton if (formal != nil and isvarparam(formal) and
90418231Slinton (not isopenarray(formal->type))
90518231Slinton ) {
90616618Ssam addr = lval(actual->value.arg[0]);
90716618Ssam push(Address, addr);
90816618Ssam } else if (passaddr(formal, actual->nodetype)) {
90916618Ssam savesp = sp;
91016618Ssam eval(actual);
91118231Slinton actsize = sp - savesp;
91218231Slinton setreg(STKP,
91318231Slinton reg(STKP) - ((actsize + sizeof(Word) - 1) & ~(sizeof(Word) - 1))
91418231Slinton );
91518231Slinton dwrite(savesp, reg(STKP), actsize);
91616618Ssam sp = savesp;
91716618Ssam push(Address, reg(STKP));
91816618Ssam if (formal != nil and isopenarray(formal->type)) {
91918231Slinton push(integer, actsize div size(formal->type->type));
92016618Ssam }
92118231Slinton } else if (formal != nil) {
92218231Slinton formsize = size(formal);
92318231Slinton savesp = sp;
92418231Slinton eval(actual);
92518231Slinton actsize = sp - savesp;
92618231Slinton if (actsize > formsize) {
92718231Slinton sp -= (actsize - formsize);
92818231Slinton }
92916618Ssam } else {
93016618Ssam eval(actual);
93116618Ssam }
93216618Ssam }
93316618Ssam
93416618Ssam /*
93516618Ssam * Evaluate an argument list left-to-right.
93616618Ssam */
93716618Ssam
evalargs(proc,arglist)93818231Slinton private integer evalargs(proc, arglist)
9399678Slinton Symbol proc;
9409678Slinton Node arglist;
9419678Slinton {
94216618Ssam Node p, actual;
94316618Ssam Symbol formal;
9449678Slinton Stack *savesp;
94518231Slinton integer count;
94616618Ssam boolean chk;
9479678Slinton
9489678Slinton savesp = sp;
9499678Slinton count = 0;
95016618Ssam formal = proc->chain;
95116618Ssam chk = (boolean) (not nosource(proc));
9529678Slinton for (p = arglist; p != nil; p = p->value.arg[1]) {
95316618Ssam assert(p->op == O_COMMA);
95416618Ssam actual = p->value.arg[0];
95516618Ssam if (not chkparam(actual, formal, chk)) {
95616618Ssam fprintf(stderr, " in call to %s", symname(proc));
9579678Slinton sp = savesp;
95816618Ssam enderrmsg();
9599678Slinton }
96016618Ssam passparam(actual, formal);
96116618Ssam if (formal != nil) {
96216618Ssam formal = formal->chain;
9639678Slinton }
9649678Slinton ++count;
9659678Slinton }
96616618Ssam if (chk) {
96716618Ssam if (formal != nil) {
96816618Ssam sp = savesp;
96916618Ssam error("not enough parameters to %s", symname(proc));
97016618Ssam }
9719678Slinton }
9729678Slinton return count;
9739678Slinton }
9749678Slinton
97526324Ssam /*
97633334Sdonn * Evaluate an argument list without any type checking.
97733334Sdonn * This is only useful for procedures with a varying number of
97833334Sdonn * arguments that are compiled -g.
97926324Ssam */
98026324Ssam
unsafe_evalargs(proc,arglist)98133334Sdonn private integer unsafe_evalargs (proc, arglist)
98226324Ssam Symbol proc;
98326324Ssam Node arglist;
98426324Ssam {
98526324Ssam Node p;
98633334Sdonn integer count;
98726324Ssam
98826324Ssam count = 0;
98926324Ssam for (p = arglist; p != nil; p = p->value.arg[1]) {
99026324Ssam assert(p->op == O_COMMA);
99126324Ssam eval(p->value.arg[0]);
99226324Ssam ++count;
99326324Ssam }
99426324Ssam return count;
99526324Ssam }
99626324Ssam
procreturn(f)9979678Slinton public procreturn(f)
9989678Slinton Symbol f;
9999678Slinton {
100018231Slinton integer retvalsize;
100118231Slinton Node tmp;
100218231Slinton char *copy;
100318231Slinton
10049678Slinton flushoutput();
10059678Slinton popenv();
100618231Slinton if (endproc.isfunc) {
100718231Slinton retvalsize = size(f->type);
100818231Slinton if (retvalsize > sizeof(long)) {
100918231Slinton pushretval(retvalsize, true);
101018231Slinton copy = newarr(char, retvalsize);
101118231Slinton popn(retvalsize, copy);
101218231Slinton tmp = build(O_SCON, copy);
101318231Slinton } else {
101418231Slinton tmp = build(O_LCON, (long) (reg(0)));
101518231Slinton }
101618231Slinton tmp->nodetype = f->type;
101718231Slinton tfree(endproc.callnode);
101818231Slinton *(endproc.callnode) = *(tmp);
101918231Slinton dispose(tmp);
102018231Slinton eval(endproc.cmdnode);
102118231Slinton } else {
102218231Slinton putchar('\n');
102318231Slinton printname(stdout, f);
102433334Sdonn printf(" returns successfully\n");
102518231Slinton }
10269678Slinton erecover();
10279678Slinton }
10289678Slinton
10299678Slinton /*
10309678Slinton * Push the current environment.
10319678Slinton */
10329678Slinton
pushenv()10339678Slinton private pushenv()
10349678Slinton {
10359678Slinton push(Address, pc);
10369678Slinton push(Lineno, curline);
10379678Slinton push(String, cursource);
10389678Slinton push(Boolean, isstopped);
10399678Slinton push(Symbol, curfunc);
104016618Ssam push(Frame, curframe);
104116618Ssam push(struct Frame, curframerec);
104218231Slinton push(CallEnv, endproc);
10439678Slinton push(Word, reg(PROGCTR));
10449678Slinton push(Word, reg(STKP));
104533334Sdonn push(Word, reg(FRP));
10469678Slinton }
10479678Slinton
10489678Slinton /*
10499678Slinton * Pop back to the real world.
10509678Slinton */
10519678Slinton
popenv()10529678Slinton public popenv()
10539678Slinton {
105418231Slinton String filename;
10559678Slinton
105633334Sdonn setreg(FRP, pop(Word));
10579678Slinton setreg(STKP, pop(Word));
10589678Slinton setreg(PROGCTR, pop(Word));
105918231Slinton endproc = pop(CallEnv);
106016618Ssam curframerec = pop(struct Frame);
106116618Ssam curframe = pop(Frame);
10629678Slinton curfunc = pop(Symbol);
10639678Slinton isstopped = pop(Boolean);
10649678Slinton filename = pop(String);
10659678Slinton curline = pop(Lineno);
10669678Slinton pc = pop(Address);
10679678Slinton setsource(filename);
10689678Slinton }
10699678Slinton
10709678Slinton /*
10719678Slinton * Flush the debuggee's standard output.
10729678Slinton *
10739678Slinton * This is VERY dependent on the use of stdio.
10749678Slinton */
10759678Slinton
flushoutput()10769678Slinton public flushoutput()
10779678Slinton {
107818231Slinton Symbol p, iob;
107918231Slinton Stack *savesp;
10809678Slinton
10819678Slinton p = lookup(identname("fflush", true));
10829678Slinton while (p != nil and not isblock(p)) {
10839678Slinton p = p->next_sym;
10849678Slinton }
10859678Slinton if (p != nil) {
1086*46146Storek iob = lookup(identname("__sF", true));
10879678Slinton if (iob != nil) {
10889678Slinton pushenv();
108933334Sdonn pc = codeloc(p) - FUNCOFFSET;
10909678Slinton savesp = sp;
109133334Sdonn push(long, address(iob, nil) + sizeof(*stdout));
10929678Slinton setreg(STKP, reg(STKP) - sizeof(long));
10939678Slinton dwrite(savesp, reg(STKP), sizeof(long));
10949678Slinton sp = savesp;
10959678Slinton beginproc(p, 1);
10969678Slinton stepto(return_addr());
10979678Slinton popenv();
10989678Slinton }
10999678Slinton }
11009678Slinton }
1101