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