manual page first distributed with 4.3BSD
[unix-history] / usr / src / old / dbx / runtime.vax.c
index 6ec85c3..889a67e 100644 (file)
@@ -1,9 +1,8 @@
-
 /* Copyright (c) 1982 Regents of the University of California */
 
 /* Copyright (c) 1982 Regents of the University of California */
 
-static char sccsid[] = "@(#)runtime.c 1.8 8/10/83";
+static char sccsid[] = "@(#)runtime.vax.c      1.13 (Berkeley) %G%";
 
 
-static char rcsid[] = "$Header: runtime.c,v 1.3 84/03/27 10:23:40 linton Exp $";
+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
@@ -32,8 +31,8 @@ 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 */
     Address save_ap;           /* argument pointer */
     Address save_fp;           /* frame pointer */
     Address save_pc;           /* program counter */
@@ -46,12 +45,23 @@ private Boolean walkingstack = false;
 
 #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp)
 
 
 #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;
 
@@ -59,28 +69,48 @@ register Frame frp;
     frp->mask = reg(NREG);
     frp->save_ap = reg(ARGP);
     frp->save_fp = reg(FRP);
     frp->mask = reg(NREG);
     frp->save_ap = reg(ARGP);
     frp->save_fp = reg(FRP);
-    frp->save_pc = reg(PROGCTR) + 1;
+    frp->save_pc = reg(PROGCTR);
     for (i = 0; i < NSAVEREG; i++) {
        frp->save_reg[i] = reg(i);
     }
 }
 
     for (i = 0; i < NSAVEREG; i++) {
        frp->save_reg[i] = reg(i);
     }
 }
 
+/*
+ * 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; 
     Address prev_frame, callpc; 
-    static Integer ntramp = 0;
+    static integer ntramp = 0;
 
     newfrp = frp;
     prev_frame = frp->save_fp;
 
     newfrp = frp;
     prev_frame = frp->save_fp;
@@ -114,23 +144,17 @@ nextf:
     } else {
        callpc = frame.save_pc;
     }
     } else {
        callpc = frame.save_pc;
     }
-    if (frame.save_fp == nil) {
+    if (frame.save_fp == nil or frame.save_pc == (Address) -1) {
        newfrp = nil;
        newfrp = nil;
-    } else if (callpc > 0x80000000 - 0x200 * UPAGES ) {
-        ntramp++;
-        prev_frame = frame.save_fp;
-        goto nextf;
+    } else if (isstackaddr(callpc)) {
+       ntramp++;
+       prev_frame = frame.save_fp;
+       goto nextf;
     } else {
        frame.save_pc = callpc;
         ntramp = 0;
        mask = ((frame.mask >> 16) & 0x0fff);
     } else {
        frame.save_pc = callpc;
         ntramp = 0;
        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;
@@ -160,7 +184,7 @@ Symbol *fp;
  * are returned.
  */
 
  * are returned.
  */
 
-private Frame nextfunc (frp, fp)
+public Frame nextfunc (frp, fp)
 Frame frp;
 Symbol *fp;
 {
 Frame frp;
 Symbol *fp;
 {
@@ -194,36 +218,61 @@ Symbol *fp;
 public Frame findframe(f)
 Symbol f;
 {
 public Frame findframe(f)
 Symbol f;
 {
-    register Frame frp;
+    Frame frp;
     static struct Frame frame;
     Symbol p;
     static struct Frame frame;
     Symbol p;
+    Boolean done;
 
     frp = &frame;
     getcurframe(frp);
 
     frp = &frame;
     getcurframe(frp);
-    if (f == nil)
-       return (frp);
-    /*
-     * Starting at the current stack frame,
-     * walk backwards looking for a symbol
-     * match.  Beware of local blocks which
-     * have a back pointer but no stack frame.
-     */
-    p = whatblock(frp->save_pc);
-    while (p != f) {
-       if (p == program) {
-           frp = nil;
-           break;
+    if (f != nil) {
+       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);
        }
        }
-       if (isinline(p)) {
-           p = container(p);
-           continue;
+    }
+    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;
        }
        }
-       frp = nextframe(frp);
-       if (frp == nil)
-          break;
-       p = whatblock(frp->save_pc);
     }
     }
-    return (frp);
+    pc = frame.save_pc;
+    setcurfunc(whatblock(pc));
 }
 
 /*
 }
 
 /*
@@ -252,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;
 
@@ -277,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;
        }
@@ -289,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;
 }
@@ -299,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;
 }
@@ -309,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);
@@ -348,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;
@@ -358,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);
 }
@@ -398,37 +458,30 @@ public dump()
 private walkstack(dumpvariables)
 Boolean dumpvariables;
 {
 private walkstack(dumpvariables)
 Boolean dumpvariables;
 {
-    register Frame frp;
-    register Boolean save;
-    register Lineno line;
+    Frame frp;
+    boolean save;
     Symbol f;
     struct Frame frame;
 
     Symbol f;
     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;
        getcurfunc(frp, &f);
        frp = &frame;
        getcurfunc(frp, &f);
-       do {
-           printf("%s", symname(f));
-           if (not isinline(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);
-           }
+       for (;;) {
+           printcallinfo(f, frp);
            if (dumpvariables) {
                dumpvars(f, frp);
                putchar('\n');
            }
            frp = nextfunc(frp, &f);
            if (dumpvariables) {
                dumpvars(f, frp);
                putchar('\n');
            }
            frp = nextfunc(frp, &f);
-       } while (frp != nil and f != program);
+           if (frp == nil or f == program) {
+               break;
+           }
+       }
        if (dumpvariables) {
            printf("in \"%s\":\n", symname(program));
            dumpvars(program, nil);
        if (dumpvariables) {
            printf("in \"%s\":\n", symname(program));
            dumpvars(program, nil);
@@ -438,6 +491,35 @@ 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
 /*
  * Set the current function to the given symbol.
  * We must adjust "curframe" so that subsequent operations are
@@ -451,6 +533,27 @@ Symbol f;
     curframe = nil;
 }
 
     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.
  */
 /*
  * Set curfunc to be N up/down the stack from its current value.
  */
@@ -470,11 +573,7 @@ integer n;
     } else {
        i = 0;
        f = curfunc;
     } else {
        i = 0;
        f = curfunc;
-       if (curframe != nil) {
-           frp = curframe;
-       } else {
-           frp = findframe(f);
-       }
+       frp = curfuncframe();
        done = false;
        do {
            if (frp == nil) {
        done = false;
        do {
            if (frp == nil) {
@@ -485,6 +584,8 @@ integer n;
                curfunc = f;
                curframe = &curframerec;
                *curframe = *frp;
                curfunc = f;
                curframe = &curframerec;
                *curframe = *frp;
+               showaggrs = false;
+               printcallinfo(curfunc, curframe);
            } else if (f == program) {
                done = true;
                error("not that many levels");
            } else if (f == program) {
                done = true;
                error("not that many levels");
@@ -500,7 +601,7 @@ public down (n)
 integer n;
 {
     integer i, depth;
 integer n;
 {
     integer i, depth;
-    register Frame frp;
+    Frame frp, curfrp;
     Symbol f;
     struct Frame frame;
 
     Symbol f;
     struct Frame frame;
 
@@ -513,8 +614,9 @@ integer n;
        frp = &frame;
        getcurfunc(frp, &f);
        if (curframe == nil) {
        frp = &frame;
        getcurfunc(frp, &f);
        if (curframe == nil) {
+           curfrp = findframe(curfunc);
            curframe = &curframerec;
            curframe = &curframerec;
-           *curframe = *(findframe(curfunc));
+           *curframe = *curfrp;
        }
        while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) {
            frp = nextfunc(frp, &f);
        }
        while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) {
            frp = nextfunc(frp, &f);
@@ -532,6 +634,8 @@ integer n;
            }
            curfunc = f;
            *curframe = *frp;
            }
            curfunc = f;
            *curframe = *frp;
+           showaggrs = false;
+           printcallinfo(curfunc, curframe);
        }
     }
 }
        }
     }
 }
@@ -540,7 +644,7 @@ integer n;
  * 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;
 {
     if (isinternal(f)) {
 Symbol f;
 {
     if (isinternal(f)) {
@@ -594,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) {
@@ -613,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;
@@ -632,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 \"");
@@ -651,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(0);
+    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 */
 }
 
@@ -668,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;
 {
@@ -710,9 +829,19 @@ boolean chk;
            b = false;
        }
     }
            b = false;
        }
     }
-    if (b and formal != nil and isvarparam(formal) and
-       not isopenarray(formal->type) and actual->op != O_RVAL)
-    {
+    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);
        beginerrmsg();
        fprintf(stderr, "expected variable, found \"");
        prtree(stderr, actual);
@@ -728,6 +857,12 @@ boolean chk;
  * 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.
  * 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)
  */
 
 private passparam (actual, formal)
@@ -737,21 +872,33 @@ Symbol formal;
     boolean b;
     Address addr;
     Stack *savesp;
     boolean b;
     Address addr;
     Stack *savesp;
-    integer paramsize;
+    integer actsize, formsize;
 
 
-    if (isvarparam(formal) and not isopenarray(formal->type)) {
+    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);
        addr = lval(actual->value.arg[0]);
        push(Address, addr);
     } else if (passaddr(formal, actual->nodetype)) {
        savesp = sp;
        eval(actual);
-       paramsize = sp - savesp;
-       setreg(STKP, reg(STKP) - paramsize);
-       dwrite(savesp, reg(STKP), paramsize);
+       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)) {
        sp = savesp;
        push(Address, reg(STKP));
        if (formal != nil and isopenarray(formal->type)) {
-           push(integer, paramsize div size(formal->type->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);
        }
     } else {
        eval(actual);
@@ -762,14 +909,14 @@ Symbol formal;
  * Evaluate an argument list left-to-right.
  */
 
  * Evaluate an argument list left-to-right.
  */
 
-private Integer evalargs(proc, arglist)
+private integer evalargs(proc, arglist)
 Symbol proc;
 Node arglist;
 {
     Node p, actual;
     Symbol formal;
     Stack *savesp;
 Symbol proc;
 Node arglist;
 {
     Node p, actual;
     Symbol formal;
     Stack *savesp;
-    Integer count;
+    integer count;
     boolean chk;
 
     savesp = sp;
     boolean chk;
 
     savesp = sp;
@@ -802,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();
 }
 
@@ -823,6 +991,7 @@ private pushenv()
     push(Symbol, curfunc);
     push(Frame, curframe);
     push(struct Frame, curframerec);
     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));
 }
@@ -833,10 +1002,11 @@ 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);
     curframerec = pop(struct Frame);
     curframe = pop(Frame);
     curfunc = pop(Symbol);
@@ -855,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)) {