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