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