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