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