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