121621Sdist /*
221621Sdist * Copyright (c) 1983 Regents of the University of California.
321621Sdist * All rights reserved. The Berkeley software License Agreement
421621Sdist * specifies the terms and conditions for redistribution.
521621Sdist */
69678Slinton
721621Sdist #ifndef lint
8*30797Sbostic static char sccsid[] = "@(#)runtime.c 5.3 (Berkeley) 04/06/87";
921621Sdist #endif not lint
109678Slinton
1118231Slinton static char rcsid[] = "$Header: runtime.c,v 1.5 84/12/26 10:41:52 linton Exp $";
1218231Slinton
139678Slinton /*
149678Slinton * Runtime organization dependent routines, mostly dealing with
159678Slinton * activation records.
169678Slinton */
179678Slinton
189678Slinton #include "defs.h"
199678Slinton #include "runtime.h"
209678Slinton #include "process.h"
219678Slinton #include "machine.h"
229678Slinton #include "events.h"
239678Slinton #include "mappings.h"
249678Slinton #include "symbols.h"
259678Slinton #include "tree.h"
269678Slinton #include "eval.h"
279678Slinton #include "operators.h"
289678Slinton #include "object.h"
2912546Scsvaf #include <sys/param.h>
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
5418231Slinton #define isstackaddr(addr) \
5518231Slinton (((addr) < 0x80000000) and ((addr) > 0x80000000 - 0x200 * 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;
11812546Scsvaf 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:
14713937Slinton dread(&frame, prev_frame, sizeof(struct Frame));
14813937Slinton if (ntramp == 1) {
14914620Ssam dread(&callpc, prev_frame + 84, sizeof(callpc));
15013937Slinton } else {
15113937Slinton callpc = frame.save_pc;
15213937Slinton }
15318231Slinton if (frame.save_fp == nil or frame.save_pc == (Address) -1) {
1549678Slinton newfrp = nil;
15518231Slinton } else if (isstackaddr(callpc)) {
15618231Slinton ntramp++;
15718231Slinton prev_frame = frame.save_fp;
15818231Slinton goto nextf;
15913937Slinton } else {
16012546Scsvaf frame.save_pc = callpc;
16113937Slinton ntramp = 0;
1629678Slinton mask = ((frame.mask >> 16) & 0x0fff);
16318231Slinton getsaveregs(newfrp, &frame, mask);
1649678Slinton newfrp->condition_handler = frame.condition_handler;
1659678Slinton newfrp->mask = mask;
1669678Slinton newfrp->save_ap = frame.save_ap;
1679678Slinton newfrp->save_fp = frame.save_fp;
1689678Slinton newfrp->save_pc = frame.save_pc;
1699678Slinton }
1709678Slinton return newfrp;
1719678Slinton }
1729678Slinton
1739678Slinton /*
17416618Ssam * Get the current frame information in the given Frame and store the
17516618Ssam * associated function in the given value-result parameter.
17616618Ssam */
17716618Ssam
getcurfunc(frp,fp)17816618Ssam private getcurfunc (frp, fp)
17916618Ssam Frame frp;
18016618Ssam Symbol *fp;
18116618Ssam {
18216618Ssam getcurframe(frp);
18316618Ssam *fp = whatblock(frp->save_pc);
18416618Ssam }
18516618Ssam
18616618Ssam /*
18716618Ssam * Return the frame associated with the next function up the call stack, or
18816618Ssam * nil if there is none. The function is returned in a value-result parameter.
18916618Ssam * For "inline" functions the statically outer function and same frame
19016618Ssam * are returned.
19116618Ssam */
19216618Ssam
nextfunc(frp,fp)19318231Slinton public Frame nextfunc (frp, fp)
19416618Ssam Frame frp;
19516618Ssam Symbol *fp;
19616618Ssam {
19716618Ssam Symbol t;
19816618Ssam Frame nfrp;
19916618Ssam
20016618Ssam t = *fp;
20116618Ssam checkref(t);
20216618Ssam if (isinline(t)) {
20316618Ssam t = container(t);
20416618Ssam nfrp = frp;
20516618Ssam } else {
20616618Ssam nfrp = nextframe(frp);
20716618Ssam if (nfrp == nil) {
20816618Ssam t = nil;
20916618Ssam } else {
21016618Ssam t = whatblock(nfrp->save_pc);
21116618Ssam }
21216618Ssam }
21316618Ssam *fp = t;
21416618Ssam return nfrp;
21516618Ssam }
21616618Ssam
21716618Ssam /*
2189678Slinton * Return the frame associated with the given function.
2199678Slinton * If the function is nil, return the most recently activated frame.
2209678Slinton *
2219678Slinton * Static allocation for the frame.
2229678Slinton */
2239678Slinton
findframe(f)2249678Slinton public Frame findframe(f)
2259678Slinton Symbol f;
2269678Slinton {
22718231Slinton Frame frp;
2289678Slinton static struct Frame frame;
22911866Slinton Symbol p;
23018231Slinton Boolean done;
2319678Slinton
2329678Slinton frp = &frame;
2339678Slinton getcurframe(frp);
23418231Slinton if (f != nil) {
23518231Slinton if (f == curfunc and curframe != nil) {
23618231Slinton *frp = *curframe;
23718231Slinton } else {
23818231Slinton done = false;
23918231Slinton p = whatblock(frp->save_pc);
24018231Slinton do {
24118231Slinton if (p == f) {
24218231Slinton done = true;
24318231Slinton } else if (p == program) {
24418231Slinton done = true;
24518231Slinton frp = nil;
24618231Slinton } else {
24718231Slinton frp = nextfunc(frp, &p);
24818231Slinton if (frp == nil) {
24918231Slinton done = true;
25018231Slinton }
25118231Slinton }
25218231Slinton } while (not done);
25315784Ssam }
25418231Slinton }
25518231Slinton return frp;
25618231Slinton }
25718231Slinton
25818231Slinton /*
25918231Slinton * Set the registers according to the given frame pointer.
26018231Slinton */
26118231Slinton
getnewregs(addr)26218231Slinton public getnewregs (addr)
26318231Slinton Address addr;
26418231Slinton {
26518231Slinton struct Frame frame;
26618231Slinton integer i, j, mask;
26718231Slinton
26818231Slinton dread(&frame, addr, sizeof(frame));
26918231Slinton setreg(ARGP, frame.save_ap);
27018231Slinton setreg(FRP, frame.save_fp);
27118231Slinton setreg(PROGCTR, frame.save_pc);
27218231Slinton mask = ((frame.mask >> 16) & 0x0fff);
27318231Slinton j = 0;
27418231Slinton for (i = 0; i < NSAVEREG; i++) {
27518231Slinton if (bis(mask, i)) {
27618231Slinton setreg(i, frame.save_reg[j]);
27718231Slinton ++j;
27816636Ssam }
2799678Slinton }
28018231Slinton pc = frame.save_pc;
28118231Slinton setcurfunc(whatblock(pc));
2829678Slinton }
2839678Slinton
2849678Slinton /*
2859678Slinton * Find the return address of the current procedure/function.
2869678Slinton */
2879678Slinton
return_addr()2889678Slinton public Address return_addr()
2899678Slinton {
2909678Slinton Frame frp;
2919678Slinton Address addr;
2929678Slinton struct Frame frame;
2939678Slinton
2949678Slinton frp = &frame;
2959678Slinton getcurframe(frp);
2969678Slinton frp = nextframe(frp);
2979678Slinton if (frp == nil) {
2989678Slinton addr = 0;
2999678Slinton } else {
3009678Slinton addr = frp->save_pc;
3019678Slinton }
3029678Slinton return addr;
3039678Slinton }
3049678Slinton
3059678Slinton /*
3069678Slinton * Push the value associated with the current function.
3079678Slinton */
3089678Slinton
pushretval(len,isindirect)3099678Slinton public pushretval(len, isindirect)
31018231Slinton integer len;
31118231Slinton boolean isindirect;
3129678Slinton {
3139678Slinton Word r0;
3149678Slinton
3159678Slinton r0 = reg(0);
3169678Slinton if (isindirect) {
3179678Slinton rpush((Address) r0, len);
3189678Slinton } else {
3199678Slinton switch (len) {
3209678Slinton case sizeof(char):
3219678Slinton push(char, r0);
3229678Slinton break;
3239678Slinton
3249678Slinton case sizeof(short):
3259678Slinton push(short, r0);
3269678Slinton break;
3279678Slinton
3289678Slinton default:
3299678Slinton if (len == sizeof(Word)) {
3309678Slinton push(Word, r0);
3319678Slinton } else if (len == 2*sizeof(Word)) {
3329678Slinton push(Word, r0);
3339678Slinton push(Word, reg(1));
3349678Slinton } else {
33518231Slinton error("[internal error: bad size %d in pushretval]", len);
3369678Slinton }
3379678Slinton break;
3389678Slinton }
3399678Slinton }
3409678Slinton }
3419678Slinton
3429678Slinton /*
3439678Slinton * Return the base address for locals in the given frame.
3449678Slinton */
3459678Slinton
locals_base(frp)3469678Slinton public Address locals_base(frp)
34718231Slinton Frame frp;
3489678Slinton {
3499678Slinton return (frp == nil) ? reg(FRP) : frp->save_fp;
3509678Slinton }
3519678Slinton
3529678Slinton /*
3539678Slinton * Return the base address for arguments in the given frame.
3549678Slinton */
3559678Slinton
args_base(frp)3569678Slinton public Address args_base(frp)
35718231Slinton Frame frp;
3589678Slinton {
3599678Slinton return (frp == nil) ? reg(ARGP) : frp->save_ap;
3609678Slinton }
3619678Slinton
3629678Slinton /*
3639678Slinton * Return saved register n from the given frame.
3649678Slinton */
3659678Slinton
savereg(n,frp)3669678Slinton public Word savereg(n, frp)
36718231Slinton integer n;
36818231Slinton Frame frp;
3699678Slinton {
37018231Slinton Word w;
3719678Slinton
3729678Slinton if (frp == nil) {
3739678Slinton w = reg(n);
3749678Slinton } else {
3759678Slinton switch (n) {
3769678Slinton case ARGP:
3779678Slinton w = frp->save_ap;
3789678Slinton break;
3799678Slinton
3809678Slinton case FRP:
3819678Slinton w = frp->save_fp;
3829678Slinton break;
3839678Slinton
3849678Slinton case STKP:
3859678Slinton w = reg(STKP);
3869678Slinton break;
3879678Slinton
3889678Slinton case PROGCTR:
3899678Slinton w = frp->save_pc;
3909678Slinton break;
3919678Slinton
3929678Slinton default:
3939678Slinton assert(n >= 0 and n < NSAVEREG);
3949678Slinton w = frp->save_reg[n];
3959678Slinton break;
3969678Slinton }
3979678Slinton }
3989678Slinton return w;
3999678Slinton }
4009678Slinton
4019678Slinton /*
4029678Slinton * Return the nth argument to the current procedure.
4039678Slinton */
4049678Slinton
argn(n,frp)4059678Slinton public Word argn(n, frp)
40618231Slinton integer n;
4079678Slinton Frame frp;
4089678Slinton {
4099678Slinton Word w;
4109678Slinton
4119678Slinton dread(&w, args_base(frp) + (n * sizeof(Word)), sizeof(w));
4129678Slinton return w;
4139678Slinton }
4149678Slinton
4159678Slinton /*
41618231Slinton * Print a list of currently active blocks starting with most recent.
4179678Slinton */
4189678Slinton
wherecmd()41918231Slinton public wherecmd()
4209678Slinton {
42118231Slinton walkstack(false);
4229678Slinton }
4239678Slinton
4249678Slinton /*
42518231Slinton * Print the variables in the given frame or the current one if nil.
4269678Slinton */
4279678Slinton
dump(func)42818231Slinton public dump (func)
42918231Slinton Symbol func;
4309678Slinton {
43118231Slinton Symbol f;
43218231Slinton Frame frp;
43318231Slinton
43418231Slinton if (func == nil) {
43518231Slinton f = curfunc;
43618231Slinton if (curframe != nil) {
43718231Slinton frp = curframe;
43818231Slinton } else {
43918231Slinton frp = findframe(f);
44018231Slinton }
44118231Slinton } else {
44218231Slinton f = func;
44318231Slinton frp = findframe(f);
44418231Slinton }
44518231Slinton showaggrs = true;
44618231Slinton printcallinfo(f, frp);
44718231Slinton dumpvars(f, frp);
4489678Slinton }
4499678Slinton
4509678Slinton /*
45118231Slinton * Dump all values.
4529678Slinton */
4539678Slinton
dumpall()45418231Slinton public dumpall ()
4559678Slinton {
4569678Slinton walkstack(true);
4579678Slinton }
4589678Slinton
4599678Slinton /*
4609678Slinton * Walk the stack of active procedures printing information
4619678Slinton * about each active procedure.
4629678Slinton */
4639678Slinton
walkstack(dumpvariables)4649678Slinton private walkstack(dumpvariables)
4659678Slinton Boolean dumpvariables;
4669678Slinton {
46718231Slinton Frame frp;
46818231Slinton boolean save;
46916618Ssam Symbol f;
4709678Slinton struct Frame frame;
4719678Slinton
47218231Slinton if (notstarted(process) or isfinished(process)) {
4739678Slinton error("program is not active");
4749678Slinton } else {
4759678Slinton save = walkingstack;
4769678Slinton walkingstack = true;
47718231Slinton showaggrs = dumpvariables;
4789678Slinton frp = &frame;
47916618Ssam getcurfunc(frp, &f);
48018231Slinton for (;;) {
48118231Slinton printcallinfo(f, frp);
4829678Slinton if (dumpvariables) {
4839678Slinton dumpvars(f, frp);
4849678Slinton putchar('\n');
4859678Slinton }
48616618Ssam frp = nextfunc(frp, &f);
48718231Slinton if (frp == nil or f == program) {
48818231Slinton break;
48918231Slinton }
49018231Slinton }
4919678Slinton if (dumpvariables) {
4929678Slinton printf("in \"%s\":\n", symname(program));
4939678Slinton dumpvars(program, nil);
4949678Slinton putchar('\n');
4959678Slinton }
4969678Slinton walkingstack = save;
4979678Slinton }
4989678Slinton }
4999678Slinton
5009678Slinton /*
50118231Slinton * Print out the information about a call, i.e.,
50218231Slinton * routine name, parameter values, and source location.
50318231Slinton */
50418231Slinton
printcallinfo(f,frp)50518231Slinton private printcallinfo (f, frp)
50618231Slinton Symbol f;
50718231Slinton Frame frp;
50818231Slinton {
50918231Slinton Lineno line;
51018231Slinton Address savepc;
51118231Slinton
51218231Slinton savepc = frp->save_pc;
51318231Slinton if (frp->save_fp != reg(FRP)) {
51418231Slinton savepc -= 1;
51518231Slinton }
51618231Slinton printname(stdout, f);
51718231Slinton if (not isinline(f)) {
51818231Slinton printparams(f, frp);
51918231Slinton }
52018231Slinton line = srcline(savepc);
52118231Slinton if (line != 0) {
52218231Slinton printf(", line %d", line);
52318231Slinton printf(" in \"%s\"\n", srcfilename(savepc));
52418231Slinton } else {
52518231Slinton printf(" at 0x%x\n", savepc);
52618231Slinton }
52718231Slinton }
52818231Slinton
52918231Slinton /*
53016618Ssam * Set the current function to the given symbol.
53116618Ssam * We must adjust "curframe" so that subsequent operations are
53216618Ssam * not confused; for simplicity we simply clear it.
53316618Ssam */
53416618Ssam
setcurfunc(f)53516618Ssam public setcurfunc (f)
53616618Ssam Symbol f;
53716618Ssam {
53816618Ssam curfunc = f;
53916618Ssam curframe = nil;
54016618Ssam }
54116618Ssam
54216618Ssam /*
54318231Slinton * Return the frame for the current function.
54418231Slinton * The space for the frame is allocated statically.
54518231Slinton */
54618231Slinton
curfuncframe()54718231Slinton public Frame curfuncframe ()
54818231Slinton {
54918231Slinton static struct Frame frame;
55018231Slinton Frame frp;
55118231Slinton
55218231Slinton if (curframe == nil) {
55318231Slinton frp = findframe(curfunc);
55418231Slinton curframe = &curframerec;
55518231Slinton *curframe = *frp;
55618231Slinton } else {
55718231Slinton frp = &frame;
55818231Slinton *frp = *curframe;
55918231Slinton }
56018231Slinton return frp;
56118231Slinton }
56218231Slinton
56318231Slinton /*
56416618Ssam * Set curfunc to be N up/down the stack from its current value.
56516618Ssam */
56616618Ssam
up(n)56716618Ssam public up (n)
56816618Ssam integer n;
56916618Ssam {
57016618Ssam integer i;
57116618Ssam Symbol f;
57216618Ssam Frame frp;
57316618Ssam boolean done;
57416618Ssam
57516618Ssam if (not isactive(program)) {
57616618Ssam error("program is not active");
57716618Ssam } else if (curfunc == nil) {
57816618Ssam error("no current function");
57916618Ssam } else {
58016618Ssam i = 0;
58116618Ssam f = curfunc;
58218231Slinton frp = curfuncframe();
58316618Ssam done = false;
58416618Ssam do {
58516618Ssam if (frp == nil) {
58616618Ssam done = true;
58716618Ssam error("not that many levels");
58816618Ssam } else if (i >= n) {
58916618Ssam done = true;
59016618Ssam curfunc = f;
59116618Ssam curframe = &curframerec;
59216618Ssam *curframe = *frp;
59318231Slinton showaggrs = false;
59418231Slinton printcallinfo(curfunc, curframe);
59516618Ssam } else if (f == program) {
59616618Ssam done = true;
59716618Ssam error("not that many levels");
59816618Ssam } else {
59916618Ssam frp = nextfunc(frp, &f);
60016618Ssam }
60116618Ssam ++i;
60216618Ssam } while (not done);
60316618Ssam }
60416618Ssam }
60516618Ssam
down(n)60616618Ssam public down (n)
60716618Ssam integer n;
60816618Ssam {
60916618Ssam integer i, depth;
61018231Slinton Frame frp, curfrp;
61116618Ssam Symbol f;
61216618Ssam struct Frame frame;
61316618Ssam
61416618Ssam if (not isactive(program)) {
61516618Ssam error("program is not active");
61616618Ssam } else if (curfunc == nil) {
61716618Ssam error("no current function");
61816618Ssam } else {
61916618Ssam depth = 0;
62016618Ssam frp = &frame;
62116618Ssam getcurfunc(frp, &f);
62216618Ssam if (curframe == nil) {
62318231Slinton curfrp = findframe(curfunc);
62416618Ssam curframe = &curframerec;
62518231Slinton *curframe = *curfrp;
62616618Ssam }
62716618Ssam while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) {
62816618Ssam frp = nextfunc(frp, &f);
62916618Ssam ++depth;
63016618Ssam }
63116618Ssam if (f == nil or n > depth) {
63216618Ssam error("not that many levels");
63316618Ssam } else {
63416618Ssam depth -= n;
63516618Ssam frp = &frame;
63616618Ssam getcurfunc(frp, &f);
63716618Ssam for (i = 0; i < depth; i++) {
63816618Ssam frp = nextfunc(frp, &f);
63916618Ssam assert(frp != nil);
64016618Ssam }
64116618Ssam curfunc = f;
64216618Ssam *curframe = *frp;
64318231Slinton showaggrs = false;
64418231Slinton printcallinfo(curfunc, curframe);
64516618Ssam }
64616618Ssam }
64716618Ssam }
64816618Ssam
64916618Ssam /*
6509678Slinton * Find the entry point of a procedure or function.
6519678Slinton */
6529678Slinton
findbeginning(f)65318231Slinton public findbeginning (f)
6549678Slinton Symbol f;
6559678Slinton {
65616618Ssam if (isinternal(f)) {
65716618Ssam f->symvalue.funcv.beginaddr += 15;
65816618Ssam } else {
65916618Ssam f->symvalue.funcv.beginaddr += 2;
66016618Ssam }
6619678Slinton }
6629678Slinton
6639678Slinton /*
6649678Slinton * Return the address corresponding to the first line in a function.
6659678Slinton */
6669678Slinton
firstline(f)6679678Slinton public Address firstline(f)
6689678Slinton Symbol f;
6699678Slinton {
6709678Slinton Address addr;
6719678Slinton
6729678Slinton addr = codeloc(f);
6739678Slinton while (linelookup(addr) == 0 and addr < objsize) {
6749678Slinton ++addr;
6759678Slinton }
6769678Slinton if (addr == objsize) {
6779678Slinton addr = -1;
6789678Slinton }
6799678Slinton return addr;
6809678Slinton }
6819678Slinton
6829678Slinton /*
6839678Slinton * Catcher drops strike three ...
6849678Slinton */
6859678Slinton
runtofirst()6869678Slinton public runtofirst()
6879678Slinton {
6889678Slinton Address addr;
6899678Slinton
6909678Slinton addr = pc;
6919678Slinton while (linelookup(addr) == 0 and addr < objsize) {
6929678Slinton ++addr;
6939678Slinton }
6949678Slinton if (addr < objsize) {
6959678Slinton stepto(addr);
6969678Slinton }
6979678Slinton }
6989678Slinton
6999678Slinton /*
7009678Slinton * Return the address corresponding to the end of the program.
7019678Slinton *
7029678Slinton * We look for the entry to "exit".
7039678Slinton */
7049678Slinton
lastaddr()7059678Slinton public Address lastaddr()
7069678Slinton {
70718231Slinton Symbol s;
7089678Slinton
7099678Slinton s = lookup(identname("exit", true));
7109678Slinton if (s == nil) {
7119678Slinton panic("can't find exit");
7129678Slinton }
7139678Slinton return codeloc(s);
7149678Slinton }
7159678Slinton
7169678Slinton /*
7179678Slinton * Decide if the given function is currently active.
7189678Slinton *
7199678Slinton * We avoid calls to "findframe" during a stack trace for efficiency.
7209678Slinton * Presumably information evaluated while walking the stack is active.
7219678Slinton */
7229678Slinton
isactive(f)7239678Slinton public Boolean isactive(f)
7249678Slinton Symbol f;
7259678Slinton {
72618231Slinton Boolean b;
7279678Slinton
7289678Slinton if (isfinished(process)) {
7299678Slinton b = false;
7309678Slinton } else {
7319678Slinton if (walkingstack or f == program or
7329678Slinton (ismodule(f) and isactive(container(f)))) {
7339678Slinton b = true;
7349678Slinton } else {
7359678Slinton b = (Boolean) (findframe(f) != nil);
7369678Slinton }
7379678Slinton }
7389678Slinton return b;
7399678Slinton }
7409678Slinton
7419678Slinton /*
7429678Slinton * Evaluate a call to a procedure.
7439678Slinton */
7449678Slinton
callproc(exprnode,isfunc)74518231Slinton public callproc(exprnode, isfunc)
74618231Slinton Node exprnode;
74718231Slinton boolean isfunc;
7489678Slinton {
74918231Slinton Node procnode, arglist;
7509678Slinton Symbol proc;
75118231Slinton integer argc;
7529678Slinton
75318231Slinton procnode = exprnode->value.arg[0];
75418231Slinton arglist = exprnode->value.arg[1];
7559678Slinton if (procnode->op != O_SYM) {
7569678Slinton beginerrmsg();
7579678Slinton fprintf(stderr, "can't call \"");
7589678Slinton prtree(stderr, procnode);
7599678Slinton fprintf(stderr, "\"");
7609678Slinton enderrmsg();
7619678Slinton }
7629678Slinton assert(procnode->op == O_SYM);
7639678Slinton proc = procnode->value.sym;
7649678Slinton if (not isblock(proc)) {
7659678Slinton error("\"%s\" is not a procedure or function", symname(proc));
7669678Slinton }
76718231Slinton endproc.isfunc = isfunc;
76818231Slinton endproc.callnode = exprnode;
76918231Slinton endproc.cmdnode = topnode;
7709678Slinton pushenv();
7719678Slinton pc = codeloc(proc);
7729678Slinton argc = pushargs(proc, arglist);
7739678Slinton beginproc(proc, argc);
77418231Slinton event_once(
77518231Slinton build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)),
77618231Slinton buildcmdlist(build(O_PROCRTN, proc))
77718231Slinton );
77818231Slinton isstopped = false;
77918231Slinton if (not bpact()) {
78018231Slinton isstopped = true;
78118231Slinton cont(0);
78218231Slinton }
78318231Slinton /*
78418231Slinton * bpact() won't return true, it will call printstatus() and go back
78518231Slinton * to command input if a breakpoint is found.
78618231Slinton */
7879678Slinton /* NOTREACHED */
7889678Slinton }
7899678Slinton
7909678Slinton /*
7919678Slinton * Push the arguments on the process' stack. We do this by first
7929678Slinton * evaluating them on the "eval" stack, then copying into the process'
7939678Slinton * space.
7949678Slinton */
7959678Slinton
pushargs(proc,arglist)79618231Slinton private integer pushargs(proc, arglist)
7979678Slinton Symbol proc;
7989678Slinton Node arglist;
7999678Slinton {
8009678Slinton Stack *savesp;
8019678Slinton int argc, args_size;
8029678Slinton
8039678Slinton savesp = sp;
80425807Sdonn if (varIsSet("$unsafecall")) {
80525807Sdonn argc = unsafe_evalargs(proc, arglist);
80625807Sdonn } else {
80725807Sdonn argc = evalargs(proc, arglist);
80825807Sdonn }
8099678Slinton args_size = sp - savesp;
8109678Slinton setreg(STKP, reg(STKP) - args_size);
8119678Slinton dwrite(savesp, reg(STKP), args_size);
8129678Slinton sp = savesp;
8139678Slinton return argc;
8149678Slinton }
8159678Slinton
8169678Slinton /*
81716618Ssam * Check to see if an expression is correct for a given parameter.
81816618Ssam * If the given parameter is false, don't worry about type inconsistencies.
81916618Ssam *
82016618Ssam * Return whether or not it is ok.
8219678Slinton */
8229678Slinton
chkparam(actual,formal,chk)82316618Ssam private boolean chkparam (actual, formal, chk)
82416618Ssam Node actual;
82516618Ssam Symbol formal;
82616618Ssam boolean chk;
82716618Ssam {
82816618Ssam boolean b;
82916618Ssam
83016618Ssam b = true;
83116618Ssam if (chk) {
83216618Ssam if (formal == nil) {
83316618Ssam beginerrmsg();
83416618Ssam fprintf(stderr, "too many parameters");
83516618Ssam b = false;
83616618Ssam } else if (not compatible(formal->type, actual->nodetype)) {
83716618Ssam beginerrmsg();
83816618Ssam fprintf(stderr, "type mismatch for %s", symname(formal));
83916618Ssam b = false;
84016618Ssam }
84116618Ssam }
84218231Slinton if (b and formal != nil and
84318231Slinton isvarparam(formal) and not isopenarray(formal->type) and
84418231Slinton not (
84518231Slinton actual->op == O_RVAL or actual->nodetype == t_addr or
84618231Slinton (
84718231Slinton actual->op == O_TYPERENAME and
84818231Slinton (
84918231Slinton actual->value.arg[0]->op == O_RVAL or
85018231Slinton actual->value.arg[0]->nodetype == t_addr
85118231Slinton )
85218231Slinton )
85318231Slinton )
85418231Slinton ) {
85516618Ssam beginerrmsg();
85616618Ssam fprintf(stderr, "expected variable, found \"");
85716618Ssam prtree(stderr, actual);
85816618Ssam fprintf(stderr, "\"");
85916618Ssam b = false;
86016618Ssam }
86116618Ssam return b;
86216618Ssam }
86316618Ssam
86416618Ssam /*
86516618Ssam * Pass an expression to a particular parameter.
86616618Ssam *
86716618Ssam * Normally we pass either the address or value, but in some cases
86816618Ssam * (such as C strings) we want to copy the value onto the stack and
86916618Ssam * pass its address.
87018231Slinton *
87118231Slinton * Another special case raised by strings is the possibility that
87218231Slinton * the actual parameter will be larger than the formal, even with
87318231Slinton * appropriate type-checking. This occurs because we assume during
87418231Slinton * evaluation that strings are null-terminated, whereas some languages,
87518231Slinton * notably Pascal, do not work under that assumption.
87616618Ssam */
87716618Ssam
passparam(actual,formal)87816618Ssam private passparam (actual, formal)
87916618Ssam Node actual;
88016618Ssam Symbol formal;
88116618Ssam {
88216618Ssam boolean b;
88316618Ssam Address addr;
88416618Ssam Stack *savesp;
88518231Slinton integer actsize, formsize;
88616618Ssam
88718231Slinton if (formal != nil and isvarparam(formal) and
88818231Slinton (not isopenarray(formal->type))
88918231Slinton ) {
89016618Ssam addr = lval(actual->value.arg[0]);
89116618Ssam push(Address, addr);
89216618Ssam } else if (passaddr(formal, actual->nodetype)) {
89316618Ssam savesp = sp;
89416618Ssam eval(actual);
89518231Slinton actsize = sp - savesp;
89618231Slinton setreg(STKP,
89718231Slinton reg(STKP) - ((actsize + sizeof(Word) - 1) & ~(sizeof(Word) - 1))
89818231Slinton );
89918231Slinton dwrite(savesp, reg(STKP), actsize);
90016618Ssam sp = savesp;
90116618Ssam push(Address, reg(STKP));
90216618Ssam if (formal != nil and isopenarray(formal->type)) {
90318231Slinton push(integer, actsize div size(formal->type->type));
90416618Ssam }
90518231Slinton } else if (formal != nil) {
90618231Slinton formsize = size(formal);
90718231Slinton savesp = sp;
90818231Slinton eval(actual);
90918231Slinton actsize = sp - savesp;
91018231Slinton if (actsize > formsize) {
91118231Slinton sp -= (actsize - formsize);
91218231Slinton }
91316618Ssam } else {
91416618Ssam eval(actual);
91516618Ssam }
91616618Ssam }
91716618Ssam
91816618Ssam /*
91916618Ssam * Evaluate an argument list left-to-right.
92016618Ssam */
92116618Ssam
evalargs(proc,arglist)92218231Slinton private integer evalargs(proc, arglist)
9239678Slinton Symbol proc;
9249678Slinton Node arglist;
9259678Slinton {
92616618Ssam Node p, actual;
92716618Ssam Symbol formal;
9289678Slinton Stack *savesp;
92918231Slinton integer count;
93016618Ssam boolean chk;
9319678Slinton
9329678Slinton savesp = sp;
9339678Slinton count = 0;
93416618Ssam formal = proc->chain;
93516618Ssam chk = (boolean) (not nosource(proc));
9369678Slinton for (p = arglist; p != nil; p = p->value.arg[1]) {
93716618Ssam assert(p->op == O_COMMA);
93816618Ssam actual = p->value.arg[0];
93916618Ssam if (not chkparam(actual, formal, chk)) {
94016618Ssam fprintf(stderr, " in call to %s", symname(proc));
9419678Slinton sp = savesp;
94216618Ssam enderrmsg();
9439678Slinton }
94416618Ssam passparam(actual, formal);
94516618Ssam if (formal != nil) {
94616618Ssam formal = formal->chain;
9479678Slinton }
9489678Slinton ++count;
9499678Slinton }
95016618Ssam if (chk) {
95116618Ssam if (formal != nil) {
95216618Ssam sp = savesp;
95316618Ssam error("not enough parameters to %s", symname(proc));
95416618Ssam }
9559678Slinton }
9569678Slinton return count;
9579678Slinton }
9589678Slinton
95925807Sdonn /*
96025807Sdonn * Evaluate an argument list without concern for matching the formal
96125807Sdonn * parameters of a function in type or quantity. Useful for functions
96225807Sdonn * like C's printf().
96325807Sdonn */
96425807Sdonn
unsafe_evalargs(proc,arglist)96525807Sdonn private integer unsafe_evalargs(proc, arglist)
96625807Sdonn Symbol proc;
96725807Sdonn Node arglist;
96825807Sdonn {
96925807Sdonn Node p;
97025807Sdonn Integer count;
97125807Sdonn
97225807Sdonn count = 0;
97325807Sdonn for (p = arglist; p != nil; p = p->value.arg[1]) {
97425807Sdonn assert(p->op == O_COMMA);
97525807Sdonn eval(p->value.arg[0]);
97625807Sdonn ++count;
97725807Sdonn }
97825807Sdonn return count;
97925807Sdonn }
98025807Sdonn
procreturn(f)9819678Slinton public procreturn(f)
9829678Slinton Symbol f;
9839678Slinton {
98418231Slinton integer retvalsize;
98518231Slinton Node tmp;
98618231Slinton char *copy;
98718231Slinton
9889678Slinton flushoutput();
9899678Slinton popenv();
99018231Slinton if (endproc.isfunc) {
99118231Slinton retvalsize = size(f->type);
99218231Slinton if (retvalsize > sizeof(long)) {
99318231Slinton pushretval(retvalsize, true);
99418231Slinton copy = newarr(char, retvalsize);
99518231Slinton popn(retvalsize, copy);
99618231Slinton tmp = build(O_SCON, copy);
99718231Slinton } else {
99818231Slinton tmp = build(O_LCON, (long) (reg(0)));
99918231Slinton }
100018231Slinton tmp->nodetype = f->type;
100118231Slinton tfree(endproc.callnode);
100218231Slinton *(endproc.callnode) = *(tmp);
100318231Slinton dispose(tmp);
100418231Slinton eval(endproc.cmdnode);
100518231Slinton } else {
100618231Slinton putchar('\n');
100718231Slinton printname(stdout, f);
1008*30797Sbostic printf("%s returns successfully\n", symname(f));
100918231Slinton }
10109678Slinton erecover();
10119678Slinton }
10129678Slinton
10139678Slinton /*
10149678Slinton * Push the current environment.
10159678Slinton */
10169678Slinton
pushenv()10179678Slinton private pushenv()
10189678Slinton {
10199678Slinton push(Address, pc);
10209678Slinton push(Lineno, curline);
10219678Slinton push(String, cursource);
10229678Slinton push(Boolean, isstopped);
10239678Slinton push(Symbol, curfunc);
102416618Ssam push(Frame, curframe);
102516618Ssam push(struct Frame, curframerec);
102618231Slinton push(CallEnv, endproc);
10279678Slinton push(Word, reg(PROGCTR));
10289678Slinton push(Word, reg(STKP));
10299678Slinton }
10309678Slinton
10319678Slinton /*
10329678Slinton * Pop back to the real world.
10339678Slinton */
10349678Slinton
popenv()10359678Slinton public popenv()
10369678Slinton {
103718231Slinton String filename;
10389678Slinton
10399678Slinton setreg(STKP, pop(Word));
10409678Slinton setreg(PROGCTR, pop(Word));
104118231Slinton endproc = pop(CallEnv);
104216618Ssam curframerec = pop(struct Frame);
104316618Ssam curframe = pop(Frame);
10449678Slinton curfunc = pop(Symbol);
10459678Slinton isstopped = pop(Boolean);
10469678Slinton filename = pop(String);
10479678Slinton curline = pop(Lineno);
10489678Slinton pc = pop(Address);
10499678Slinton setsource(filename);
10509678Slinton }
10519678Slinton
10529678Slinton /*
10539678Slinton * Flush the debuggee's standard output.
10549678Slinton *
10559678Slinton * This is VERY dependent on the use of stdio.
10569678Slinton */
10579678Slinton
flushoutput()10589678Slinton public flushoutput()
10599678Slinton {
106018231Slinton Symbol p, iob;
106118231Slinton Stack *savesp;
10629678Slinton
10639678Slinton p = lookup(identname("fflush", true));
10649678Slinton while (p != nil and not isblock(p)) {
10659678Slinton p = p->next_sym;
10669678Slinton }
10679678Slinton if (p != nil) {
10689678Slinton iob = lookup(identname("_iob", true));
10699678Slinton if (iob != nil) {
10709678Slinton pushenv();
10719678Slinton pc = codeloc(p);
10729678Slinton savesp = sp;
10739678Slinton push(long, address(iob, nil) + sizeof(struct _iobuf));
10749678Slinton setreg(STKP, reg(STKP) - sizeof(long));
10759678Slinton dwrite(savesp, reg(STKP), sizeof(long));
10769678Slinton sp = savesp;
10779678Slinton beginproc(p, 1);
10789678Slinton stepto(return_addr());
10799678Slinton popenv();
10809678Slinton }
10819678Slinton }
10829678Slinton }
1083