133332Sdonn /*
238105Sbostic * Copyright (c) 1983 The Regents of the University of California.
338105Sbostic * All rights reserved.
438105Sbostic *
5*42684Sbostic * %sccs.include.redist.c%
633332Sdonn */
733332Sdonn
833332Sdonn #ifndef lint
9*42684Sbostic static char sccsid[] = "@(#)runtime.iris.c 5.3 (Berkeley) 06/01/90";
1038105Sbostic #endif /* not lint */
1133332Sdonn
1233332Sdonn /*
1333332Sdonn * Runtime organization dependent routines, mostly dealing with
1433332Sdonn * activation records.
1533332Sdonn */
1633332Sdonn
1733332Sdonn #include "defs.h"
1833332Sdonn #include "runtime.h"
1933332Sdonn #include "process.h"
2033332Sdonn #include "machine.h"
2133332Sdonn #include "events.h"
2233332Sdonn #include "mappings.h"
2333332Sdonn #include "symbols.h"
2433332Sdonn #include "tree.h"
2533332Sdonn #include "eval.h"
2633332Sdonn #include "operators.h"
2733332Sdonn #include "object.h"
2833332Sdonn #include <sys/param.h>
2933332Sdonn #include <signal.h>
3033332Sdonn
3133332Sdonn #ifndef public
3233332Sdonn typedef struct Frame *Frame;
3333332Sdonn
3433332Sdonn #include "machine.h"
3533332Sdonn #endif
3633332Sdonn
3733332Sdonn #define NSAVEREG 14
3833332Sdonn
3933332Sdonn struct Frame {
4033332Sdonn Address save_fp; /* frame pointer */
4133332Sdonn Address save_pc; /* program counter */
4233332Sdonn Word save_reg[NSAVEREG]; /* not necessarily there */
4333332Sdonn integer nargwords; /* computed, not stored */
4433332Sdonn };
4533332Sdonn
4633332Sdonn private Frame curframe = nil;
4733332Sdonn private struct Frame curframerec;
4833332Sdonn private Boolean walkingstack = false;
4933332Sdonn
5033332Sdonn #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp)
5133332Sdonn
inSignalHandler(addr)5233332Sdonn private boolean inSignalHandler (addr)
5333332Sdonn Address addr;
5433332Sdonn {
5533332Sdonn Symbol f;
5633332Sdonn
5733332Sdonn #ifdef IRIS
5833332Sdonn return false;
5933332Sdonn #else /* sun */
6033332Sdonn f = whatblock(addr);
6133332Sdonn return (boolean) (f != nil and streq(symname(f), "_sigtramp"));
6233332Sdonn #endif
6333332Sdonn }
6433332Sdonn
6533332Sdonn typedef struct {
6633332Sdonn Node callnode;
6733332Sdonn Node cmdnode;
6833332Sdonn boolean isfunc;
6933332Sdonn } CallEnv;
7033332Sdonn
7133332Sdonn private CallEnv endproc;
7233332Sdonn
7333332Sdonn /*
7433332Sdonn * Set a frame to the current activation record.
7533332Sdonn */
7633332Sdonn
getcurframe(frp)7733332Sdonn private getcurframe(frp)
7833332Sdonn Frame frp;
7933332Sdonn {
8033332Sdonn register int i;
8133332Sdonn
8233332Sdonn checkref(frp);
8333332Sdonn frp->save_fp = reg(FRP);
8433332Sdonn frp->save_pc = reg(PROGCTR);
8533332Sdonn for (i = 0; i < NSAVEREG; i++) {
8633332Sdonn frp->save_reg[i] = reg(i);
8733332Sdonn }
8833332Sdonn if (frp->save_fp == nil) {
8933332Sdonn frp->nargwords = 0;
9033332Sdonn } else {
9133332Sdonn findnumargs(frp);
9233332Sdonn }
9333332Sdonn }
9433332Sdonn
9533332Sdonn /*
9633332Sdonn * Get the saved registers from one frame to another
9733332Sdonn * given mask specifying which registers were actually saved.
9833332Sdonn */
9933332Sdonn
10033332Sdonn #define bis(b, n) ((b & (1 << (n))) != 0)
10133332Sdonn
getsaveregs(newfrp,frp,mask)10233332Sdonn private getsaveregs (newfrp, frp, mask)
10333332Sdonn Frame newfrp, frp;
10433332Sdonn integer mask;
10533332Sdonn {
10633332Sdonn integer i, j;
10733332Sdonn
10833332Sdonn j = 0;
10933332Sdonn for (i = 0; i < NSAVEREG; i++) {
11033332Sdonn if (bis(mask, i)) {
11133332Sdonn newfrp->save_reg[i] = frp->save_reg[j];
11233332Sdonn ++j;
11333332Sdonn }
11433332Sdonn }
11533332Sdonn }
11633332Sdonn
11733332Sdonn /*
11833332Sdonn * Return a pointer to the next activation record up the stack.
11933332Sdonn * Return nil if there is none.
12033332Sdonn * Writes over space pointed to by given argument.
12133332Sdonn */
12233332Sdonn
nextframe(frp)12333332Sdonn private Frame nextframe(frp)
12433332Sdonn Frame frp;
12533332Sdonn {
12633332Sdonn Frame newfrp;
12733332Sdonn struct Frame frame;
12833332Sdonn integer mask;
12933332Sdonn Address prev_frame, callpc, higher_fp, higher_pc;
13033332Sdonn static integer ntramp = 0;
13133332Sdonn
13233332Sdonn newfrp = frp;
13333332Sdonn prev_frame = frp->save_fp;
13433332Sdonn
13533332Sdonn /*
13633332Sdonn * The check for interrupt generated frames is taken from adb with only
13733332Sdonn * partial understanding. If you're in "sub" and on a sigxxx "sigsub"
13833332Sdonn * gets control, then the stack does NOT look like <main, sub, sigsub>.
13933332Sdonn *
14033332Sdonn * As best I can make out it looks like:
14133332Sdonn *
14233332Sdonn * <main, (machine check exception block + sub), sysframe, sigsub>.
14333332Sdonn *
14433332Sdonn * When the signal occurs an exception block and a frame for the routine
14533332Sdonn * in which it occured are pushed on the user stack. Then another frame
14633332Sdonn * is pushed corresponding to a call from the kernel to sigsub.
14733332Sdonn *
14833332Sdonn * The addr in sub at which the exception occured is not in sub.save_pc
14933332Sdonn * but in the machine check exception block. It is at the magic address
15033332Sdonn * fp + 84.
15133332Sdonn *
15233332Sdonn * The current approach ignores the sys_frame (what adb reports as sigtramp)
15333332Sdonn * and takes the pc for sub from the exception block. This allows the
15433332Sdonn * "where" command to report <main, sub, sigsub>, which seems reasonable.
15533332Sdonn */
15633332Sdonn
15733332Sdonn nextf:
15833332Sdonn if (prev_frame + sizeof(struct Frame) <= USRSTACK) {
15933332Sdonn dread(&frame, prev_frame, sizeof(struct Frame));
16033332Sdonn } else if (USRSTACK - prev_frame > 2 * sizeof(Word)) {
16133332Sdonn dread(&frame, prev_frame, USRSTACK - prev_frame);
16233332Sdonn } else {
16333332Sdonn frame.save_fp = nil;
16433332Sdonn }
16533332Sdonn if (ntramp == 1) {
16633332Sdonn dread(&callpc, prev_frame + 92, sizeof(callpc));
16733332Sdonn } else {
16833332Sdonn callpc = frame.save_pc;
16933332Sdonn }
17033332Sdonn if (frame.save_fp == nil or frame.save_pc == (Address) -1) {
17133332Sdonn newfrp = nil;
17233332Sdonn } else {
17333332Sdonn if (inSignalHandler(callpc)) {
17433332Sdonn # ifdef sun
17533332Sdonn Address scp;
17633332Sdonn
17733332Sdonn dread(&scp, prev_frame + 16, sizeof(scp));
17833332Sdonn dread(&callpc,
17933332Sdonn &(((struct sigcontext *)scp)->sc_pc), sizeof(Word)
18033332Sdonn );
18133332Sdonn # endif /* sun */
18233332Sdonn }
18333332Sdonn frame.save_pc = callpc;
18433332Sdonn ntramp = 0;
18533332Sdonn higher_fp = frp->save_fp;
18633332Sdonn higher_pc = frp->save_pc;
18733332Sdonn newfrp->save_fp = frame.save_fp;
18833332Sdonn newfrp->save_pc = frame.save_pc;
18933332Sdonn findnumargs(newfrp);
19033332Sdonn findsavedregs(newfrp, higher_fp, higher_pc);
19133332Sdonn }
19233332Sdonn return newfrp;
19333332Sdonn }
19433332Sdonn
19533332Sdonn /*
19633332Sdonn * Finding the saved registers and number of arguments passed to
19733332Sdonn * the current procedure is painful for the 68000.
19833332Sdonn *
19933332Sdonn * This is a version of the way adb for the 68000 does this.
20033332Sdonn */
20133332Sdonn
20233332Sdonn #define HIWORD 0xffff0000
20333332Sdonn #define LOWORD 0x0000ffff
20433332Sdonn #define LINKA6 0x4e560000 /* link a6,#x */
20533332Sdonn #define ADDLSP 0xdffc0000 /* addl #x,sp */
20633332Sdonn #define ADDWSP 0xdefc0000 /* addw #x,sp */
20733332Sdonn #define LEASP 0x4fef0000 /* lea sp@(x),sp*/
20833332Sdonn #define TSTBSP 0x4a2f0000 /* tstb sp@(x) */
20933332Sdonn #define INSMSK 0xfff80000
21033332Sdonn #define MOVLSP 0x2e800000 /* movl dx,sp@ */
21133332Sdonn #define MOVLD0 0x20000000 /* movl d0,dx */
21233332Sdonn #define MOVLA0 0x20400000 /* movl d0,ax */
21333332Sdonn #define MVLMSK 0xf1ff0000
21433332Sdonn #define MOVEML 0x48d70000 /* moveml #x,sp@ */
21533332Sdonn #define JSR 0x4eb80000 /* jsr x.[WL] */
21633332Sdonn #define JSRPC 0x4eba0000 /* jsr PC@( ) */
21733332Sdonn #define LONGBIT 0x00010000
21833332Sdonn #define BSR 0x61000000 /* bsr x */
21933332Sdonn #define BYTE3 0x0000ff00
22033332Sdonn #define LOBYTE 0x000000ff
22133332Sdonn #define ADQMSK 0xf1ff0000
22233332Sdonn #define ADDQSP 0x508f0000 /* addql #x,sp */
22333332Sdonn #define ADDQWSP 0x504f0000 /* addqw #x,sp */
22433332Sdonn
22533332Sdonn private int savedregsmask;
22633332Sdonn private int savedregp;
22733332Sdonn
22833332Sdonn /*
22933332Sdonn * Find out how many words of arguments were passed to
23033332Sdonn * the current procedure.
23133332Sdonn */
23233332Sdonn
findnumargs(newfrp)23333332Sdonn private findnumargs (newfrp)
23433332Sdonn Frame newfrp;
23533332Sdonn {
23633332Sdonn integer val;
23733332Sdonn integer instruc;
23833332Sdonn Address addr;
23933332Sdonn
24033332Sdonn dread(&addr, newfrp->save_fp + sizeof(Address), sizeof(addr));
24133332Sdonn iread(&instruc, addr, sizeof(instruc));
24233332Sdonn if ((instruc&MVLMSK) == MOVLA0 or (instruc&MVLMSK) == MOVLD0) {
24333332Sdonn addr += 2;
24433332Sdonn iread(&instruc, addr, sizeof(instruc));
24533332Sdonn }
24633332Sdonn if ((instruc&ADQMSK) == ADDQSP or (instruc&ADQMSK) == ADDQWSP){
24733332Sdonn val = (instruc >> (16+9)) & 07;
24833332Sdonn if (val == 0) {
24933332Sdonn val = 8;
25033332Sdonn }
25133332Sdonn } else if ((instruc&HIWORD) == ADDLSP){
25233332Sdonn iread(&val, addr + 2, sizeof(val));
25333332Sdonn } else if ((instruc&HIWORD) == ADDWSP || (instruc&HIWORD) == LEASP){
25433332Sdonn val = instruc&LOWORD;
25533332Sdonn } else {
25633332Sdonn val = 0;
25733332Sdonn }
25833332Sdonn newfrp->nargwords = val / sizeof(Word);
25933332Sdonn }
26033332Sdonn
26133332Sdonn /*
26233332Sdonn * Get the saved registers for the given Frame.
26333332Sdonn */
26433332Sdonn
findsavedregs(newfrp,higher_fp,higher_pc)26533332Sdonn private findsavedregs (newfrp, higher_fp, higher_pc)
26633332Sdonn Frame newfrp;
26733332Sdonn register Address higher_fp, higher_pc;
26833332Sdonn {
26933332Sdonn int val, regp, i;
27033332Sdonn Address addr;
27133332Sdonn Symbol func;
27233332Sdonn Address calladdr;
27333332Sdonn int instruc;
27433332Sdonn
27533332Sdonn /*
27633332Sdonn * Find the entry point of the current procedure.
27733332Sdonn * This is done by finding the procedure for the higher frame's pc
27833332Sdonn * and taking its starting address.
27933332Sdonn */
28033332Sdonn func = whatblock(higher_pc, true);
28133332Sdonn calladdr = codeloc(func) - FUNCOFFSET;
28233332Sdonn
28333332Sdonn /*
28433332Sdonn * Look at the entry code for the current procedure
28533332Sdonn * to determine which registers were saved, and where they are.
28633332Sdonn *
28733332Sdonn * First find the size of the activation record.
28833332Sdonn */
28933332Sdonn addr = calladdr;
29033332Sdonn iread(&instruc, addr, sizeof(instruc));
29133332Sdonn if ((instruc&HIWORD) == LINKA6) {
29233332Sdonn if ((instruc &= LOWORD) == 0) {
29333332Sdonn /* look for addl */
29433332Sdonn addr += 4;
29533332Sdonn iread(&instruc, addr, sizeof(instruc));
29633332Sdonn if ((instruc&HIWORD) == ADDLSP) {
29733332Sdonn iread(&instruc, addr + 2, sizeof(instruc));
29833332Sdonn addr += 6;
29933332Sdonn } else {
30033332Sdonn instruc = 0;
30133332Sdonn }
30233332Sdonn } else {
30333332Sdonn /* link offset was non-zero -- sign extend it */
30433332Sdonn instruc <<= 16;
30533332Sdonn instruc >>= 16;
30633332Sdonn }
30733332Sdonn /* we now have the negative frame size */
30833332Sdonn regp = higher_fp + instruc;
30933332Sdonn savedregp = regp;
31033332Sdonn }
31133332Sdonn
31233332Sdonn /*
31333332Sdonn * Now find which registers were saved.
31433332Sdonn * (expecting a probe instruction next)
31533332Sdonn */
31633332Sdonn iread(&instruc, addr, sizeof(instruc));
31733332Sdonn if ((instruc&HIWORD) == TSTBSP) {
31833332Sdonn addr += 4;
31933332Sdonn iread(&instruc, addr, sizeof(instruc));
32033332Sdonn }
32133332Sdonn /*
32233332Sdonn * expect either a moveml or a movl next
32333332Sdonn */
32433332Sdonn if ((instruc&INSMSK) == MOVLSP){
32533332Sdonn /*
32633332Sdonn * Only one register saved.
32733332Sdonn */
32833332Sdonn i = (instruc>>16) & 07;
32933332Sdonn dread(&(newfrp->save_reg[i]), regp, sizeof(Word));
33033332Sdonn savedregsmask = 1 << i;
33133332Sdonn } else if ((instruc&HIWORD) == MOVEML) {
33233332Sdonn /*
33333332Sdonn * Saving multiple registers or unoptimized code
33433332Sdonn */
33533332Sdonn val = instruc & LOWORD;
33633332Sdonn savedregsmask = val;
33733332Sdonn i = 0;
33833332Sdonn while (val != 0) {
33933332Sdonn if (val&1) {
34033332Sdonn dread(&(newfrp->save_reg[i]), regp, sizeof(Word));
34133332Sdonn regp += sizeof(Word);
34233332Sdonn }
34333332Sdonn val >>= 1;
34433332Sdonn ++i;
34533332Sdonn }
34633332Sdonn } else {
34733332Sdonn savedregsmask = 0;
34833332Sdonn }
34933332Sdonn }
35033332Sdonn
35133332Sdonn /*
35233332Sdonn * Get the current frame information in the given Frame and store the
35333332Sdonn * associated function in the given value-result parameter.
35433332Sdonn */
35533332Sdonn
getcurfunc(frp,fp)35633332Sdonn private getcurfunc (frp, fp)
35733332Sdonn Frame frp;
35833332Sdonn Symbol *fp;
35933332Sdonn {
36033332Sdonn getcurframe(frp);
36133332Sdonn *fp = whatblock(frp->save_pc);
36233332Sdonn }
36333332Sdonn
36433332Sdonn /*
36533332Sdonn * Return the frame associated with the next function up the call stack, or
36633332Sdonn * nil if there is none. The function is returned in a value-result parameter.
36733332Sdonn * For "inline" functions the statically outer function and same frame
36833332Sdonn * are returned.
36933332Sdonn */
37033332Sdonn
nextfunc(frp,fp)37133332Sdonn public Frame nextfunc (frp, fp)
37233332Sdonn Frame frp;
37333332Sdonn Symbol *fp;
37433332Sdonn {
37533332Sdonn Symbol t;
37633332Sdonn Frame nfrp;
37733332Sdonn
37833332Sdonn t = *fp;
37933332Sdonn checkref(t);
38033332Sdonn if (isinline(t)) {
38133332Sdonn t = container(t);
38233332Sdonn nfrp = frp;
38333332Sdonn } else {
38433332Sdonn nfrp = nextframe(frp);
38533332Sdonn if (nfrp == nil) {
38633332Sdonn t = nil;
38733332Sdonn } else {
38833332Sdonn t = whatblock(nfrp->save_pc);
38933332Sdonn }
39033332Sdonn }
39133332Sdonn *fp = t;
39233332Sdonn return nfrp;
39333332Sdonn }
39433332Sdonn
39533332Sdonn /*
39633332Sdonn * Return the frame associated with the given function.
39733332Sdonn * If the function is nil, return the most recently activated frame.
39833332Sdonn *
39933332Sdonn * Static allocation for the frame.
40033332Sdonn */
40133332Sdonn
findframe(f)40233332Sdonn public Frame findframe(f)
40333332Sdonn Symbol f;
40433332Sdonn {
40533332Sdonn Frame frp;
40633332Sdonn static struct Frame frame;
40733332Sdonn Symbol p;
40833332Sdonn Boolean done;
40933332Sdonn
41033332Sdonn frp = &frame;
41133332Sdonn getcurframe(frp);
41233332Sdonn if (f != nil) {
41333332Sdonn if (f == curfunc and curframe != nil) {
41433332Sdonn *frp = *curframe;
41533332Sdonn } else {
41633332Sdonn done = false;
41733332Sdonn p = whatblock(frp->save_pc);
41833332Sdonn do {
41933332Sdonn if (p == f) {
42033332Sdonn done = true;
42133332Sdonn } else if (p == program) {
42233332Sdonn done = true;
42333332Sdonn frp = nil;
42433332Sdonn } else {
42533332Sdonn frp = nextfunc(frp, &p);
42633332Sdonn if (frp == nil) {
42733332Sdonn done = true;
42833332Sdonn }
42933332Sdonn }
43033332Sdonn } while (not done);
43133332Sdonn }
43233332Sdonn }
43333332Sdonn return frp;
43433332Sdonn }
43533332Sdonn
43633332Sdonn /*
43733332Sdonn * Set the registers according to the given frame pointer.
43833332Sdonn */
43933332Sdonn
getnewregs(addr)44033332Sdonn public getnewregs (addr)
44133332Sdonn Address addr;
44233332Sdonn {
44333332Sdonn struct Frame frame;
44433332Sdonn integer i, j, mask;
44533332Sdonn
44633332Sdonn dread(&frame, addr, sizeof(frame));
44733332Sdonn setreg(FRP, frame.save_fp);
44833332Sdonn setreg(PROGCTR, frame.save_pc);
44933332Sdonn pc = frame.save_pc;
45033332Sdonn setcurfunc(whatblock(pc));
45133332Sdonn }
45233332Sdonn
45333332Sdonn /*
45433332Sdonn * Find the return address of the current procedure/function.
45533332Sdonn */
45633332Sdonn
return_addr()45733332Sdonn public Address return_addr()
45833332Sdonn {
45933332Sdonn Frame frp;
46033332Sdonn Address addr;
46133332Sdonn struct Frame frame;
46233332Sdonn
46333332Sdonn frp = &frame;
46433332Sdonn getcurframe(frp);
46533332Sdonn frp = nextframe(frp);
46633332Sdonn if (frp == nil) {
46733332Sdonn addr = 0;
46833332Sdonn } else {
46933332Sdonn addr = frp->save_pc;
47033332Sdonn }
47133332Sdonn return addr;
47233332Sdonn }
47333332Sdonn
47433332Sdonn /*
47533332Sdonn * Push the value associated with the current function.
47633332Sdonn */
47733332Sdonn
pushretval(len,isindirect)47833332Sdonn public pushretval(len, isindirect)
47933332Sdonn integer len;
48033332Sdonn boolean isindirect;
48133332Sdonn {
48233332Sdonn Word r0;
48333332Sdonn
48433332Sdonn r0 = reg(0);
48533332Sdonn if (isindirect) {
48633332Sdonn rpush((Address) r0, len);
48733332Sdonn } else {
48833332Sdonn switch (len) {
48933332Sdonn case sizeof(char):
49033332Sdonn push(char, r0);
49133332Sdonn break;
49233332Sdonn
49333332Sdonn case sizeof(short):
49433332Sdonn push(short, r0);
49533332Sdonn break;
49633332Sdonn
49733332Sdonn default:
49833332Sdonn if (len == sizeof(Word)) {
49933332Sdonn push(Word, r0);
50033332Sdonn } else if (len == 2*sizeof(Word)) {
50133332Sdonn push(Word, r0);
50233332Sdonn push(Word, reg(1));
50333332Sdonn } else {
50433332Sdonn error("[internal error: bad size %d in pushretval]", len);
50533332Sdonn }
50633332Sdonn break;
50733332Sdonn }
50833332Sdonn }
50933332Sdonn }
51033332Sdonn
51133332Sdonn /*
51233332Sdonn * Return the base address for locals in the given frame.
51333332Sdonn */
51433332Sdonn
locals_base(frp)51533332Sdonn public Address locals_base(frp)
51633332Sdonn Frame frp;
51733332Sdonn {
51833332Sdonn return (frp == nil) ? reg(FRP) : frp->save_fp;
51933332Sdonn }
52033332Sdonn
52133332Sdonn /*
52233332Sdonn * Return the base address for arguments in the given frame.
52333332Sdonn */
52433332Sdonn
args_base(frp)52533332Sdonn public Address args_base(frp)
52633332Sdonn Frame frp;
52733332Sdonn {
52833332Sdonn return (frp == nil) ? reg(FRP) : frp->save_fp;
52933332Sdonn }
53033332Sdonn
53133332Sdonn /*
53233332Sdonn * Return saved register n from the given frame.
53333332Sdonn */
53433332Sdonn
savereg(n,frp)53533332Sdonn public Word savereg(n, frp)
53633332Sdonn integer n;
53733332Sdonn Frame frp;
53833332Sdonn {
53933332Sdonn Word w;
54033332Sdonn
54133332Sdonn if (frp == nil) {
54233332Sdonn w = reg(n);
54333332Sdonn } else {
54433332Sdonn switch (n) {
54533332Sdonn case FRP:
54633332Sdonn w = frp->save_fp;
54733332Sdonn break;
54833332Sdonn
54933332Sdonn case STKP:
55033332Sdonn w = reg(STKP);
55133332Sdonn break;
55233332Sdonn
55333332Sdonn case PROGCTR:
55433332Sdonn w = frp->save_pc;
55533332Sdonn break;
55633332Sdonn
55733332Sdonn default:
55833332Sdonn assert(n >= 0 and n < NSAVEREG);
55933332Sdonn w = frp->save_reg[n];
56033332Sdonn break;
56133332Sdonn }
56233332Sdonn }
56333332Sdonn return w;
56433332Sdonn }
56533332Sdonn
56633332Sdonn /*
56733332Sdonn * Return the nth argument to the current procedure.
56833332Sdonn */
56933332Sdonn
argn(n,frp)57033332Sdonn public Word argn(n, frp)
57133332Sdonn integer n;
57233332Sdonn Frame frp;
57333332Sdonn {
57433332Sdonn Address argaddr;
57533332Sdonn Word w;
57633332Sdonn
57733332Sdonn argaddr = args_base(frp) + 4 + (n * sizeof(Word));
57833332Sdonn dread(&w, argaddr, sizeof(w));
57933332Sdonn return w;
58033332Sdonn }
58133332Sdonn
58233332Sdonn /*
58333332Sdonn * Return the number of words of arguments passed to the procedure
58433332Sdonn * associated with the given frame (it's a macro for the VAX).
58533332Sdonn */
58633332Sdonn
nargspassed(frp)58733332Sdonn public integer nargspassed (frp)
58833332Sdonn Frame frp;
58933332Sdonn {
59033332Sdonn integer n;
59133332Sdonn struct Frame frame;
59233332Sdonn
59333332Sdonn if (frp == nil) {
59433332Sdonn getcurframe(&frame);
59533332Sdonn n = frame.nargwords;
59633332Sdonn } else {
59733332Sdonn n = frp->nargwords;
59833332Sdonn }
59933332Sdonn return n;
60033332Sdonn }
60133332Sdonn
60233332Sdonn /*
60333332Sdonn * Print a list of currently active blocks starting with most recent.
60433332Sdonn */
60533332Sdonn
wherecmd()60633332Sdonn public wherecmd()
60733332Sdonn {
60833332Sdonn walkstack(false);
60933332Sdonn }
61033332Sdonn
61133332Sdonn /*
61233332Sdonn * Print the variables in the given frame or the current one if nil.
61333332Sdonn */
61433332Sdonn
dump(func)61533332Sdonn public dump (func)
61633332Sdonn Symbol func;
61733332Sdonn {
61833332Sdonn Symbol f;
61933332Sdonn Frame frp;
62033332Sdonn
62133332Sdonn if (func == nil) {
62233332Sdonn f = curfunc;
62333332Sdonn if (curframe != nil) {
62433332Sdonn frp = curframe;
62533332Sdonn } else {
62633332Sdonn frp = findframe(f);
62733332Sdonn }
62833332Sdonn } else {
62933332Sdonn f = func;
63033332Sdonn frp = findframe(f);
63133332Sdonn }
63233332Sdonn showaggrs = true;
63333332Sdonn printcallinfo(f, frp);
63433332Sdonn dumpvars(f, frp);
63533332Sdonn }
63633332Sdonn
63733332Sdonn /*
63833332Sdonn * Dump all values.
63933332Sdonn */
64033332Sdonn
dumpall()64133332Sdonn public dumpall ()
64233332Sdonn {
64333332Sdonn walkstack(true);
64433332Sdonn }
64533332Sdonn
64633332Sdonn /*
64733332Sdonn * Walk the stack of active procedures printing information
64833332Sdonn * about each active procedure.
64933332Sdonn */
65033332Sdonn
walkstack(dumpvariables)65133332Sdonn private walkstack(dumpvariables)
65233332Sdonn Boolean dumpvariables;
65333332Sdonn {
65433332Sdonn Frame frp;
65533332Sdonn boolean save;
65633332Sdonn Symbol f;
65733332Sdonn struct Frame frame;
65833332Sdonn
65933332Sdonn if (notstarted(process) or isfinished(process)) {
66033332Sdonn error("program is not active");
66133332Sdonn } else {
66233332Sdonn save = walkingstack;
66333332Sdonn walkingstack = true;
66433332Sdonn showaggrs = dumpvariables;
66533332Sdonn frp = &frame;
66633332Sdonn getcurfunc(frp, &f);
66733332Sdonn for (;;) {
66833332Sdonn printcallinfo(f, frp);
66933332Sdonn if (dumpvariables) {
67033332Sdonn dumpvars(f, frp);
67133332Sdonn putchar('\n');
67233332Sdonn }
67333332Sdonn frp = nextfunc(frp, &f);
67433332Sdonn if (frp == nil or f == program) {
67533332Sdonn break;
67633332Sdonn }
67733332Sdonn }
67833332Sdonn if (dumpvariables) {
67933332Sdonn printf("in \"%s\":\n", symname(program));
68033332Sdonn dumpvars(program, nil);
68133332Sdonn putchar('\n');
68233332Sdonn }
68333332Sdonn walkingstack = save;
68433332Sdonn }
68533332Sdonn }
68633332Sdonn
68733332Sdonn /*
68833332Sdonn * Print out the information about a call, i.e.,
68933332Sdonn * routine name, parameter values, and source location.
69033332Sdonn */
69133332Sdonn
printcallinfo(f,frp)69233332Sdonn private printcallinfo (f, frp)
69333332Sdonn Symbol f;
69433332Sdonn Frame frp;
69533332Sdonn {
69633332Sdonn Lineno line;
69733332Sdonn Address savepc;
69833332Sdonn
69933332Sdonn savepc = frp->save_pc;
70033332Sdonn if (frp->save_fp != reg(FRP)) {
70133332Sdonn savepc -= 1;
70233332Sdonn }
70333332Sdonn printname(stdout, f);
70433332Sdonn if (not isinline(f)) {
70533332Sdonn printparams(f, frp);
70633332Sdonn }
70733332Sdonn line = srcline(savepc);
70833332Sdonn if (line != 0) {
70933332Sdonn printf(", line %d", line);
71033332Sdonn printf(" in \"%s\"\n", srcfilename(savepc));
71133332Sdonn } else {
71233332Sdonn printf(" at 0x%x\n", savepc);
71333332Sdonn }
71433332Sdonn }
71533332Sdonn
71633332Sdonn /*
71733332Sdonn * Set the current function to the given symbol.
71833332Sdonn * We must adjust "curframe" so that subsequent operations are
71933332Sdonn * not confused; for simplicity we simply clear it.
72033332Sdonn */
72133332Sdonn
setcurfunc(f)72233332Sdonn public setcurfunc (f)
72333332Sdonn Symbol f;
72433332Sdonn {
72533332Sdonn curfunc = f;
72633332Sdonn curframe = nil;
72733332Sdonn }
72833332Sdonn
72933332Sdonn /*
73033332Sdonn * Return the frame for the current function.
73133332Sdonn * The space for the frame is allocated statically.
73233332Sdonn */
73333332Sdonn
curfuncframe()73433332Sdonn public Frame curfuncframe ()
73533332Sdonn {
73633332Sdonn static struct Frame frame;
73733332Sdonn Frame frp;
73833332Sdonn
73933332Sdonn if (curframe == nil) {
74033332Sdonn frp = findframe(curfunc);
74133332Sdonn curframe = &curframerec;
74233332Sdonn *curframe = *frp;
74333332Sdonn } else {
74433332Sdonn frp = &frame;
74533332Sdonn *frp = *curframe;
74633332Sdonn }
74733332Sdonn return frp;
74833332Sdonn }
74933332Sdonn
75033332Sdonn /*
75133332Sdonn * Set curfunc to be N up/down the stack from its current value.
75233332Sdonn */
75333332Sdonn
up(n)75433332Sdonn public up (n)
75533332Sdonn integer n;
75633332Sdonn {
75733332Sdonn integer i;
75833332Sdonn Symbol f;
75933332Sdonn Frame frp;
76033332Sdonn boolean done;
76133332Sdonn
76233332Sdonn if (not isactive(program)) {
76333332Sdonn error("program is not active");
76433332Sdonn } else if (curfunc == nil) {
76533332Sdonn error("no current function");
76633332Sdonn } else {
76733332Sdonn i = 0;
76833332Sdonn f = curfunc;
76933332Sdonn frp = curfuncframe();
77033332Sdonn done = false;
77133332Sdonn do {
77233332Sdonn if (frp == nil) {
77333332Sdonn done = true;
77433332Sdonn error("not that many levels");
77533332Sdonn } else if (i >= n) {
77633332Sdonn done = true;
77733332Sdonn curfunc = f;
77833332Sdonn curframe = &curframerec;
77933332Sdonn *curframe = *frp;
78033332Sdonn showaggrs = false;
78133332Sdonn printcallinfo(curfunc, curframe);
78233332Sdonn } else if (f == program) {
78333332Sdonn done = true;
78433332Sdonn error("not that many levels");
78533332Sdonn } else {
78633332Sdonn frp = nextfunc(frp, &f);
78733332Sdonn }
78833332Sdonn ++i;
78933332Sdonn } while (not done);
79033332Sdonn }
79133332Sdonn }
79233332Sdonn
down(n)79333332Sdonn public down (n)
79433332Sdonn integer n;
79533332Sdonn {
79633332Sdonn integer i, depth;
79733332Sdonn Frame frp, curfrp;
79833332Sdonn Symbol f;
79933332Sdonn struct Frame frame;
80033332Sdonn
80133332Sdonn if (not isactive(program)) {
80233332Sdonn error("program is not active");
80333332Sdonn } else if (curfunc == nil) {
80433332Sdonn error("no current function");
80533332Sdonn } else {
80633332Sdonn depth = 0;
80733332Sdonn frp = &frame;
80833332Sdonn getcurfunc(frp, &f);
80933332Sdonn if (curframe == nil) {
81033332Sdonn curfrp = findframe(curfunc);
81133332Sdonn curframe = &curframerec;
81233332Sdonn *curframe = *curfrp;
81333332Sdonn }
81433332Sdonn while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) {
81533332Sdonn frp = nextfunc(frp, &f);
81633332Sdonn ++depth;
81733332Sdonn }
81833332Sdonn if (f == nil or n > depth) {
81933332Sdonn error("not that many levels");
82033332Sdonn } else {
82133332Sdonn depth -= n;
82233332Sdonn frp = &frame;
82333332Sdonn getcurfunc(frp, &f);
82433332Sdonn for (i = 0; i < depth; i++) {
82533332Sdonn frp = nextfunc(frp, &f);
82633332Sdonn assert(frp != nil);
82733332Sdonn }
82833332Sdonn curfunc = f;
82933332Sdonn *curframe = *frp;
83033332Sdonn showaggrs = false;
83133332Sdonn printcallinfo(curfunc, curframe);
83233332Sdonn }
83333332Sdonn }
83433332Sdonn }
83533332Sdonn
83633332Sdonn /*
83733332Sdonn * Find the entry point of a procedure or function.
83833332Sdonn */
83933332Sdonn
findbeginning(f)84033332Sdonn public findbeginning (f)
84133332Sdonn Symbol f;
84233332Sdonn {
84333332Sdonn if (isinternal(f)) {
84433332Sdonn f->symvalue.funcv.beginaddr += 18; /* VAX only */
84533332Sdonn } else {
84633332Sdonn /* on 68000's don't add for beginning of program */
84733332Sdonn if (f->symvalue.funcv.beginaddr != CODESTART) {
84833332Sdonn f->symvalue.funcv.beginaddr += FUNCOFFSET;
84933332Sdonn }
85033332Sdonn }
85133332Sdonn }
85233332Sdonn
85333332Sdonn /*
85433332Sdonn * Return the address corresponding to the first line in a function.
85533332Sdonn */
85633332Sdonn
firstline(f)85733332Sdonn public Address firstline(f)
85833332Sdonn Symbol f;
85933332Sdonn {
86033332Sdonn Address addr;
86133332Sdonn
86233332Sdonn addr = codeloc(f);
86333332Sdonn while (linelookup(addr) == 0 and addr < objsize) {
86433332Sdonn ++addr;
86533332Sdonn }
86633332Sdonn if (addr == objsize) {
86733332Sdonn addr = -1;
86833332Sdonn }
86933332Sdonn return addr;
87033332Sdonn }
87133332Sdonn
87233332Sdonn /*
87333332Sdonn * Catcher drops strike three ...
87433332Sdonn */
87533332Sdonn
runtofirst()87633332Sdonn public runtofirst()
87733332Sdonn {
87833332Sdonn Address addr, endaddr;
87933332Sdonn
88033332Sdonn addr = pc;
88133332Sdonn endaddr = objsize + CODESTART;
88233332Sdonn while (linelookup(addr) == 0 and addr < endaddr) {
88333332Sdonn ++addr;
88433332Sdonn }
88533332Sdonn if (addr < endaddr) {
88633332Sdonn stepto(addr);
88733332Sdonn }
88833332Sdonn }
88933332Sdonn
89033332Sdonn /*
89133332Sdonn * Return the address corresponding to the end of the program.
89233332Sdonn *
89333332Sdonn * We look for the entry to "exit".
89433332Sdonn */
89533332Sdonn
lastaddr()89633332Sdonn public Address lastaddr()
89733332Sdonn {
89833332Sdonn Symbol s;
89933332Sdonn
90033332Sdonn s = lookup(identname("exit", true));
90133332Sdonn if (s == nil) {
90233332Sdonn panic("can't find exit");
90333332Sdonn }
90433332Sdonn return codeloc(s);
90533332Sdonn }
90633332Sdonn
90733332Sdonn /*
90833332Sdonn * Decide if the given function is currently active.
90933332Sdonn *
91033332Sdonn * We avoid calls to "findframe" during a stack trace for efficiency.
91133332Sdonn * Presumably information evaluated while walking the stack is active.
91233332Sdonn */
91333332Sdonn
isactive(f)91433332Sdonn public Boolean isactive (f)
91533332Sdonn Symbol f;
91633332Sdonn {
91733332Sdonn Boolean b;
91833332Sdonn
91933332Sdonn if (isfinished(process)) {
92033332Sdonn b = false;
92133332Sdonn } else {
92233332Sdonn if (walkingstack or f == program or f == nil or
92333332Sdonn (ismodule(f) and isactive(container(f)))) {
92433332Sdonn b = true;
92533332Sdonn } else {
92633332Sdonn b = (Boolean) (findframe(f) != nil);
92733332Sdonn }
92833332Sdonn }
92933332Sdonn return b;
93033332Sdonn }
93133332Sdonn
93233332Sdonn /*
93333332Sdonn * Evaluate a call to a procedure.
93433332Sdonn */
93533332Sdonn
callproc(exprnode,isfunc)93633332Sdonn public callproc(exprnode, isfunc)
93733332Sdonn Node exprnode;
93833332Sdonn boolean isfunc;
93933332Sdonn {
94033332Sdonn Node procnode, arglist;
94133332Sdonn Symbol proc;
94233332Sdonn integer argc;
94333332Sdonn
94433332Sdonn procnode = exprnode->value.arg[0];
94533332Sdonn arglist = exprnode->value.arg[1];
94633332Sdonn if (procnode->op != O_SYM) {
94733332Sdonn beginerrmsg();
94833332Sdonn fprintf(stderr, "can't call \"");
94933332Sdonn prtree(stderr, procnode);
95033332Sdonn fprintf(stderr, "\"");
95133332Sdonn enderrmsg();
95233332Sdonn }
95333332Sdonn assert(procnode->op == O_SYM);
95433332Sdonn proc = procnode->value.sym;
95533332Sdonn if (not isblock(proc)) {
95633332Sdonn error("\"%s\" is not a procedure or function", symname(proc));
95733332Sdonn }
95833332Sdonn endproc.isfunc = isfunc;
95933332Sdonn endproc.callnode = exprnode;
96033332Sdonn endproc.cmdnode = topnode;
96133332Sdonn pushenv();
96233332Sdonn pc = codeloc(proc);
96333332Sdonn argc = pushargs(proc, arglist);
96433332Sdonn setreg(FRP, 1); /* have to ensure it's non-zero for return_addr() */
96533332Sdonn beginproc(proc, argc);
96633332Sdonn event_once(
96733332Sdonn build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)),
96833332Sdonn buildcmdlist(build(O_PROCRTN, proc))
96933332Sdonn );
97033332Sdonn isstopped = false;
97133332Sdonn if (not bpact()) {
97233332Sdonn isstopped = true;
97333332Sdonn cont(0);
97433332Sdonn }
97533332Sdonn /*
97633332Sdonn * bpact() won't return true, it will call printstatus() and go back
97733332Sdonn * to command input if a breakpoint is found.
97833332Sdonn */
97933332Sdonn /* NOTREACHED */
98033332Sdonn }
98133332Sdonn
98233332Sdonn /*
98333332Sdonn * Push the arguments on the process' stack. We do this by first
98433332Sdonn * evaluating them on the "eval" stack, then copying into the process'
98533332Sdonn * space.
98633332Sdonn */
98733332Sdonn
pushargs(proc,arglist)98833332Sdonn private integer pushargs(proc, arglist)
98933332Sdonn Symbol proc;
99033332Sdonn Node arglist;
99133332Sdonn {
99233332Sdonn Stack *savesp;
99333332Sdonn int argc, args_size;
99433332Sdonn
99533332Sdonn savesp = sp;
99633332Sdonn if (varIsSet("$unsafecall")) {
99733332Sdonn argc = unsafe_evalargs(proc, arglist);
99833332Sdonn } else {
99933332Sdonn argc = evalargs(proc, arglist);
100033332Sdonn }
100133332Sdonn args_size = sp - savesp;
100233332Sdonn setreg(STKP, reg(STKP) - args_size);
100333332Sdonn dwrite(savesp, reg(STKP), args_size);
100433332Sdonn sp = savesp;
100533332Sdonn return argc;
100633332Sdonn }
100733332Sdonn
100833332Sdonn /*
100933332Sdonn * Check to see if an expression is correct for a given parameter.
101033332Sdonn * If the given parameter is false, don't worry about type inconsistencies.
101133332Sdonn *
101233332Sdonn * Return whether or not it is ok.
101333332Sdonn */
101433332Sdonn
chkparam(actual,formal,chk)101533332Sdonn private boolean chkparam (actual, formal, chk)
101633332Sdonn Node actual;
101733332Sdonn Symbol formal;
101833332Sdonn boolean chk;
101933332Sdonn {
102033332Sdonn boolean b;
102133332Sdonn
102233332Sdonn b = true;
102333332Sdonn if (chk) {
102433332Sdonn if (formal == nil) {
102533332Sdonn beginerrmsg();
102633332Sdonn fprintf(stderr, "too many parameters");
102733332Sdonn b = false;
102833332Sdonn } else if (not compatible(formal->type, actual->nodetype)) {
102933332Sdonn beginerrmsg();
103033332Sdonn fprintf(stderr, "type mismatch for %s", symname(formal));
103133332Sdonn b = false;
103233332Sdonn }
103333332Sdonn }
103433332Sdonn if (b and formal != nil and
103533332Sdonn isvarparam(formal) and not isopenarray(formal->type) and
103633332Sdonn not (
103733332Sdonn actual->op == O_RVAL or actual->nodetype == t_addr or
103833332Sdonn (
103933332Sdonn actual->op == O_TYPERENAME and
104033332Sdonn (
104133332Sdonn actual->value.arg[0]->op == O_RVAL or
104233332Sdonn actual->value.arg[0]->nodetype == t_addr
104333332Sdonn )
104433332Sdonn )
104533332Sdonn )
104633332Sdonn ) {
104733332Sdonn beginerrmsg();
104833332Sdonn fprintf(stderr, "expected variable, found \"");
104933332Sdonn prtree(stderr, actual);
105033332Sdonn fprintf(stderr, "\"");
105133332Sdonn b = false;
105233332Sdonn }
105333332Sdonn return b;
105433332Sdonn }
105533332Sdonn
105633332Sdonn /*
105733332Sdonn * Pass an expression to a particular parameter.
105833332Sdonn *
105933332Sdonn * Normally we pass either the address or value, but in some cases
106033332Sdonn * (such as C strings) we want to copy the value onto the stack and
106133332Sdonn * pass its address.
106233332Sdonn *
106333332Sdonn * Another special case raised by strings is the possibility that
106433332Sdonn * the actual parameter will be larger than the formal, even with
106533332Sdonn * appropriate type-checking. This occurs because we assume during
106633332Sdonn * evaluation that strings are null-terminated, whereas some languages,
106733332Sdonn * notably Pascal, do not work under that assumption.
106833332Sdonn */
106933332Sdonn
passparam(actual,formal)107033332Sdonn private passparam (actual, formal)
107133332Sdonn Node actual;
107233332Sdonn Symbol formal;
107333332Sdonn {
107433332Sdonn boolean b;
107533332Sdonn Address addr;
107633332Sdonn Stack *savesp;
107733332Sdonn integer actsize, formsize;
107833332Sdonn
107933332Sdonn if (formal != nil and isvarparam(formal) and
108033332Sdonn (not isopenarray(formal->type))
108133332Sdonn ) {
108233332Sdonn addr = lval(actual->value.arg[0]);
108333332Sdonn push(Address, addr);
108433332Sdonn } else if (passaddr(formal, actual->nodetype)) {
108533332Sdonn savesp = sp;
108633332Sdonn eval(actual);
108733332Sdonn actsize = sp - savesp;
108833332Sdonn setreg(STKP,
108933332Sdonn reg(STKP) - ((actsize + sizeof(Word) - 1) & ~(sizeof(Word) - 1))
109033332Sdonn );
109133332Sdonn dwrite(savesp, reg(STKP), actsize);
109233332Sdonn sp = savesp;
109333332Sdonn push(Address, reg(STKP));
109433332Sdonn if (formal != nil and isopenarray(formal->type)) {
109533332Sdonn push(integer, actsize div size(formal->type->type));
109633332Sdonn }
109733332Sdonn } else if (formal != nil) {
109833332Sdonn formsize = size(formal);
109933332Sdonn savesp = sp;
110033332Sdonn eval(actual);
110133332Sdonn actsize = sp - savesp;
110233332Sdonn if (actsize > formsize) {
110333332Sdonn sp -= (actsize - formsize);
110433332Sdonn }
110533332Sdonn } else {
110633332Sdonn eval(actual);
110733332Sdonn }
110833332Sdonn }
110933332Sdonn
111033332Sdonn /*
111133332Sdonn * Evaluate an argument list left-to-right.
111233332Sdonn */
111333332Sdonn
evalargs(proc,arglist)111433332Sdonn private integer evalargs(proc, arglist)
111533332Sdonn Symbol proc;
111633332Sdonn Node arglist;
111733332Sdonn {
111833332Sdonn Node p, actual;
111933332Sdonn Symbol formal;
112033332Sdonn Stack *savesp;
112133332Sdonn integer count;
112233332Sdonn boolean chk;
112333332Sdonn
112433332Sdonn savesp = sp;
112533332Sdonn count = 0;
112633332Sdonn formal = proc->chain;
112733332Sdonn chk = (boolean) (not nosource(proc));
112833332Sdonn for (p = arglist; p != nil; p = p->value.arg[1]) {
112933332Sdonn assert(p->op == O_COMMA);
113033332Sdonn actual = p->value.arg[0];
113133332Sdonn if (not chkparam(actual, formal, chk)) {
113233332Sdonn fprintf(stderr, " in call to %s", symname(proc));
113333332Sdonn sp = savesp;
113433332Sdonn enderrmsg();
113533332Sdonn }
113633332Sdonn passparam(actual, formal);
113733332Sdonn if (formal != nil) {
113833332Sdonn formal = formal->chain;
113933332Sdonn }
114033332Sdonn ++count;
114133332Sdonn }
114233332Sdonn if (chk) {
114333332Sdonn if (formal != nil) {
114433332Sdonn sp = savesp;
114533332Sdonn error("not enough parameters to %s", symname(proc));
114633332Sdonn }
114733332Sdonn }
114833332Sdonn return count;
114933332Sdonn }
115033332Sdonn
115133332Sdonn /*
115233332Sdonn * Evaluate an argument list without any type checking.
115333332Sdonn * This is only useful for procedures with a varying number of
115433332Sdonn * arguments that are compiled -g.
115533332Sdonn */
115633332Sdonn
unsafe_evalargs(proc,arglist)115733332Sdonn private integer unsafe_evalargs (proc, arglist)
115833332Sdonn Symbol proc;
115933332Sdonn Node arglist;
116033332Sdonn {
116133332Sdonn Node p;
116233332Sdonn integer count;
116333332Sdonn
116433332Sdonn count = 0;
116533332Sdonn for (p = arglist; p != nil; p = p->value.arg[1]) {
116633332Sdonn assert(p->op == O_COMMA);
116733332Sdonn eval(p->value.arg[0]);
116833332Sdonn ++count;
116933332Sdonn }
117033332Sdonn return count;
117133332Sdonn }
117233332Sdonn
procreturn(f)117333332Sdonn public procreturn(f)
117433332Sdonn Symbol f;
117533332Sdonn {
117633332Sdonn integer retvalsize;
117733332Sdonn Node tmp;
117833332Sdonn char *copy;
117933332Sdonn
118033332Sdonn flushoutput();
118133332Sdonn popenv();
118233332Sdonn if (endproc.isfunc) {
118333332Sdonn retvalsize = size(f->type);
118433332Sdonn if (retvalsize > sizeof(long)) {
118533332Sdonn pushretval(retvalsize, true);
118633332Sdonn copy = newarr(char, retvalsize);
118733332Sdonn popn(retvalsize, copy);
118833332Sdonn tmp = build(O_SCON, copy);
118933332Sdonn } else {
119033332Sdonn tmp = build(O_LCON, (long) (reg(0)));
119133332Sdonn }
119233332Sdonn tmp->nodetype = f->type;
119333332Sdonn tfree(endproc.callnode);
119433332Sdonn *(endproc.callnode) = *(tmp);
119533332Sdonn dispose(tmp);
119633332Sdonn eval(endproc.cmdnode);
119733332Sdonn } else {
119833332Sdonn putchar('\n');
119933332Sdonn printname(stdout, f);
120033332Sdonn printf(" returns successfully\n");
120133332Sdonn }
120233332Sdonn erecover();
120333332Sdonn }
120433332Sdonn
120533332Sdonn /*
120633332Sdonn * Push the current environment.
120733332Sdonn */
120833332Sdonn
pushenv()120933332Sdonn private pushenv()
121033332Sdonn {
121133332Sdonn push(Address, pc);
121233332Sdonn push(Lineno, curline);
121333332Sdonn push(String, cursource);
121433332Sdonn push(Boolean, isstopped);
121533332Sdonn push(Symbol, curfunc);
121633332Sdonn push(Frame, curframe);
121733332Sdonn push(struct Frame, curframerec);
121833332Sdonn push(CallEnv, endproc);
121933332Sdonn push(Word, reg(PROGCTR));
122033332Sdonn push(Word, reg(STKP));
122133332Sdonn push(Word, reg(FRP));
122233332Sdonn }
122333332Sdonn
122433332Sdonn /*
122533332Sdonn * Pop back to the real world.
122633332Sdonn */
122733332Sdonn
popenv()122833332Sdonn public popenv()
122933332Sdonn {
123033332Sdonn String filename;
123133332Sdonn
123233332Sdonn setreg(FRP, pop(Word));
123333332Sdonn setreg(STKP, pop(Word));
123433332Sdonn setreg(PROGCTR, pop(Word));
123533332Sdonn endproc = pop(CallEnv);
123633332Sdonn curframerec = pop(struct Frame);
123733332Sdonn curframe = pop(Frame);
123833332Sdonn curfunc = pop(Symbol);
123933332Sdonn isstopped = pop(Boolean);
124033332Sdonn filename = pop(String);
124133332Sdonn curline = pop(Lineno);
124233332Sdonn pc = pop(Address);
124333332Sdonn setsource(filename);
124433332Sdonn }
124533332Sdonn
124633332Sdonn /*
124733332Sdonn * Flush the debuggee's standard output.
124833332Sdonn *
124933332Sdonn * This is VERY dependent on the use of stdio.
125033332Sdonn */
125133332Sdonn
flushoutput()125233332Sdonn public flushoutput()
125333332Sdonn {
125433332Sdonn Symbol p, iob;
125533332Sdonn Stack *savesp;
125633332Sdonn
125733332Sdonn p = lookup(identname("fflush", true));
125833332Sdonn while (p != nil and not isblock(p)) {
125933332Sdonn p = p->next_sym;
126033332Sdonn }
126133332Sdonn if (p != nil) {
126233332Sdonn iob = lookup(identname("_iob", true));
126333332Sdonn if (iob != nil) {
126433332Sdonn pushenv();
126533332Sdonn pc = codeloc(p) - FUNCOFFSET;
126633332Sdonn savesp = sp;
126733332Sdonn push(long, address(iob, nil) + sizeof(*stdout));
126833332Sdonn setreg(STKP, reg(STKP) - sizeof(long));
126933332Sdonn dwrite(savesp, reg(STKP), sizeof(long));
127033332Sdonn sp = savesp;
127133332Sdonn beginproc(p, 1);
127233332Sdonn stepto(return_addr());
127333332Sdonn popenv();
127433332Sdonn }
127533332Sdonn }
127633332Sdonn }
1277