manual page first distributed with 4.3BSD
[unix-history] / usr / src / old / dbx / runtime.vax.c
index 08799d5..889a67e 100644 (file)
@@ -1,6 +1,8 @@
 /* Copyright (c) 1982 Regents of the University of California */
 
 /* Copyright (c) 1982 Regents of the University of California */
 
-static char sccsid[] = "@(#)runtime.vax.c 1.3 %G%";
+static char sccsid[] = "@(#)runtime.vax.c      1.13 (Berkeley) %G%";
+
+static char rcsid[] = "$Header: runtime.c,v 1.5 84/12/26 10:41:52 linton Exp $";
 
 /*
  * Runtime organization dependent routines, mostly dealing with
 
 /*
  * Runtime organization dependent routines, mostly dealing with
@@ -18,6 +20,7 @@ static char sccsid[] = "@(#)runtime.vax.c 1.3 %G%";
 #include "eval.h"
 #include "operators.h"
 #include "object.h"
 #include "eval.h"
 #include "operators.h"
 #include "object.h"
+#include <sys/param.h>
 
 #ifndef public
 typedef struct Frame *Frame;
 
 #ifndef public
 typedef struct Frame *Frame;
@@ -28,22 +31,37 @@ typedef struct Frame *Frame;
 #define NSAVEREG 12
 
 struct Frame {
 #define NSAVEREG 12
 
 struct Frame {
-    Integer condition_handler;
-    Integer mask;
+    integer condition_handler;
+    integer mask;
     Address save_ap;           /* argument pointer */
     Address save_fp;           /* frame pointer */
     Address save_pc;           /* program counter */
     Word save_reg[NSAVEREG];   /* not necessarily there */
 };
 
     Address save_ap;           /* argument pointer */
     Address save_fp;           /* frame pointer */
     Address save_pc;           /* program counter */
     Word save_reg[NSAVEREG];   /* not necessarily there */
 };
 
+private Frame curframe = nil;
+private struct Frame curframerec;
 private Boolean walkingstack = false;
 
 private Boolean walkingstack = false;
 
+#define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp)
+
+#define isstackaddr(addr) \
+    (((addr) < 0x80000000) and ((addr) > 0x80000000 - 0x200 * UPAGES))
+
+typedef struct {
+    Node callnode;
+    Node cmdnode;
+    boolean isfunc;
+} CallEnv;
+
+private CallEnv endproc;
+
 /*
  * Set a frame to the current activation record.
  */
 
 private getcurframe(frp)
 /*
  * Set a frame to the current activation record.
  */
 
 private getcurframe(frp)
-register Frame frp;
+Frame frp;
 {
     register int i;
 
 {
     register int i;
 
@@ -57,34 +75,86 @@ register Frame frp;
     }
 }
 
     }
 }
 
+/*
+ * Get the saved registers from one frame to another
+ * given mask specifying which registers were actually saved.
+ */
+
+#define bis(b, n) ((b & (1 << (n))) != 0)
+
+private getsaveregs (newfrp, frp, mask)
+Frame newfrp, frp;
+integer mask;
+{
+    integer i, j;
+
+    j = 0;
+    for (i = 0; i < NSAVEREG; i++) {
+       if (bis(mask, i)) {
+           newfrp->save_reg[i] = frp->save_reg[j];
+           ++j;
+       }
+    }
+}
+
 /*
  * Return a pointer to the next activation record up the stack.
  * Return nil if there is none.
  * Writes over space pointed to by given argument.
  */
 
 /*
  * Return a pointer to the next activation record up the stack.
  * Return nil if there is none.
  * Writes over space pointed to by given argument.
  */
 
-#define bis(b, n) ((b & (1 << (n))) != 0)
-
 private Frame nextframe(frp)
 Frame frp;
 {
 private Frame nextframe(frp)
 Frame frp;
 {
-    register Frame newfrp;
+    Frame newfrp;
     struct Frame frame;
     struct Frame frame;
-    register Integer i, j, mask;
+    integer mask;
+    Address prev_frame, callpc; 
+    static integer ntramp = 0;
 
     newfrp = frp;
 
     newfrp = frp;
-    dread(&frame, newfrp->save_fp, sizeof(struct Frame));
-    if (frame.save_fp == nil) {
+    prev_frame = frp->save_fp;
+
+/*
+ *  The check for interrupt generated frames is taken from adb with only
+ *  partial understanding.  If you're in "sub" and on a sigxxx "sigsub"
+ *  gets control, then the stack does NOT look like <main, sub, sigsub>.
+ *
+ *  As best I can make out it looks like:
+ *
+ *     <main, (machine check exception block + sub), sysframe, sigsub>.
+ *
+ *  When the signal occurs an exception block and a frame for the routine
+ *  in which it occured are pushed on the user stack.  Then another frame
+ *  is pushed corresponding to a call from the kernel to sigsub.
+ *
+ *  The addr in sub at which the exception occured is not in sub.save_pc
+ *  but in the machine check exception block.  It is at the magic address
+ *  fp + 84.
+ *
+ *  The current approach ignores the sys_frame (what adb reports as sigtramp)
+ *  and takes the pc for sub from the exception block.  This allows the
+ *  "where" command to report <main, sub, sigsub>, which seems reasonable.
+ */
+
+nextf:
+    dread(&frame, prev_frame, sizeof(struct Frame));
+    if (ntramp == 1) {
+       dread(&callpc, prev_frame + 84, sizeof(callpc));
+    } else {
+       callpc = frame.save_pc;
+    }
+    if (frame.save_fp == nil or frame.save_pc == (Address) -1) {
        newfrp = nil;
        newfrp = nil;
+    } else if (isstackaddr(callpc)) {
+       ntramp++;
+       prev_frame = frame.save_fp;
+       goto nextf;
     } else {
     } else {
+       frame.save_pc = callpc;
+        ntramp = 0;
        mask = ((frame.mask >> 16) & 0x0fff);
        mask = ((frame.mask >> 16) & 0x0fff);
-       j = 0;
-       for (i = 0; i < NSAVEREG; i++) {
-           if (bis(mask, i)) {
-               newfrp->save_reg[i] = frame.save_reg[j];
-               ++j;
-           }
-       }
+       getsaveregs(newfrp, &frame, mask);
        newfrp->condition_handler = frame.condition_handler;
        newfrp->mask = mask;
        newfrp->save_ap = frame.save_ap;
        newfrp->condition_handler = frame.condition_handler;
        newfrp->mask = mask;
        newfrp->save_ap = frame.save_ap;
@@ -94,6 +164,50 @@ Frame frp;
     return newfrp;
 }
 
     return newfrp;
 }
 
+/*
+ * Get the current frame information in the given Frame and store the
+ * associated function in the given value-result parameter.
+ */
+
+private getcurfunc (frp, fp)
+Frame frp;
+Symbol *fp;
+{
+    getcurframe(frp);
+    *fp = whatblock(frp->save_pc);
+}
+
+/*
+ * Return the frame associated with the next function up the call stack, or
+ * nil if there is none.  The function is returned in a value-result parameter.
+ * For "inline" functions the statically outer function and same frame
+ * are returned.
+ */
+
+public Frame nextfunc (frp, fp)
+Frame frp;
+Symbol *fp;
+{
+    Symbol t;
+    Frame nfrp;
+
+    t = *fp;
+    checkref(t);
+    if (isinline(t)) {
+       t = container(t);
+       nfrp = frp;
+    } else {
+       nfrp = nextframe(frp);
+       if (nfrp == nil) {
+           t = nil;
+       } else {
+           t = whatblock(nfrp->save_pc);
+       }
+    }
+    *fp = t;
+    return nfrp;
+}
+
 /*
  * Return the frame associated with the given function.
  * If the function is nil, return the most recently activated frame.
 /*
  * Return the frame associated with the given function.
  * If the function is nil, return the most recently activated frame.
@@ -104,19 +218,63 @@ Frame frp;
 public Frame findframe(f)
 Symbol f;
 {
 public Frame findframe(f)
 Symbol f;
 {
-    register Frame frp;
+    Frame frp;
     static struct Frame frame;
     static struct Frame frame;
+    Symbol p;
+    Boolean done;
 
     frp = &frame;
     getcurframe(frp);
     if (f != nil) {
 
     frp = &frame;
     getcurframe(frp);
     if (f != nil) {
-       while (frp != nil and whatblock(frp->save_pc) != f) {
-           frp = nextframe(frp);
+       if (f == curfunc and curframe != nil) {
+           *frp = *curframe;
+       } else {
+           done = false;
+           p = whatblock(frp->save_pc);
+           do {
+               if (p == f) {
+                   done = true;
+               } else if (p == program) {
+                   done = true;
+                   frp = nil;
+               } else {
+                   frp = nextfunc(frp, &p);
+                   if (frp == nil) {
+                       done = true;
+                   }
+               }
+           } while (not done);
        }
     }
     return frp;
 }
 
        }
     }
     return frp;
 }
 
+/*
+ * Set the registers according to the given frame pointer.
+ */
+
+public getnewregs (addr)
+Address addr;
+{
+    struct Frame frame;
+    integer i, j, mask;
+
+    dread(&frame, addr, sizeof(frame));
+    setreg(ARGP, frame.save_ap);
+    setreg(FRP, frame.save_fp);
+    setreg(PROGCTR, frame.save_pc);
+    mask = ((frame.mask >> 16) & 0x0fff);
+    j = 0;
+    for (i = 0; i < NSAVEREG; i++) {
+       if (bis(mask, i)) {
+           setreg(i, frame.save_reg[j]);
+           ++j;
+       }
+    }
+    pc = frame.save_pc;
+    setcurfunc(whatblock(pc));
+}
+
 /*
  * Find the return address of the current procedure/function.
  */
 /*
  * Find the return address of the current procedure/function.
  */
@@ -143,8 +301,8 @@ public Address return_addr()
  */
 
 public pushretval(len, isindirect)
  */
 
 public pushretval(len, isindirect)
-Integer len;
-Boolean isindirect;
+integer len;
+boolean isindirect;
 {
     Word r0;
 
 {
     Word r0;
 
@@ -168,7 +326,7 @@ Boolean isindirect;
                    push(Word, r0);
                    push(Word, reg(1));
                } else {
                    push(Word, r0);
                    push(Word, reg(1));
                } else {
-                   panic("not indirect in pushretval?");
+                   error("[internal error: bad size %d in pushretval]", len);
                }
                break;
        }
                }
                break;
        }
@@ -180,7 +338,7 @@ Boolean isindirect;
  */
 
 public Address locals_base(frp)
  */
 
 public Address locals_base(frp)
-register Frame frp;
+Frame frp;
 {
     return (frp == nil) ? reg(FRP) : frp->save_fp;
 }
 {
     return (frp == nil) ? reg(FRP) : frp->save_fp;
 }
@@ -190,7 +348,7 @@ register Frame frp;
  */
 
 public Address args_base(frp)
  */
 
 public Address args_base(frp)
-register Frame frp;
+Frame frp;
 {
     return (frp == nil) ? reg(ARGP) : frp->save_ap;
 }
 {
     return (frp == nil) ? reg(ARGP) : frp->save_ap;
 }
@@ -200,10 +358,10 @@ register Frame frp;
  */
 
 public Word savereg(n, frp)
  */
 
 public Word savereg(n, frp)
-register Integer n;
-register Frame frp;
+integer n;
+Frame frp;
 {
 {
-    register Word w;
+    Word w;
 
     if (frp == nil) {
        w = reg(n);
 
     if (frp == nil) {
        w = reg(n);
@@ -239,7 +397,7 @@ register Frame frp;
  */
 
 public Word argn(n, frp)
  */
 
 public Word argn(n, frp)
-Integer n;
+integer n;
 Frame frp;
 {
     Word w;
 Frame frp;
 {
     Word w;
@@ -249,34 +407,45 @@ Frame frp;
 }
 
 /*
 }
 
 /*
- * Calculate the entry address for a procedure or function parameter,
- * given the address of the descriptor.
+ * Print a list of currently active blocks starting with most recent.
  */
 
  */
 
-public Address fparamaddr(a)
-Address a;
+public wherecmd()
 {
 {
-    Address r;
-
-    dread(&r, a, sizeof(r));
-    return r;
+    walkstack(false);
 }
 
 /*
 }
 
 /*
- * Print a list of currently active blocks starting with most recent.
+ * Print the variables in the given frame or the current one if nil.
  */
 
  */
 
-public wherecmd()
+public dump (func)
+Symbol func;
 {
 {
-    walkstack(false);
+    Symbol f;
+    Frame frp;
+
+    if (func == nil) {
+       f = curfunc;
+       if (curframe != nil) {
+           frp = curframe;
+       } else {
+           frp = findframe(f);
+       }
+    } else {
+       f = func;
+       frp = findframe(f);
+    }
+    showaggrs = true;
+    printcallinfo(f, frp);
+    dumpvars(f, frp);
 }
 
 /*
 }
 
 /*
- * Dump the world to the given file.
- * Like "where", but variables are dumped also.
+ * Dump all values.
  */
 
  */
 
-public dump()
+public dumpall ()
 {
     walkstack(true);
 }
 {
     walkstack(true);
 }
@@ -286,44 +455,33 @@ public dump()
  * about each active procedure.
  */
 
  * about each active procedure.
  */
 
-#define lastfunc(f)     (f == program)
-
 private walkstack(dumpvariables)
 Boolean dumpvariables;
 {
 private walkstack(dumpvariables)
 Boolean dumpvariables;
 {
-    register Frame frp;
-    register Symbol f;
-    register Boolean save;
-    register Lineno line;
+    Frame frp;
+    boolean save;
+    Symbol f;
     struct Frame frame;
 
     struct Frame frame;
 
-    if (notstarted(process)) {
+    if (notstarted(process) or isfinished(process)) {
        error("program is not active");
     } else {
        save = walkingstack;
        walkingstack = true;
        error("program is not active");
     } else {
        save = walkingstack;
        walkingstack = true;
+       showaggrs = dumpvariables;
        frp = &frame;
        frp = &frame;
-       getcurframe(frp);
-       f = whatblock(frp->save_pc);
-       do {
-           printf("%s", symname(f));
-           printparams(f, frp);
-           line = srcline(frp->save_pc - 1);
-           if (line != 0) {
-               printf(", line %d", line);
-               printf(" in \"%s\"\n", srcfilename(frp->save_pc - 1));
-           } else {
-               printf(" at 0x%x\n", frp->save_pc);
-           }
+       getcurfunc(frp, &f);
+       for (;;) {
+           printcallinfo(f, frp);
            if (dumpvariables) {
                dumpvars(f, frp);
                putchar('\n');
            }
            if (dumpvariables) {
                dumpvars(f, frp);
                putchar('\n');
            }
-           frp = nextframe(frp);
-           if (frp != nil) {
-               f = whatblock(frp->save_pc);
+           frp = nextfunc(frp, &f);
+           if (frp == nil or f == program) {
+               break;
            }
            }
-       } while (frp != nil and not lastfunc(f));
+       }
        if (dumpvariables) {
            printf("in \"%s\":\n", symname(program));
            dumpvars(program, nil);
        if (dumpvariables) {
            printf("in \"%s\":\n", symname(program));
            dumpvars(program, nil);
@@ -333,14 +491,167 @@ Boolean dumpvariables;
     }
 }
 
     }
 }
 
+/*
+ * Print out the information about a call, i.e.,
+ * routine name, parameter values, and source location.
+ */
+
+private printcallinfo (f, frp)
+Symbol f;
+Frame frp;
+{
+    Lineno line;
+    Address savepc;
+
+    savepc = frp->save_pc;
+    if (frp->save_fp != reg(FRP)) {
+       savepc -= 1;
+    }
+    printname(stdout, f);
+    if (not isinline(f)) {
+       printparams(f, frp);
+    }
+    line = srcline(savepc);
+    if (line != 0) {
+       printf(", line %d", line);
+       printf(" in \"%s\"\n", srcfilename(savepc));
+    } else {
+       printf(" at 0x%x\n", savepc);
+    }
+}
+
+/*
+ * Set the current function to the given symbol.
+ * We must adjust "curframe" so that subsequent operations are
+ * not confused; for simplicity we simply clear it.
+ */
+
+public setcurfunc (f)
+Symbol f;
+{
+    curfunc = f;
+    curframe = nil;
+}
+
+/*
+ * Return the frame for the current function.
+ * The space for the frame is allocated statically.
+ */
+
+public Frame curfuncframe ()
+{
+    static struct Frame frame;
+    Frame frp;
+
+    if (curframe == nil) {
+       frp = findframe(curfunc);
+       curframe = &curframerec;
+       *curframe = *frp;
+    } else {
+       frp = &frame;
+       *frp = *curframe;
+    }
+    return frp;
+}
+
+/*
+ * Set curfunc to be N up/down the stack from its current value.
+ */
+
+public up (n)
+integer n;
+{
+    integer i;
+    Symbol f;
+    Frame frp;
+    boolean done;
+
+    if (not isactive(program)) {
+       error("program is not active");
+    } else if (curfunc == nil) {
+       error("no current function");
+    } else {
+       i = 0;
+       f = curfunc;
+       frp = curfuncframe();
+       done = false;
+       do {
+           if (frp == nil) {
+               done = true;
+               error("not that many levels");
+           } else if (i >= n) {
+               done = true;
+               curfunc = f;
+               curframe = &curframerec;
+               *curframe = *frp;
+               showaggrs = false;
+               printcallinfo(curfunc, curframe);
+           } else if (f == program) {
+               done = true;
+               error("not that many levels");
+           } else {
+               frp = nextfunc(frp, &f);
+           }
+           ++i;
+       } while (not done);
+    }
+}
+
+public down (n)
+integer n;
+{
+    integer i, depth;
+    Frame frp, curfrp;
+    Symbol f;
+    struct Frame frame;
+
+    if (not isactive(program)) {
+       error("program is not active");
+    } else if (curfunc == nil) {
+       error("no current function");
+    } else {
+       depth = 0;
+       frp = &frame;
+       getcurfunc(frp, &f);
+       if (curframe == nil) {
+           curfrp = findframe(curfunc);
+           curframe = &curframerec;
+           *curframe = *curfrp;
+       }
+       while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) {
+           frp = nextfunc(frp, &f);
+           ++depth;
+       }
+       if (f == nil or n > depth) {
+           error("not that many levels");
+       } else {
+           depth -= n;
+           frp = &frame;
+           getcurfunc(frp, &f);
+           for (i = 0; i < depth; i++) {
+               frp = nextfunc(frp, &f);
+               assert(frp != nil);
+           }
+           curfunc = f;
+           *curframe = *frp;
+           showaggrs = false;
+           printcallinfo(curfunc, curframe);
+       }
+    }
+}
+
 /*
  * Find the entry point of a procedure or function.
  */
 
 /*
  * Find the entry point of a procedure or function.
  */
 
-public findbeginning(f)
+public findbeginning (f)
 Symbol f;
 {
 Symbol f;
 {
-    f->symvalue.funcv.beginaddr += 2;
+    if (isinternal(f)) {
+       f->symvalue.funcv.beginaddr += 15;
+    } else {
+       f->symvalue.funcv.beginaddr += 2;
+    }
 }
 
 /*
 }
 
 /*
@@ -387,7 +698,7 @@ public runtofirst()
 
 public Address lastaddr()
 {
 
 public Address lastaddr()
 {
-    register Symbol s;
+    Symbol s;
 
     s = lookup(identname("exit", true));
     if (s == nil) {
 
     s = lookup(identname("exit", true));
     if (s == nil) {
@@ -406,7 +717,7 @@ public Address lastaddr()
 public Boolean isactive(f)
 Symbol f;
 {
 public Boolean isactive(f)
 Symbol f;
 {
-    register Boolean b;
+    Boolean b;
 
     if (isfinished(process)) {
        b = false;
 
     if (isfinished(process)) {
        b = false;
@@ -425,13 +736,16 @@ Symbol f;
  * Evaluate a call to a procedure.
  */
 
  * Evaluate a call to a procedure.
  */
 
-public callproc(procnode, arglist)
-Node procnode;
-Node arglist;
+public callproc(exprnode, isfunc)
+Node exprnode;
+boolean isfunc;
 {
 {
+    Node procnode, arglist;
     Symbol proc;
     Symbol proc;
-    Integer argc;
+    integer argc;
 
 
+    procnode = exprnode->value.arg[0];
+    arglist = exprnode->value.arg[1];
     if (procnode->op != O_SYM) {
        beginerrmsg();
        fprintf(stderr, "can't call \"");
     if (procnode->op != O_SYM) {
        beginerrmsg();
        fprintf(stderr, "can't call \"");
@@ -444,14 +758,26 @@ Node arglist;
     if (not isblock(proc)) {
        error("\"%s\" is not a procedure or function", symname(proc));
     }
     if (not isblock(proc)) {
        error("\"%s\" is not a procedure or function", symname(proc));
     }
+    endproc.isfunc = isfunc;
+    endproc.callnode = exprnode;
+    endproc.cmdnode = topnode;
     pushenv();
     pc = codeloc(proc);
     argc = pushargs(proc, arglist);
     beginproc(proc, argc);
     pushenv();
     pc = codeloc(proc);
     argc = pushargs(proc, arglist);
     beginproc(proc, argc);
-    isstopped = true;
-    event_once(build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)),
-       buildcmdlist(build(O_PROCRTN, proc)));
-    cont();
+    event_once(
+       build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)),
+       buildcmdlist(build(O_PROCRTN, proc))
+    );
+    isstopped = false;
+    if (not bpact()) {
+       isstopped = true;
+       cont(0);
+    }
+    /*
+     * bpact() won't return true, it will call printstatus() and go back
+     * to command input if a breakpoint is found.
+     */
     /* NOTREACHED */
 }
 
     /* NOTREACHED */
 }
 
@@ -461,7 +787,7 @@ Node arglist;
  * space.
  */
 
  * space.
  */
 
-private Integer pushargs(proc, arglist)
+private integer pushargs(proc, arglist)
 Symbol proc;
 Node arglist;
 {
 Symbol proc;
 Node arglist;
 {
@@ -478,51 +804,144 @@ Node arglist;
 }
 
 /*
 }
 
 /*
- * Evaluate arguments left-to-right.
+ * Check to see if an expression is correct for a given parameter.
+ * If the given parameter is false, don't worry about type inconsistencies.
+ *
+ * Return whether or not it is ok.
+ */
+
+private boolean chkparam (actual, formal, chk)
+Node actual;
+Symbol formal;
+boolean chk;
+{
+    boolean b;
+
+    b = true;
+    if (chk) {
+       if (formal == nil) {
+           beginerrmsg();
+           fprintf(stderr, "too many parameters");
+           b = false;
+       } else if (not compatible(formal->type, actual->nodetype)) {
+           beginerrmsg();
+           fprintf(stderr, "type mismatch for %s", symname(formal));
+           b = false;
+       }
+    }
+    if (b and formal != nil and
+       isvarparam(formal) and not isopenarray(formal->type) and
+       not (
+           actual->op == O_RVAL or actual->nodetype == t_addr or
+           (
+               actual->op == O_TYPERENAME and
+               (
+                   actual->value.arg[0]->op == O_RVAL or
+                   actual->value.arg[0]->nodetype == t_addr
+               )
+           )
+       )
+    ) {
+       beginerrmsg();
+       fprintf(stderr, "expected variable, found \"");
+       prtree(stderr, actual);
+       fprintf(stderr, "\"");
+       b = false;
+    }
+    return b;
+}
+
+/*
+ * Pass an expression to a particular parameter.
+ *
+ * Normally we pass either the address or value, but in some cases
+ * (such as C strings) we want to copy the value onto the stack and
+ * pass its address.
+ *
+ * Another special case raised by strings is the possibility that
+ * the actual parameter will be larger than the formal, even with
+ * appropriate type-checking.  This occurs because we assume during
+ * evaluation that strings are null-terminated, whereas some languages,
+ * notably Pascal, do not work under that assumption.
+ */
+
+private passparam (actual, formal)
+Node actual;
+Symbol formal;
+{
+    boolean b;
+    Address addr;
+    Stack *savesp;
+    integer actsize, formsize;
+
+    if (formal != nil and isvarparam(formal) and
+       (not isopenarray(formal->type))
+    ) {
+       addr = lval(actual->value.arg[0]);
+       push(Address, addr);
+    } else if (passaddr(formal, actual->nodetype)) {
+       savesp = sp;
+       eval(actual);
+       actsize = sp - savesp;
+       setreg(STKP,
+           reg(STKP) - ((actsize + sizeof(Word) - 1) & ~(sizeof(Word) - 1))
+       );
+       dwrite(savesp, reg(STKP), actsize);
+       sp = savesp;
+       push(Address, reg(STKP));
+       if (formal != nil and isopenarray(formal->type)) {
+           push(integer, actsize div size(formal->type->type));
+       }
+    } else if (formal != nil) {
+       formsize = size(formal);
+       savesp = sp;
+       eval(actual);
+       actsize = sp - savesp;
+       if (actsize > formsize) {
+           sp -= (actsize - formsize);
+       }
+    } else {
+       eval(actual);
+    }
+}
+
+/*
+ * Evaluate an argument list left-to-right.
  */
 
  */
 
-private Integer evalargs(proc, arglist)
+private integer evalargs(proc, arglist)
 Symbol proc;
 Node arglist;
 {
 Symbol proc;
 Node arglist;
 {
-    Node p, exp;
-    Symbol arg;
+    Node p, actual;
+    Symbol formal;
     Stack *savesp;
     Stack *savesp;
-    Address addr;
-    Integer count;
+    integer count;
+    boolean chk;
 
     savesp = sp;
     count = 0;
 
     savesp = sp;
     count = 0;
-    arg = proc->chain;
+    formal = proc->chain;
+    chk = (boolean) (not nosource(proc));
     for (p = arglist; p != nil; p = p->value.arg[1]) {
     for (p = arglist; p != nil; p = p->value.arg[1]) {
-       if (p->op != O_COMMA) {
-           panic("evalargs: arglist missing comma");
-       }
-       if (arg == nil) {
+       assert(p->op == O_COMMA);
+       actual = p->value.arg[0];
+       if (not chkparam(actual, formal, chk)) {
+           fprintf(stderr, " in call to %s", symname(proc));
            sp = savesp;
            sp = savesp;
-           error("too many parameters to %s", symname(proc));
+           enderrmsg();
        }
        }
-       exp = p->value.arg[0];
-       if (not compatible(arg->type, exp->nodetype)) {
-           sp = savesp;
-           error("expression for parameter %s is of wrong type", symname(arg));
+       passparam(actual, formal);
+       if (formal != nil) {
+           formal = formal->chain;
        }
        }
-       if (arg->class == REF) {
-           if (exp->op != O_RVAL) {
-               sp = savesp;
-               error("variable expected for parameter \"%s\"", symname(arg));
-           }
-           addr = lval(exp->value.arg[0]);
-           push(Address, addr);
-       } else {
-           eval(exp);
-       }
-       arg = arg->chain;
        ++count;
     }
        ++count;
     }
-    if (arg != nil) {
-       sp = savesp;
-       error("not enough parameters to %s", symname(proc));
+    if (chk) {
+       if (formal != nil) {
+           sp = savesp;
+           error("not enough parameters to %s", symname(proc));
+       }
     }
     return count;
 }
     }
     return count;
 }
@@ -530,11 +949,32 @@ Node arglist;
 public procreturn(f)
 Symbol f;
 {
 public procreturn(f)
 Symbol f;
 {
+    integer retvalsize;
+    Node tmp;
+    char *copy;
+
     flushoutput();
     flushoutput();
-    putchar('\n');
-    printname(stdout, f);
-    printf(" returns successfully\n", symname(f));
     popenv();
     popenv();
+    if (endproc.isfunc) {
+       retvalsize = size(f->type);
+       if (retvalsize > sizeof(long)) {
+           pushretval(retvalsize, true);
+           copy = newarr(char, retvalsize);
+           popn(retvalsize, copy);
+           tmp = build(O_SCON, copy);
+       } else {
+           tmp = build(O_LCON, (long) (reg(0)));
+       }
+       tmp->nodetype = f->type;
+       tfree(endproc.callnode);
+       *(endproc.callnode) = *(tmp);
+       dispose(tmp);
+       eval(endproc.cmdnode);
+    } else {
+       putchar('\n');
+       printname(stdout, f);
+       printf(" returns successfully\n", symname(f));
+    }
     erecover();
 }
 
     erecover();
 }
 
@@ -549,6 +989,9 @@ private pushenv()
     push(String, cursource);
     push(Boolean, isstopped);
     push(Symbol, curfunc);
     push(String, cursource);
     push(Boolean, isstopped);
     push(Symbol, curfunc);
+    push(Frame, curframe);
+    push(struct Frame, curframerec);
+    push(CallEnv, endproc);
     push(Word, reg(PROGCTR));
     push(Word, reg(STKP));
 }
     push(Word, reg(PROGCTR));
     push(Word, reg(STKP));
 }
@@ -559,10 +1002,13 @@ private pushenv()
 
 public popenv()
 {
 
 public popenv()
 {
-    register String filename;
+    String filename;
 
     setreg(STKP, pop(Word));
     setreg(PROGCTR, pop(Word));
 
     setreg(STKP, pop(Word));
     setreg(PROGCTR, pop(Word));
+    endproc = pop(CallEnv);
+    curframerec = pop(struct Frame);
+    curframe = pop(Frame);
     curfunc = pop(Symbol);
     isstopped = pop(Boolean);
     filename = pop(String);
     curfunc = pop(Symbol);
     isstopped = pop(Boolean);
     filename = pop(String);
@@ -579,8 +1025,8 @@ public popenv()
 
 public flushoutput()
 {
 
 public flushoutput()
 {
-    register Symbol p, iob;
-    register Stack *savesp;
+    Symbol p, iob;
+    Stack *savesp;
 
     p = lookup(identname("fflush", true));
     while (p != nil and not isblock(p)) {
 
     p = lookup(identname("fflush", true));
     while (p != nil and not isblock(p)) {