xref: /original-bsd/old/dbx/runtime.tahoe.c (revision acda45c0)
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.6 (Berkeley) 01/27/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     argc = evalargs(proc, arglist);
799     args_size = sp - savesp;
800     setreg(STKP, reg(STKP) - args_size);
801     dwrite(savesp, reg(STKP), args_size);
802     sp = savesp;
803     return argc;
804 }
805 
806 /*
807  * Check to see if an expression is correct for a given parameter.
808  * If the given parameter is false, don't worry about type inconsistencies.
809  *
810  * Return whether or not it is ok.
811  */
812 
813 private boolean chkparam (actual, formal, chk)
814 Node actual;
815 Symbol formal;
816 boolean chk;
817 {
818     boolean b;
819 
820     b = true;
821     if (chk) {
822 	if (formal == nil) {
823 	    beginerrmsg();
824 	    fprintf(stderr, "too many parameters");
825 	    b = false;
826 	} else if (not compatible(formal->type, actual->nodetype)) {
827 	    beginerrmsg();
828 	    fprintf(stderr, "type mismatch for %s", symname(formal));
829 	    b = false;
830 	}
831     }
832     if (b and formal != nil and
833 	isvarparam(formal) and not isopenarray(formal->type) and
834 	not (
835 	    actual->op == O_RVAL or actual->nodetype == t_addr or
836 	    (
837 		actual->op == O_TYPERENAME and
838 		(
839 		    actual->value.arg[0]->op == O_RVAL or
840 		    actual->value.arg[0]->nodetype == t_addr
841 		)
842 	    )
843 	)
844     ) {
845 	beginerrmsg();
846 	fprintf(stderr, "expected variable, found \"");
847 	prtree(stderr, actual);
848 	fprintf(stderr, "\"");
849 	b = false;
850     }
851     return b;
852 }
853 
854 /*
855  * Pass an expression to a particular parameter.
856  *
857  * Normally we pass either the address or value, but in some cases
858  * (such as C strings) we want to copy the value onto the stack and
859  * pass its address.
860  *
861  * Another special case raised by strings is the possibility that
862  * the actual parameter will be larger than the formal, even with
863  * appropriate type-checking.  This occurs because we assume during
864  * evaluation that strings are null-terminated, whereas some languages,
865  * notably Pascal, do not work under that assumption.
866  */
867 
868 private passparam (actual, formal)
869 Node actual;
870 Symbol formal;
871 {
872     boolean b;
873     Address addr;
874     Stack *savesp;
875     integer actsize, formsize;
876 
877     if (formal != nil and isvarparam(formal) and
878 	(not isopenarray(formal->type))
879     ) {
880 	addr = lval(actual->value.arg[0]);
881 	push(Address, addr);
882     } else if (passaddr(formal, actual->nodetype)) {
883 	savesp = sp;
884 	eval(actual);
885 	actsize = sp - savesp;
886 	setreg(STKP, reg(STKP) - roundup(actsize, sizeof (Word)));
887 	dwrite(savesp, reg(STKP), actsize);
888 	sp = savesp;
889 	push(Address, reg(STKP));
890 	if (formal != nil and isopenarray(formal->type)) {
891 	    push(integer, actsize div size(formal->type->type));
892 	}
893     } else if (formal != nil) {
894 	formsize = size(formal);
895 	savesp = sp;
896 	eval(actual);
897 	actsize = sp - savesp;
898 	if (actsize > formsize) {
899 	    sp -= (actsize - formsize);
900 	}
901     } else {
902 	eval(actual);
903     }
904 }
905 
906 /*
907  * Evaluate an argument list left-to-right.
908  */
909 
910 private integer evalargs(proc, arglist)
911 Symbol proc;
912 Node arglist;
913 {
914     Node p, actual;
915     Symbol formal;
916     Stack *savesp;
917     integer count;
918     boolean chk;
919 
920     savesp = sp;
921     count = 0;
922     formal = proc->chain;
923     chk = (boolean) (not nosource(proc));
924     for (p = arglist; p != nil; p = p->value.arg[1]) {
925 	assert(p->op == O_COMMA);
926 	actual = p->value.arg[0];
927 	if (not chkparam(actual, formal, chk)) {
928 	    fprintf(stderr, " in call to %s", symname(proc));
929 	    sp = savesp;
930 	    enderrmsg();
931 	}
932 	passparam(actual, formal);
933 	if (formal != nil) {
934 	    formal = formal->chain;
935 	}
936 	++count;
937     }
938     if (chk) {
939 	if (formal != nil) {
940 	    sp = savesp;
941 	    error("not enough parameters to %s", symname(proc));
942 	}
943     }
944     return count;
945 }
946 
947 /*
948  * Evaluate an argument list without any type checking.
949  * This is only useful for procedures with a varying number of
950  * arguments that are compiled -g.
951  */
952 
953 private integer unsafe_evalargs (proc, arglist)
954 Symbol proc;
955 Node arglist;
956 {
957     Node p;
958     integer count;
959 
960     count = 0;
961     for (p = arglist; p != nil; p = p->value.arg[1]) {
962 	assert(p->op == O_COMMA);
963 	eval(p->value.arg[0]);
964 	++count;
965     }
966     return count;
967 }
968 
969 public procreturn(f)
970 Symbol f;
971 {
972     integer retvalsize;
973     Node tmp;
974     char *copy;
975 
976     flushoutput();
977     popenv();
978     if (endproc.isfunc) {
979 	retvalsize = size(f->type);
980 	if (retvalsize > sizeof(long)) {
981 	    pushretval(retvalsize, true);
982 	    copy = newarr(char, retvalsize);
983 	    popn(retvalsize, copy);
984 	    tmp = build(O_SCON, copy);
985 	} else {
986 	    tmp = build(O_LCON, (long) (reg(0)));
987 	}
988 	tmp->nodetype = f->type;
989 	tfree(endproc.callnode);
990 	*(endproc.callnode) = *(tmp);
991 	dispose(tmp);
992 	eval(endproc.cmdnode);
993     } else {
994 	putchar('\n');
995 	printname(stdout, f);
996 	printf(" returns successfully\n");
997     }
998     erecover();
999 }
1000 
1001 /*
1002  * Push the current environment.
1003  */
1004 
1005 private pushenv()
1006 {
1007     push(Address, pc);
1008     push(Lineno, curline);
1009     push(String, cursource);
1010     push(Boolean, isstopped);
1011     push(Symbol, curfunc);
1012     push(Frame, curframe);
1013     push(struct Frame, curframerec);
1014     push(CallEnv, endproc);
1015     push(Word, reg(PROGCTR));
1016     push(Word, reg(STKP));
1017 }
1018 
1019 /*
1020  * Pop back to the real world.
1021  */
1022 
1023 public popenv()
1024 {
1025     String filename;
1026 
1027     setreg(STKP, pop(Word));
1028     setreg(PROGCTR, pop(Word));
1029     endproc = pop(CallEnv);
1030     curframerec = pop(struct Frame);
1031     curframe = pop(Frame);
1032     curfunc = pop(Symbol);
1033     isstopped = pop(Boolean);
1034     filename = pop(String);
1035     curline = pop(Lineno);
1036     pc = pop(Address);
1037     setsource(filename);
1038 }
1039 
1040 /*
1041  * Flush the debuggee's standard output.
1042  *
1043  * This is VERY dependent on the use of stdio.
1044  */
1045 
1046 public flushoutput()
1047 {
1048     Symbol p, iob;
1049     Stack *savesp;
1050 
1051     p = lookup(identname("fflush", true));
1052     while (p != nil and not isblock(p)) {
1053 	p = p->next_sym;
1054     }
1055     if (p != nil) {
1056 	iob = lookup(identname("__sF", true));
1057 	if (iob != nil) {
1058 	    pushenv();
1059 	    pc = codeloc(p);
1060 	    savesp = sp;
1061 	    push(long, address(iob, nil) + sizeof(*stdout));
1062 	    setreg(STKP, reg(STKP) - sizeof(long));
1063 	    dwrite(savesp, reg(STKP), sizeof(long));
1064 	    sp = savesp;
1065 	    beginproc(p, 1);
1066 	    stepto(return_addr());
1067 	    popenv();
1068 	}
1069     }
1070 }
1071