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