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