xref: /original-bsd/old/dbx/runtime.tahoe.c (revision 1897046e)
1 /*
2  * Copyright (c) 1985 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)runtime.tahoe.c	5.8 (Berkeley) 07/30/91";
10 #endif /* not lint */
11 
12 /*
13  * Runtime organization dependent routines, mostly dealing with
14  * activation records.
15  */
16 
17 #include "defs.h"
18 #include "runtime.h"
19 #include "process.h"
20 #include "machine.h"
21 #include "events.h"
22 #include "mappings.h"
23 #include "symbols.h"
24 #include "tree.h"
25 #include "eval.h"
26 #include "operators.h"
27 #include "object.h"
28 
29 #ifndef public
30 #include "machine.h"
31 
32 typedef struct Frame {
33     Address save_pc;		/* program counter */
34     integer mask:16;		/* register save mask */
35     integer removed:16;		/* 4*number of arguments + 4 */
36     Address save_fp;		/* frame pointer */
37 #define NSAVEREG 13
38     Word save_reg[NSAVEREG];	/* not necessarily there */
39 } *Frame;
40 #endif
41 
42 private Frame curframe = nil;
43 private struct Frame curframerec;
44 private Boolean walkingstack = false;
45 
46 #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp)
47 
48 #define inSignalHandler(addr) \
49     (((addr) < 0xc0000000) and ((addr) > 0xc0000000 - 0x400 * UPAGES))
50 
51 typedef struct {
52     Node callnode;
53     Node cmdnode;
54     boolean isfunc;
55 } CallEnv;
56 
57 private CallEnv endproc;
58 
59 /*
60  * Set a frame to the current activation record.
61  */
62 
63 private getcurframe(frp)
64 Frame frp;
65 {
66     register int i;
67     long x;
68 
69     checkref(frp);
70     frp->save_fp = reg(FRP);
71     dread(&x, frp->save_fp-4, 4);
72     frp->mask = x >> 16;
73     frp->removed = x & 0xffff;
74     frp->save_pc = reg(PROGCTR);
75     for (i = 0; i < NSAVEREG; i++) {
76 	frp->save_reg[i] = reg(i);
77     }
78 }
79 
80 /*
81  * Get the saved registers from one frame to another
82  * given mask specifying which registers were actually saved.
83  */
84 
85 #define bis(b, n) ((b & (1 << (n))) != 0)
86 
87 private getsaveregs (newfrp, frp, mask)
88 Frame newfrp, frp;
89 integer mask;
90 {
91     integer i, j;
92 
93     j = 0;
94     for (i = 0; i < NSAVEREG; i++) {
95 	if (bis(mask, i)) {
96 	    newfrp->save_reg[i] = frp->save_reg[j];
97 	    ++j;
98 	}
99     }
100 }
101 
102 /*
103  * Return a pointer to the next activation record up the stack.
104  * Return nil if there is none.
105  * Writes over space pointed to by given argument.
106  */
107 
108 private Frame nextframe(frp)
109 Frame frp;
110 {
111     Frame newfrp;
112     struct Frame frame;
113     long x;
114     Address prev_frame, callpc;
115     static integer ntramp = 0;
116 
117     newfrp = frp;
118     prev_frame = frp->save_fp;
119 
120 /*
121  *  The check for interrupt generated frames is taken from adb with only
122  *  partial understanding.  If you're in "sub" and on a sigxxx "sigsub"
123  *  gets control, then the stack does NOT look like <main, sub, sigsub>.
124  *
125  *  As best I can make out it looks like:
126  *
127  *     <main, (machine check exception block + sub), sysframe, sigsub>.
128  *
129  *  When the signal occurs an exception block and a frame for the routine
130  *  in which it occured are pushed on the user stack.  Then another frame
131  *  is pushed corresponding to a call from the kernel to sigsub.
132  *
133  *  The addr in sub at which the exception occured is not in sub.save_pc
134  *  but in the machine check exception block.  It is at the magic address
135  *  fp + 84.
136  *
137  *  The current approach ignores the sys_frame (what adb reports as sigtramp)
138  *  and takes the pc for sub from the exception block.  This allows the
139  *  "where" command to report <main, sub, sigsub>, which seems reasonable.
140  */
141 
142 nextf:
143     dread(&frame, prev_frame-8, sizeof(struct Frame));
144     if (ntramp == 1) {
145 	dread(&callpc, prev_frame+44, sizeof(callpc));
146     } else {
147 	callpc = frame.save_pc;
148     }
149     if (frame.save_fp == nil or frame.save_pc == (Address) -1) {
150 	newfrp = nil;
151     } else if (inSignalHandler(callpc)) {
152 	ntramp++;
153 	prev_frame = frame.save_fp;
154 	goto nextf;
155     } else {
156         ntramp = 0;
157 	getsaveregs(newfrp, &frame, frame.mask);
158 	dread(&x, frame.save_fp-4, sizeof (x));
159 	newfrp->mask = x >> 16;
160 	newfrp->removed = x & 0xffff;
161 	newfrp->save_fp = frame.save_fp;
162 	newfrp->save_pc = callpc;
163     }
164     return newfrp;
165 }
166 
167 /*
168  * Get the current frame information in the given Frame and store the
169  * associated function in the given value-result parameter.
170  */
171 
172 private getcurfunc (frp, fp)
173 Frame frp;
174 Symbol *fp;
175 {
176     getcurframe(frp);
177     *fp = whatblock(frp->save_pc);
178 }
179 
180 /*
181  * Return the frame associated with the next function up the call stack, or
182  * nil if there is none.  The function is returned in a value-result parameter.
183  * For "inline" functions the statically outer function and same frame
184  * are returned.
185  */
186 
187 public Frame nextfunc (frp, fp)
188 Frame frp;
189 Symbol *fp;
190 {
191     Symbol t;
192     Frame nfrp;
193 
194     t = *fp;
195     checkref(t);
196     if (isinline(t)) {
197 	t = container(t);
198 	nfrp = frp;
199     } else {
200 	nfrp = nextframe(frp);
201 	if (nfrp == nil) {
202 	    t = nil;
203 	} else {
204 	    t = whatblock(nfrp->save_pc);
205 	}
206     }
207     *fp = t;
208     return nfrp;
209 }
210 
211 /*
212  * Return the frame associated with the given function.
213  * If the function is nil, return the most recently activated frame.
214  *
215  * Static allocation for the frame.
216  */
217 
218 public Frame findframe(f)
219 Symbol f;
220 {
221     Frame frp;
222     static struct Frame frame;
223     Symbol p;
224     Boolean done;
225 
226     frp = &frame;
227     getcurframe(frp);
228     if (f != nil) {
229 	if (f == curfunc and curframe != nil) {
230 	    *frp = *curframe;
231 	} else {
232 	    done = false;
233 	    p = whatblock(frp->save_pc);
234 	    do {
235 		if (p == f) {
236 		    done = true;
237 		} else if (p == program) {
238 		    done = true;
239 		    frp = nil;
240 		} else {
241 		    frp = nextfunc(frp, &p);
242 		    if (frp == nil) {
243 			done = true;
244 		    }
245 		}
246 	    } while (not done);
247 	}
248     }
249     return frp;
250 }
251 
252 /*
253  * Set the registers according to the given frame pointer.
254  */
255 
256 public getnewregs (addr)
257 Address addr;
258 {
259     struct Frame frame;
260     integer i, j, mask;
261 
262     dread(&frame, addr-8, sizeof(frame));
263     setreg(FRP, frame.save_fp);
264     setreg(PROGCTR, frame.save_pc);
265     mask = frame.mask;
266     j = 0;
267     for (i = 0; i < NSAVEREG; i++) {
268 	if (bis(mask, i)) {
269 	    setreg(i, frame.save_reg[j]);
270 	    ++j;
271 	}
272     }
273     pc = frame.save_pc;
274     setcurfunc(whatblock(pc));
275 }
276 
277 /*
278  * Find the return address of the current procedure/function.
279  */
280 
281 public Address return_addr()
282 {
283     Frame frp;
284     Address addr;
285     struct Frame frame;
286 
287     frp = &frame;
288     getcurframe(frp);
289     frp = nextframe(frp);
290     if (frp == nil) {
291 	addr = 0;
292     } else {
293 	addr = frp->save_pc;
294     }
295     return addr;
296 }
297 
298 /*
299  * Push the value associated with the current function.
300  */
301 
302 public pushretval(len, isindirect)
303 integer len;
304 boolean isindirect;
305 {
306     Word r0;
307 
308     r0 = reg(0);
309     if (isindirect) {
310 	rpush((Address) r0, len);
311     } else {
312 	switch (len) {
313 	    case sizeof(char):
314 		push(char, r0);
315 		break;
316 
317 	    case sizeof(short):
318 		push(short, r0);
319 		break;
320 
321 	    default:
322 		if (len == sizeof(Word)) {
323 		    push(Word, r0);
324 		} else if (len == 2*sizeof(Word)) {
325 		    push(Word, r0);
326 		    push(Word, reg(1));
327 		} else {
328 		    error("[internal error: bad size %d in pushretval]", len);
329 		}
330 		break;
331 	}
332     }
333 }
334 
335 /*
336  * Return the base address for locals in the given frame.
337  */
338 
339 public Address locals_base(frp)
340 Frame frp;
341 {
342     return (frp == nil ? reg(FRP) : frp->save_fp);
343 }
344 
345 /*
346  * Return the base address for arguments in the given frame.
347  */
348 
349 public Address args_base(frp)
350 Frame frp;
351 {
352     return (frp == nil ? reg(FRP) : frp->save_fp);
353 }
354 
355 /*
356  * Return saved register n from the given frame.
357  */
358 
359 public Word savereg(n, frp)
360 integer n;
361 Frame frp;
362 {
363     Word w;
364 
365     if (frp == nil) {
366 	w = reg(n);
367     } else {
368 	switch (n) {
369 
370 	    case FRP:
371 		w = frp->save_fp;
372 		break;
373 
374 	    case STKP:
375 		w = reg(STKP);
376 		break;
377 
378 	    case PROGCTR:
379 		w = frp->save_pc;
380 		break;
381 
382 	    default:
383 		assert(n >= 0 and n < NSAVEREG);
384 		w = frp->save_reg[n];
385 		break;
386 	}
387     }
388     return w;
389 }
390 
391 /*
392  * Return the nth argument to the current procedure.
393  */
394 
395 public Word argn(n, frp)
396 integer n;
397 Frame frp;
398 {
399     Address argaddr;
400     Word w;
401 
402     argaddr = args_base(frp) + (n * sizeof(Word));
403     dread(&w, argaddr, sizeof(w));
404     return w;
405 }
406 
407 /*
408  * Print a list of currently active blocks starting with most recent.
409  */
410 
411 public wherecmd()
412 {
413     walkstack(false);
414 }
415 
416 /*
417  * Print the variables in the given frame or the current one if nil.
418  */
419 
420 public dump (func)
421 Symbol func;
422 {
423     Symbol f;
424     Frame frp;
425 
426     if (func == nil) {
427 	f = curfunc;
428 	if (curframe != nil) {
429 	    frp = curframe;
430 	} else {
431 	    frp = findframe(f);
432 	}
433     } else {
434 	f = func;
435 	frp = findframe(f);
436     }
437     showaggrs = true;
438     printcallinfo(f, frp);
439     dumpvars(f, frp);
440 }
441 
442 /*
443  * Dump all values.
444  */
445 
446 public dumpall ()
447 {
448     walkstack(true);
449 }
450 
451 /*
452  * Walk the stack of active procedures printing information
453  * about each active procedure.
454  */
455 
456 private walkstack(dumpvariables)
457 Boolean dumpvariables;
458 {
459     Frame frp;
460     boolean save;
461     Symbol f;
462     struct Frame frame;
463 
464     if (notstarted(process) or isfinished(process)) {
465 	error("program is not active");
466     } else {
467 	save = walkingstack;
468 	walkingstack = true;
469 	showaggrs = dumpvariables;
470 	frp = &frame;
471 	getcurfunc(frp, &f);
472 	for (;;) {
473 	    printcallinfo(f, frp);
474 	    if (dumpvariables) {
475 		dumpvars(f, frp);
476 		putchar('\n');
477 	    }
478 	    frp = nextfunc(frp, &f);
479 	    if (frp == nil or f == program) {
480 		break;
481 	    }
482 	}
483 	if (dumpvariables) {
484 	    printf("in \"%s\":\n", symname(program));
485 	    dumpvars(program, nil);
486 	    putchar('\n');
487 	}
488 	walkingstack = save;
489     }
490 }
491 
492 /*
493  * Print out the information about a call, i.e.,
494  * routine name, parameter values, and source location.
495  */
496 
497 private printcallinfo (f, frp)
498 Symbol f;
499 Frame frp;
500 {
501     Lineno line;
502     Address savepc;
503 
504     savepc = frp->save_pc;
505     if (frp->save_fp != reg(FRP)) {
506 	savepc -= 1;
507     }
508     printname(stdout, f);
509     if (not isinline(f)) {
510 	printparams(f, frp);
511     }
512     line = srcline(savepc);
513     if (line != 0) {
514 	printf(", line %d", line);
515 	printf(" in \"%s\"\n", srcfilename(savepc));
516     } else {
517 	printf(" at 0x%x\n", savepc);
518     }
519 }
520 
521 /*
522  * Set the current function to the given symbol.
523  * We must adjust "curframe" so that subsequent operations are
524  * not confused; for simplicity we simply clear it.
525  */
526 
527 public setcurfunc (f)
528 Symbol f;
529 {
530     curfunc = f;
531     curframe = nil;
532 }
533 
534 /*
535  * Return the frame for the current function.
536  * The space for the frame is allocated statically.
537  */
538 
539 public Frame curfuncframe ()
540 {
541     static struct Frame frame;
542     Frame frp;
543 
544     if (curframe == nil) {
545 	frp = findframe(curfunc);
546 	curframe = &curframerec;
547 	*curframe = *frp;
548     } else {
549 	frp = &frame;
550 	*frp = *curframe;
551     }
552     return frp;
553 }
554 
555 /*
556  * Set curfunc to be N up/down the stack from its current value.
557  */
558 
559 public up (n)
560 integer n;
561 {
562     integer i;
563     Symbol f;
564     Frame frp;
565     boolean done;
566 
567     if (not isactive(program)) {
568 	error("program is not active");
569     } else if (curfunc == nil) {
570 	error("no current function");
571     } else {
572 	i = 0;
573 	f = curfunc;
574 	frp = curfuncframe();
575 	done = false;
576 	do {
577 	    if (frp == nil) {
578 		done = true;
579 		error("not that many levels");
580 	    } else if (i >= n) {
581 		done = true;
582 		curfunc = f;
583 		curframe = &curframerec;
584 		*curframe = *frp;
585 		showaggrs = false;
586 		printcallinfo(curfunc, curframe);
587 	    } else if (f == program) {
588 		done = true;
589 		error("not that many levels");
590 	    } else {
591 		frp = nextfunc(frp, &f);
592 	    }
593 	    ++i;
594 	} while (not done);
595     }
596 }
597 
598 public down (n)
599 integer n;
600 {
601     integer i, depth;
602     Frame frp, curfrp;
603     Symbol f;
604     struct Frame frame;
605 
606     if (not isactive(program)) {
607 	error("program is not active");
608     } else if (curfunc == nil) {
609 	error("no current function");
610     } else {
611 	depth = 0;
612 	frp = &frame;
613 	getcurfunc(frp, &f);
614 	if (curframe == nil) {
615 	    curfrp = findframe(curfunc);
616 	    curframe = &curframerec;
617 	    *curframe = *curfrp;
618 	}
619 	while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) {
620 	    frp = nextfunc(frp, &f);
621 	    ++depth;
622 	}
623 	if (f == nil or n > depth) {
624 	    error("not that many levels");
625 	} else {
626 	    depth -= n;
627 	    frp = &frame;
628 	    getcurfunc(frp, &f);
629 	    for (i = 0; i < depth; i++) {
630 		frp = nextfunc(frp, &f);
631 		assert(frp != nil);
632 	    }
633 	    curfunc = f;
634 	    *curframe = *frp;
635 	    showaggrs = false;
636 	    printcallinfo(curfunc, curframe);
637 	}
638     }
639 }
640 
641 /*
642  * Find the entry point of a procedure or function.
643  */
644 
645 public findbeginning (f)
646 Symbol f;
647 {
648     if (isinternal(f)) {
649 	f->symvalue.funcv.beginaddr += 15;
650     } else {
651 	f->symvalue.funcv.beginaddr += FUNCOFFSET;
652     }
653 }
654 
655 /*
656  * Return the address corresponding to the first line in a function.
657  */
658 
659 public Address firstline(f)
660 Symbol f;
661 {
662     Address addr;
663 
664     addr = codeloc(f);
665     while (linelookup(addr) == 0 and addr < objsize) {
666 	++addr;
667     }
668     if (addr == objsize) {
669 	addr = -1;
670     }
671     return addr;
672 }
673 
674 /*
675  * Catcher drops strike three ...
676  */
677 
678 public runtofirst()
679 {
680     Address addr, endaddr;
681 
682     addr = pc;
683     endaddr = objsize + CODESTART;
684     while (linelookup(addr) == 0 and addr < endaddr) {
685 	++addr;
686     }
687     if (addr < endaddr) {
688 	stepto(addr);
689     }
690 }
691 
692 /*
693  * Return the address corresponding to the end of the program.
694  *
695  * We look for the entry to "exit".
696  */
697 
698 public Address lastaddr()
699 {
700     Symbol s;
701 
702     s = lookup(identname("exit", true));
703     if (s == nil) {
704 	panic("can't find exit");
705     }
706     return codeloc(s);
707 }
708 
709 /*
710  * Decide if the given function is currently active.
711  *
712  * We avoid calls to "findframe" during a stack trace for efficiency.
713  * Presumably information evaluated while walking the stack is active.
714  */
715 
716 public Boolean isactive (f)
717 Symbol f;
718 {
719     Boolean b;
720 
721     if (isfinished(process)) {
722 	b = false;
723     } else {
724 	if (walkingstack or f == program or f == nil or
725 	  (ismodule(f) and isactive(container(f)))) {
726 	    b = true;
727 	} else {
728 	    b = (Boolean) (findframe(f) != nil);
729 	}
730     }
731     return b;
732 }
733 
734 /*
735  * Evaluate a call to a procedure.
736  */
737 
738 public callproc(exprnode, isfunc)
739 Node exprnode;
740 boolean isfunc;
741 {
742     Node procnode, arglist;
743     Symbol proc;
744     integer argc;
745 
746     procnode = exprnode->value.arg[0];
747     arglist = exprnode->value.arg[1];
748     if (procnode->op != O_SYM) {
749 	beginerrmsg();
750 	fprintf(stderr, "can't call \"");
751 	prtree(stderr, procnode);
752 	fprintf(stderr, "\"");
753 	enderrmsg();
754     }
755     assert(procnode->op == O_SYM);
756     proc = procnode->value.sym;
757     if (not isblock(proc)) {
758 	error("\"%s\" is not a procedure or function", symname(proc));
759     }
760     endproc.isfunc = isfunc;
761     endproc.callnode = exprnode;
762     endproc.cmdnode = topnode;
763     pushenv();
764     pc = codeloc(proc);
765     argc = pushargs(proc, arglist);
766     setreg(FRP, 1);	/* have to ensure it's non-zero for return_addr() */
767     beginproc(proc, argc);
768     event_once(
769 	build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)),
770 	buildcmdlist(build(O_PROCRTN, proc))
771     );
772     isstopped = false;
773     if (not bpact()) {
774 	isstopped = true;
775 	cont(0);
776     }
777     /*
778      * bpact() won't return true, it will call printstatus() and go back
779      * to command input if a breakpoint is found.
780      */
781     /* NOTREACHED */
782 }
783 
784 /*
785  * Push the arguments on the process' stack.  We do this by first
786  * evaluating them on the "eval" stack, then copying into the process'
787  * space.
788  */
789 
790 private integer pushargs(proc, arglist)
791 Symbol proc;
792 Node arglist;
793 {
794     Stack *savesp;
795     int argc, args_size;
796 
797     savesp = sp;
798     if (varIsSet("$unsafecall")) {
799 	argc = unsafe_evalargs(proc, arglist);
800     } else {
801 	argc = evalargs(proc, arglist);
802     }
803     argc = evalargs(proc, arglist);
804     args_size = sp - savesp;
805     setreg(STKP, reg(STKP) - args_size);
806     dwrite(savesp, reg(STKP), args_size);
807     sp = savesp;
808     return argc;
809 }
810 
811 /*
812  * Check to see if an expression is correct for a given parameter.
813  * If the given parameter is false, don't worry about type inconsistencies.
814  *
815  * Return whether or not it is ok.
816  */
817 
818 private boolean chkparam (actual, formal, chk)
819 Node actual;
820 Symbol formal;
821 boolean chk;
822 {
823     boolean b;
824 
825     b = true;
826     if (chk) {
827 	if (formal == nil) {
828 	    beginerrmsg();
829 	    fprintf(stderr, "too many parameters");
830 	    b = false;
831 	} else if (not compatible(formal->type, actual->nodetype)) {
832 	    beginerrmsg();
833 	    fprintf(stderr, "type mismatch for %s", symname(formal));
834 	    b = false;
835 	}
836     }
837     if (b and formal != nil and
838 	isvarparam(formal) and not isopenarray(formal->type) and
839 	not (
840 	    actual->op == O_RVAL or actual->nodetype == t_addr or
841 	    (
842 		actual->op == O_TYPERENAME and
843 		(
844 		    actual->value.arg[0]->op == O_RVAL or
845 		    actual->value.arg[0]->nodetype == t_addr
846 		)
847 	    )
848 	)
849     ) {
850 	beginerrmsg();
851 	fprintf(stderr, "expected variable, found \"");
852 	prtree(stderr, actual);
853 	fprintf(stderr, "\"");
854 	b = false;
855     }
856     return b;
857 }
858 
859 /*
860  * Pass an expression to a particular parameter.
861  *
862  * Normally we pass either the address or value, but in some cases
863  * (such as C strings) we want to copy the value onto the stack and
864  * pass its address.
865  *
866  * Another special case raised by strings is the possibility that
867  * the actual parameter will be larger than the formal, even with
868  * appropriate type-checking.  This occurs because we assume during
869  * evaluation that strings are null-terminated, whereas some languages,
870  * notably Pascal, do not work under that assumption.
871  */
872 
873 private passparam (actual, formal)
874 Node actual;
875 Symbol formal;
876 {
877     boolean b;
878     Address addr;
879     Stack *savesp;
880     integer actsize, formsize;
881 
882     if (formal != nil and isvarparam(formal) and
883 	(not isopenarray(formal->type))
884     ) {
885 	addr = lval(actual->value.arg[0]);
886 	push(Address, addr);
887     } else if (passaddr(formal, actual->nodetype)) {
888 	savesp = sp;
889 	eval(actual);
890 	actsize = sp - savesp;
891 	setreg(STKP, reg(STKP) - roundup(actsize, sizeof (Word)));
892 	dwrite(savesp, reg(STKP), actsize);
893 	sp = savesp;
894 	push(Address, reg(STKP));
895 	if (formal != nil and isopenarray(formal->type)) {
896 	    push(integer, actsize div size(formal->type->type));
897 	}
898     } else if (formal != nil) {
899 	formsize = size(formal);
900 	savesp = sp;
901 	eval(actual);
902 	actsize = sp - savesp;
903 	if (actsize > formsize) {
904 	    sp -= (actsize - formsize);
905 	}
906     } else {
907 	eval(actual);
908     }
909 }
910 
911 /*
912  * Evaluate an argument list left-to-right.
913  */
914 
915 private integer evalargs(proc, arglist)
916 Symbol proc;
917 Node arglist;
918 {
919     Node p, actual;
920     Symbol formal;
921     Stack *savesp;
922     integer count;
923     boolean chk;
924 
925     savesp = sp;
926     count = 0;
927     formal = proc->chain;
928     chk = (boolean) (not nosource(proc));
929     for (p = arglist; p != nil; p = p->value.arg[1]) {
930 	assert(p->op == O_COMMA);
931 	actual = p->value.arg[0];
932 	if (not chkparam(actual, formal, chk)) {
933 	    fprintf(stderr, " in call to %s", symname(proc));
934 	    sp = savesp;
935 	    enderrmsg();
936 	}
937 	passparam(actual, formal);
938 	if (formal != nil) {
939 	    formal = formal->chain;
940 	}
941 	++count;
942     }
943     if (chk) {
944 	if (formal != nil) {
945 	    sp = savesp;
946 	    error("not enough parameters to %s", symname(proc));
947 	}
948     }
949     return count;
950 }
951 
952 /*
953  * Evaluate an argument list without any type checking.
954  * This is only useful for procedures with a varying number of
955  * arguments that are compiled -g.
956  */
957 
958 private integer unsafe_evalargs (proc, arglist)
959 Symbol proc;
960 Node arglist;
961 {
962     Node p;
963     integer count;
964 
965     count = 0;
966     for (p = arglist; p != nil; p = p->value.arg[1]) {
967 	assert(p->op == O_COMMA);
968 	eval(p->value.arg[0]);
969 	++count;
970     }
971     return count;
972 }
973 
974 public procreturn(f)
975 Symbol f;
976 {
977     integer retvalsize;
978     Node tmp;
979     char *copy;
980 
981     flushoutput();
982     popenv();
983     if (endproc.isfunc) {
984 	retvalsize = size(f->type);
985 	if (retvalsize > sizeof(long)) {
986 	    pushretval(retvalsize, true);
987 	    copy = newarr(char, retvalsize);
988 	    popn(retvalsize, copy);
989 	    tmp = build(O_SCON, copy);
990 	} else {
991 	    tmp = build(O_LCON, (long) (reg(0)));
992 	}
993 	tmp->nodetype = f->type;
994 	tfree(endproc.callnode);
995 	*(endproc.callnode) = *(tmp);
996 	dispose(tmp);
997 	eval(endproc.cmdnode);
998     } else {
999 	putchar('\n');
1000 	printname(stdout, f);
1001 	printf(" returns successfully\n");
1002     }
1003     erecover();
1004 }
1005 
1006 /*
1007  * Push the current environment.
1008  */
1009 
1010 private pushenv()
1011 {
1012     push(Address, pc);
1013     push(Lineno, curline);
1014     push(String, cursource);
1015     push(Boolean, isstopped);
1016     push(Symbol, curfunc);
1017     push(Frame, curframe);
1018     push(struct Frame, curframerec);
1019     push(CallEnv, endproc);
1020     push(Word, reg(PROGCTR));
1021     push(Word, reg(STKP));
1022     push(Word, reg(FRP));
1023 }
1024 
1025 /*
1026  * Pop back to the real world.
1027  */
1028 
1029 public popenv()
1030 {
1031     String filename;
1032 
1033     setreg(FRP, pop(Word));
1034     setreg(STKP, pop(Word));
1035     setreg(PROGCTR, pop(Word));
1036     endproc = pop(CallEnv);
1037     curframerec = pop(struct Frame);
1038     curframe = pop(Frame);
1039     curfunc = pop(Symbol);
1040     isstopped = pop(Boolean);
1041     filename = pop(String);
1042     curline = pop(Lineno);
1043     pc = pop(Address);
1044     setsource(filename);
1045 }
1046 
1047 /*
1048  * Flush the debuggee's standard output.
1049  *
1050  * This is VERY dependent on the use of stdio.
1051  */
1052 
1053 public flushoutput()
1054 {
1055     Symbol p, iob;
1056     Stack *savesp;
1057 
1058     p = lookup(identname("fflush", true));
1059     while (p != nil and not isblock(p)) {
1060 	p = p->next_sym;
1061     }
1062     if (p != nil) {
1063 	iob = lookup(identname("__sF", true));
1064 	if (iob != nil) {
1065 	    pushenv();
1066 	    pc = codeloc(p);
1067 	    savesp = sp;
1068 	    push(long, address(iob, nil) + sizeof(*stdout));
1069 	    setreg(STKP, reg(STKP) - sizeof(long));
1070 	    dwrite(savesp, reg(STKP), sizeof(long));
1071 	    sp = savesp;
1072 	    beginproc(p, 1);
1073 	    stepto(return_addr());
1074 	    popenv();
1075 	}
1076     }
1077 }
1078