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