xref: /csrg-svn/old/dbx/runtime.vax.c (revision 9678)
1*9678Slinton /* Copyright (c) 1982 Regents of the University of California */
2*9678Slinton 
3*9678Slinton static char sccsid[] = "@(#)@(#)runtime.vax.c 1.1 12/15/82";
4*9678Slinton 
5*9678Slinton /*
6*9678Slinton  * Runtime organization dependent routines, mostly dealing with
7*9678Slinton  * activation records.
8*9678Slinton  */
9*9678Slinton 
10*9678Slinton #include "defs.h"
11*9678Slinton #include "runtime.h"
12*9678Slinton #include "process.h"
13*9678Slinton #include "machine.h"
14*9678Slinton #include "events.h"
15*9678Slinton #include "mappings.h"
16*9678Slinton #include "symbols.h"
17*9678Slinton #include "tree.h"
18*9678Slinton #include "eval.h"
19*9678Slinton #include "operators.h"
20*9678Slinton #include "object.h"
21*9678Slinton 
22*9678Slinton #ifndef public
23*9678Slinton typedef struct Frame *Frame;
24*9678Slinton 
25*9678Slinton #include "machine.h"
26*9678Slinton #endif
27*9678Slinton 
28*9678Slinton #define NSAVEREG 12
29*9678Slinton 
30*9678Slinton struct Frame {
31*9678Slinton     Integer condition_handler;
32*9678Slinton     Integer mask;
33*9678Slinton     Address save_ap;		/* argument pointer */
34*9678Slinton     Address save_fp;		/* frame pointer */
35*9678Slinton     Address save_pc;		/* program counter */
36*9678Slinton     Word save_reg[NSAVEREG];	/* not necessarily there */
37*9678Slinton };
38*9678Slinton 
39*9678Slinton private Boolean walkingstack = false;
40*9678Slinton 
41*9678Slinton /*
42*9678Slinton  * Set a frame to the current activation record.
43*9678Slinton  */
44*9678Slinton 
45*9678Slinton private getcurframe(frp)
46*9678Slinton register Frame frp;
47*9678Slinton {
48*9678Slinton     register int i;
49*9678Slinton 
50*9678Slinton     checkref(frp);
51*9678Slinton     frp->mask = reg(NREG);
52*9678Slinton     frp->save_ap = reg(ARGP);
53*9678Slinton     frp->save_fp = reg(FRP);
54*9678Slinton     frp->save_pc = reg(PROGCTR);
55*9678Slinton     for (i = 0; i < NSAVEREG; i++) {
56*9678Slinton 	frp->save_reg[i] = reg(i);
57*9678Slinton     }
58*9678Slinton }
59*9678Slinton 
60*9678Slinton /*
61*9678Slinton  * Return a pointer to the next activation record up the stack.
62*9678Slinton  * Return nil if there is none.
63*9678Slinton  * Writes over space pointed to by given argument.
64*9678Slinton  */
65*9678Slinton 
66*9678Slinton #define bis(b, n) ((b & (1 << (n))) != 0)
67*9678Slinton 
68*9678Slinton private Frame nextframe(frp)
69*9678Slinton Frame frp;
70*9678Slinton {
71*9678Slinton     register Frame newfrp;
72*9678Slinton     struct Frame frame;
73*9678Slinton     register Integer i, j, mask;
74*9678Slinton 
75*9678Slinton     newfrp = frp;
76*9678Slinton     dread(&frame, newfrp->save_fp, sizeof(struct Frame));
77*9678Slinton     if (frame.save_fp == nil) {
78*9678Slinton 	newfrp = nil;
79*9678Slinton     } else {
80*9678Slinton 	mask = ((frame.mask >> 16) & 0x0fff);
81*9678Slinton 	j = 0;
82*9678Slinton 	for (i = 0; i < NSAVEREG; i++) {
83*9678Slinton 	    if (bis(mask, i)) {
84*9678Slinton 		newfrp->save_reg[i] = frame.save_reg[j];
85*9678Slinton 		++j;
86*9678Slinton 	    }
87*9678Slinton 	}
88*9678Slinton 	newfrp->condition_handler = frame.condition_handler;
89*9678Slinton 	newfrp->mask = mask;
90*9678Slinton 	newfrp->save_ap = frame.save_ap;
91*9678Slinton 	newfrp->save_fp = frame.save_fp;
92*9678Slinton 	newfrp->save_pc = frame.save_pc;
93*9678Slinton     }
94*9678Slinton     return newfrp;
95*9678Slinton }
96*9678Slinton 
97*9678Slinton /*
98*9678Slinton  * Return the frame associated with the given function.
99*9678Slinton  * If the function is nil, return the most recently activated frame.
100*9678Slinton  *
101*9678Slinton  * Static allocation for the frame.
102*9678Slinton  */
103*9678Slinton 
104*9678Slinton public Frame findframe(f)
105*9678Slinton Symbol f;
106*9678Slinton {
107*9678Slinton     register Frame frp;
108*9678Slinton     static struct Frame frame;
109*9678Slinton 
110*9678Slinton     frp = &frame;
111*9678Slinton     getcurframe(frp);
112*9678Slinton     if (f != nil) {
113*9678Slinton 	while (frp != nil and whatblock(frp->save_pc) != f) {
114*9678Slinton 	    frp = nextframe(frp);
115*9678Slinton 	}
116*9678Slinton     }
117*9678Slinton     return frp;
118*9678Slinton }
119*9678Slinton 
120*9678Slinton /*
121*9678Slinton  * Find the return address of the current procedure/function.
122*9678Slinton  */
123*9678Slinton 
124*9678Slinton public Address return_addr()
125*9678Slinton {
126*9678Slinton     Frame frp;
127*9678Slinton     Address addr;
128*9678Slinton     struct Frame frame;
129*9678Slinton 
130*9678Slinton     frp = &frame;
131*9678Slinton     getcurframe(frp);
132*9678Slinton     frp = nextframe(frp);
133*9678Slinton     if (frp == nil) {
134*9678Slinton 	addr = 0;
135*9678Slinton     } else {
136*9678Slinton 	addr = frp->save_pc;
137*9678Slinton     }
138*9678Slinton     return addr;
139*9678Slinton }
140*9678Slinton 
141*9678Slinton /*
142*9678Slinton  * Push the value associated with the current function.
143*9678Slinton  */
144*9678Slinton 
145*9678Slinton public pushretval(len, isindirect)
146*9678Slinton Integer len;
147*9678Slinton Boolean isindirect;
148*9678Slinton {
149*9678Slinton     Word r0;
150*9678Slinton 
151*9678Slinton     r0 = reg(0);
152*9678Slinton     if (isindirect) {
153*9678Slinton 	rpush((Address) r0, len);
154*9678Slinton     } else {
155*9678Slinton 	switch (len) {
156*9678Slinton 	    case sizeof(char):
157*9678Slinton 		push(char, r0);
158*9678Slinton 		break;
159*9678Slinton 
160*9678Slinton 	    case sizeof(short):
161*9678Slinton 		push(short, r0);
162*9678Slinton 		break;
163*9678Slinton 
164*9678Slinton 	    default:
165*9678Slinton 		if (len == sizeof(Word)) {
166*9678Slinton 		    push(Word, r0);
167*9678Slinton 		} else if (len == 2*sizeof(Word)) {
168*9678Slinton 		    push(Word, r0);
169*9678Slinton 		    push(Word, reg(1));
170*9678Slinton 		} else {
171*9678Slinton 		    panic("not indirect in pushretval?");
172*9678Slinton 		}
173*9678Slinton 		break;
174*9678Slinton 	}
175*9678Slinton     }
176*9678Slinton }
177*9678Slinton 
178*9678Slinton /*
179*9678Slinton  * Return the base address for locals in the given frame.
180*9678Slinton  */
181*9678Slinton 
182*9678Slinton public Address locals_base(frp)
183*9678Slinton register Frame frp;
184*9678Slinton {
185*9678Slinton     return (frp == nil) ? reg(FRP) : frp->save_fp;
186*9678Slinton }
187*9678Slinton 
188*9678Slinton /*
189*9678Slinton  * Return the base address for arguments in the given frame.
190*9678Slinton  */
191*9678Slinton 
192*9678Slinton public Address args_base(frp)
193*9678Slinton register Frame frp;
194*9678Slinton {
195*9678Slinton     return (frp == nil) ? reg(ARGP) : frp->save_ap;
196*9678Slinton }
197*9678Slinton 
198*9678Slinton /*
199*9678Slinton  * Return saved register n from the given frame.
200*9678Slinton  */
201*9678Slinton 
202*9678Slinton public Word savereg(n, frp)
203*9678Slinton register Integer n;
204*9678Slinton register Frame frp;
205*9678Slinton {
206*9678Slinton     register Word w;
207*9678Slinton 
208*9678Slinton     if (frp == nil) {
209*9678Slinton 	w = reg(n);
210*9678Slinton     } else {
211*9678Slinton 	switch (n) {
212*9678Slinton 	    case ARGP:
213*9678Slinton 		w = frp->save_ap;
214*9678Slinton 		break;
215*9678Slinton 
216*9678Slinton 	    case FRP:
217*9678Slinton 		w = frp->save_fp;
218*9678Slinton 		break;
219*9678Slinton 
220*9678Slinton 	    case STKP:
221*9678Slinton 		w = reg(STKP);
222*9678Slinton 		break;
223*9678Slinton 
224*9678Slinton 	    case PROGCTR:
225*9678Slinton 		w = frp->save_pc;
226*9678Slinton 		break;
227*9678Slinton 
228*9678Slinton 	    default:
229*9678Slinton 		assert(n >= 0 and n < NSAVEREG);
230*9678Slinton 		w = frp->save_reg[n];
231*9678Slinton 		break;
232*9678Slinton 	}
233*9678Slinton     }
234*9678Slinton     return w;
235*9678Slinton }
236*9678Slinton 
237*9678Slinton /*
238*9678Slinton  * Return the nth argument to the current procedure.
239*9678Slinton  */
240*9678Slinton 
241*9678Slinton public Word argn(n, frp)
242*9678Slinton Integer n;
243*9678Slinton Frame frp;
244*9678Slinton {
245*9678Slinton     Word w;
246*9678Slinton 
247*9678Slinton     dread(&w, args_base(frp) + (n * sizeof(Word)), sizeof(w));
248*9678Slinton     return w;
249*9678Slinton }
250*9678Slinton 
251*9678Slinton /*
252*9678Slinton  * Calculate the entry address for a procedure or function parameter,
253*9678Slinton  * given the address of the descriptor.
254*9678Slinton  */
255*9678Slinton 
256*9678Slinton public Address fparamaddr(a)
257*9678Slinton Address a;
258*9678Slinton {
259*9678Slinton     Address r;
260*9678Slinton 
261*9678Slinton     dread(&r, a, sizeof(r));
262*9678Slinton     return r;
263*9678Slinton }
264*9678Slinton 
265*9678Slinton /*
266*9678Slinton  * Print a list of currently active blocks starting with most recent.
267*9678Slinton  */
268*9678Slinton 
269*9678Slinton public wherecmd()
270*9678Slinton {
271*9678Slinton     walkstack(false);
272*9678Slinton }
273*9678Slinton 
274*9678Slinton /*
275*9678Slinton  * Dump the world to the given file.
276*9678Slinton  * Like "where", but variables are dumped also.
277*9678Slinton  */
278*9678Slinton 
279*9678Slinton public dump()
280*9678Slinton {
281*9678Slinton     walkstack(true);
282*9678Slinton }
283*9678Slinton 
284*9678Slinton /*
285*9678Slinton  * Walk the stack of active procedures printing information
286*9678Slinton  * about each active procedure.
287*9678Slinton  */
288*9678Slinton 
289*9678Slinton #define lastfunc(f)     (f == program)
290*9678Slinton 
291*9678Slinton private walkstack(dumpvariables)
292*9678Slinton Boolean dumpvariables;
293*9678Slinton {
294*9678Slinton     register Frame frp;
295*9678Slinton     register Symbol f;
296*9678Slinton     register Boolean save;
297*9678Slinton     register Lineno line;
298*9678Slinton     struct Frame frame;
299*9678Slinton 
300*9678Slinton     if (notstarted(process)) {
301*9678Slinton 	error("program is not active");
302*9678Slinton     } else {
303*9678Slinton 	save = walkingstack;
304*9678Slinton 	walkingstack = true;
305*9678Slinton 	frp = &frame;
306*9678Slinton 	getcurframe(frp);
307*9678Slinton 	f = whatblock(frp->save_pc);
308*9678Slinton 	do {
309*9678Slinton 	    printf("%s", symname(f));
310*9678Slinton 	    printparams(f, frp);
311*9678Slinton 	    line = srcline(frp->save_pc);
312*9678Slinton 	    if (line != 0) {
313*9678Slinton 		printf(", line %d", line);
314*9678Slinton 		printf(" in \"%s\"\n", srcfilename(frp->save_pc));
315*9678Slinton 	    } else {
316*9678Slinton 		printf(" at 0x%x\n", frp->save_pc);
317*9678Slinton 	    }
318*9678Slinton 	    if (dumpvariables) {
319*9678Slinton 		dumpvars(f, frp);
320*9678Slinton 		putchar('\n');
321*9678Slinton 	    }
322*9678Slinton 	    frp = nextframe(frp);
323*9678Slinton 	    if (frp != nil) {
324*9678Slinton 		f = whatblock(frp->save_pc);
325*9678Slinton 	    }
326*9678Slinton 	} while (frp != nil and not lastfunc(f));
327*9678Slinton 	if (dumpvariables) {
328*9678Slinton 	    printf("in \"%s\":\n", symname(program));
329*9678Slinton 	    dumpvars(program, nil);
330*9678Slinton 	    putchar('\n');
331*9678Slinton 	}
332*9678Slinton 	walkingstack = save;
333*9678Slinton     }
334*9678Slinton }
335*9678Slinton 
336*9678Slinton /*
337*9678Slinton  * Find the entry point of a procedure or function.
338*9678Slinton  */
339*9678Slinton 
340*9678Slinton public findbeginning(f)
341*9678Slinton Symbol f;
342*9678Slinton {
343*9678Slinton     f->symvalue.funcv.beginaddr += 2;
344*9678Slinton }
345*9678Slinton 
346*9678Slinton /*
347*9678Slinton  * Return the address corresponding to the first line in a function.
348*9678Slinton  */
349*9678Slinton 
350*9678Slinton public Address firstline(f)
351*9678Slinton Symbol f;
352*9678Slinton {
353*9678Slinton     Address addr;
354*9678Slinton 
355*9678Slinton     addr = codeloc(f);
356*9678Slinton     while (linelookup(addr) == 0 and addr < objsize) {
357*9678Slinton 	++addr;
358*9678Slinton     }
359*9678Slinton     if (addr == objsize) {
360*9678Slinton 	addr = -1;
361*9678Slinton     }
362*9678Slinton     return addr;
363*9678Slinton }
364*9678Slinton 
365*9678Slinton /*
366*9678Slinton  * Catcher drops strike three ...
367*9678Slinton  */
368*9678Slinton 
369*9678Slinton public runtofirst()
370*9678Slinton {
371*9678Slinton     Address addr;
372*9678Slinton 
373*9678Slinton     addr = pc;
374*9678Slinton     while (linelookup(addr) == 0 and addr < objsize) {
375*9678Slinton 	++addr;
376*9678Slinton     }
377*9678Slinton     if (addr < objsize) {
378*9678Slinton 	stepto(addr);
379*9678Slinton     }
380*9678Slinton }
381*9678Slinton 
382*9678Slinton /*
383*9678Slinton  * Return the address corresponding to the end of the program.
384*9678Slinton  *
385*9678Slinton  * We look for the entry to "exit".
386*9678Slinton  */
387*9678Slinton 
388*9678Slinton public Address lastaddr()
389*9678Slinton {
390*9678Slinton     register Symbol s;
391*9678Slinton 
392*9678Slinton     s = lookup(identname("exit", true));
393*9678Slinton     if (s == nil) {
394*9678Slinton 	panic("can't find exit");
395*9678Slinton     }
396*9678Slinton     return codeloc(s);
397*9678Slinton }
398*9678Slinton 
399*9678Slinton /*
400*9678Slinton  * Decide if the given function is currently active.
401*9678Slinton  *
402*9678Slinton  * We avoid calls to "findframe" during a stack trace for efficiency.
403*9678Slinton  * Presumably information evaluated while walking the stack is active.
404*9678Slinton  */
405*9678Slinton 
406*9678Slinton public Boolean isactive(f)
407*9678Slinton Symbol f;
408*9678Slinton {
409*9678Slinton     register Boolean b;
410*9678Slinton 
411*9678Slinton     if (isfinished(process)) {
412*9678Slinton 	b = false;
413*9678Slinton     } else {
414*9678Slinton 	if (walkingstack or f == program or
415*9678Slinton 	  (ismodule(f) and isactive(container(f)))) {
416*9678Slinton 	    b = true;
417*9678Slinton 	} else {
418*9678Slinton 	    b = (Boolean) (findframe(f) != nil);
419*9678Slinton 	}
420*9678Slinton     }
421*9678Slinton     return b;
422*9678Slinton }
423*9678Slinton 
424*9678Slinton /*
425*9678Slinton  * Evaluate a call to a procedure.
426*9678Slinton  */
427*9678Slinton 
428*9678Slinton public callproc(procnode, arglist)
429*9678Slinton Node procnode;
430*9678Slinton Node arglist;
431*9678Slinton {
432*9678Slinton     Symbol proc;
433*9678Slinton     Integer argc;
434*9678Slinton 
435*9678Slinton     if (procnode->op != O_SYM) {
436*9678Slinton 	beginerrmsg();
437*9678Slinton 	fprintf(stderr, "can't call \"");
438*9678Slinton 	prtree(stderr, procnode);
439*9678Slinton 	fprintf(stderr, "\"");
440*9678Slinton 	enderrmsg();
441*9678Slinton     }
442*9678Slinton     assert(procnode->op == O_SYM);
443*9678Slinton     proc = procnode->value.sym;
444*9678Slinton     if (not isblock(proc)) {
445*9678Slinton 	error("\"%s\" is not a procedure or function", symname(proc));
446*9678Slinton     }
447*9678Slinton     pushenv();
448*9678Slinton     pc = codeloc(proc);
449*9678Slinton     argc = pushargs(proc, arglist);
450*9678Slinton     beginproc(proc, argc);
451*9678Slinton     isstopped = true;
452*9678Slinton     event_once(build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)),
453*9678Slinton 	buildcmdlist(build(O_PROCRTN, proc)));
454*9678Slinton     cont();
455*9678Slinton     /* NOTREACHED */
456*9678Slinton }
457*9678Slinton 
458*9678Slinton /*
459*9678Slinton  * Push the arguments on the process' stack.  We do this by first
460*9678Slinton  * evaluating them on the "eval" stack, then copying into the process'
461*9678Slinton  * space.
462*9678Slinton  */
463*9678Slinton 
464*9678Slinton private Integer pushargs(proc, arglist)
465*9678Slinton Symbol proc;
466*9678Slinton Node arglist;
467*9678Slinton {
468*9678Slinton     Stack *savesp;
469*9678Slinton     int argc, args_size;
470*9678Slinton 
471*9678Slinton     savesp = sp;
472*9678Slinton     argc = evalargs(proc, arglist);
473*9678Slinton     args_size = sp - savesp;
474*9678Slinton     setreg(STKP, reg(STKP) - args_size);
475*9678Slinton     dwrite(savesp, reg(STKP), args_size);
476*9678Slinton     sp = savesp;
477*9678Slinton     return argc;
478*9678Slinton }
479*9678Slinton 
480*9678Slinton /*
481*9678Slinton  * Evaluate arguments left-to-right.
482*9678Slinton  */
483*9678Slinton 
484*9678Slinton private Integer evalargs(proc, arglist)
485*9678Slinton Symbol proc;
486*9678Slinton Node arglist;
487*9678Slinton {
488*9678Slinton     Node p, exp;
489*9678Slinton     Symbol arg;
490*9678Slinton     Stack *savesp;
491*9678Slinton     Address addr;
492*9678Slinton     Integer count;
493*9678Slinton 
494*9678Slinton     savesp = sp;
495*9678Slinton     count = 0;
496*9678Slinton     arg = proc->chain;
497*9678Slinton     for (p = arglist; p != nil; p = p->value.arg[1]) {
498*9678Slinton 	if (p->op != O_COMMA) {
499*9678Slinton 	    panic("evalargs: arglist missing comma");
500*9678Slinton 	}
501*9678Slinton 	if (arg == nil) {
502*9678Slinton 	    sp = savesp;
503*9678Slinton 	    error("too many parameters to %s", symname(proc));
504*9678Slinton 	}
505*9678Slinton 	exp = p->value.arg[0];
506*9678Slinton 	if (not compatible(arg->type, exp->nodetype)) {
507*9678Slinton 	    sp = savesp;
508*9678Slinton 	    error("expression for parameter %s is of wrong type", symname(arg));
509*9678Slinton 	}
510*9678Slinton 	if (arg->class == REF) {
511*9678Slinton 	    if (exp->op != O_RVAL) {
512*9678Slinton 		sp = savesp;
513*9678Slinton 		error("variable expected for parameter \"%s\"", symname(arg));
514*9678Slinton 	    }
515*9678Slinton 	    addr = lval(exp->value.arg[0]);
516*9678Slinton 	    push(Address, addr);
517*9678Slinton 	} else {
518*9678Slinton 	    eval(exp);
519*9678Slinton 	}
520*9678Slinton 	arg = arg->chain;
521*9678Slinton 	++count;
522*9678Slinton     }
523*9678Slinton     if (arg != nil) {
524*9678Slinton 	sp = savesp;
525*9678Slinton 	error("not enough parameters to %s", symname(proc));
526*9678Slinton     }
527*9678Slinton     return count;
528*9678Slinton }
529*9678Slinton 
530*9678Slinton public procreturn(f)
531*9678Slinton Symbol f;
532*9678Slinton {
533*9678Slinton     flushoutput();
534*9678Slinton     putchar('\n');
535*9678Slinton     printname(stdout, f);
536*9678Slinton     printf(" returns successfully\n", symname(f));
537*9678Slinton     popenv();
538*9678Slinton     erecover();
539*9678Slinton }
540*9678Slinton 
541*9678Slinton /*
542*9678Slinton  * Push the current environment.
543*9678Slinton  */
544*9678Slinton 
545*9678Slinton private pushenv()
546*9678Slinton {
547*9678Slinton     push(Address, pc);
548*9678Slinton     push(Lineno, curline);
549*9678Slinton     push(String, cursource);
550*9678Slinton     push(Boolean, isstopped);
551*9678Slinton     push(Symbol, curfunc);
552*9678Slinton     push(Word, reg(PROGCTR));
553*9678Slinton     push(Word, reg(STKP));
554*9678Slinton }
555*9678Slinton 
556*9678Slinton /*
557*9678Slinton  * Pop back to the real world.
558*9678Slinton  */
559*9678Slinton 
560*9678Slinton public popenv()
561*9678Slinton {
562*9678Slinton     register String filename;
563*9678Slinton 
564*9678Slinton     setreg(STKP, pop(Word));
565*9678Slinton     setreg(PROGCTR, pop(Word));
566*9678Slinton     curfunc = pop(Symbol);
567*9678Slinton     isstopped = pop(Boolean);
568*9678Slinton     filename = pop(String);
569*9678Slinton     curline = pop(Lineno);
570*9678Slinton     pc = pop(Address);
571*9678Slinton     setsource(filename);
572*9678Slinton }
573*9678Slinton 
574*9678Slinton /*
575*9678Slinton  * Flush the debuggee's standard output.
576*9678Slinton  *
577*9678Slinton  * This is VERY dependent on the use of stdio.
578*9678Slinton  */
579*9678Slinton 
580*9678Slinton public flushoutput()
581*9678Slinton {
582*9678Slinton     register Symbol p, iob;
583*9678Slinton     register Stack *savesp;
584*9678Slinton 
585*9678Slinton     p = lookup(identname("fflush", true));
586*9678Slinton     while (p != nil and not isblock(p)) {
587*9678Slinton 	p = p->next_sym;
588*9678Slinton     }
589*9678Slinton     if (p != nil) {
590*9678Slinton 	iob = lookup(identname("_iob", true));
591*9678Slinton 	if (iob != nil) {
592*9678Slinton 	    pushenv();
593*9678Slinton 	    pc = codeloc(p);
594*9678Slinton 	    savesp = sp;
595*9678Slinton 	    push(long, address(iob, nil) + sizeof(struct _iobuf));
596*9678Slinton 	    setreg(STKP, reg(STKP) - sizeof(long));
597*9678Slinton 	    dwrite(savesp, reg(STKP), sizeof(long));
598*9678Slinton 	    sp = savesp;
599*9678Slinton 	    beginproc(p, 1);
600*9678Slinton 	    stepto(return_addr());
601*9678Slinton 	    popenv();
602*9678Slinton 	}
603*9678Slinton     }
604*9678Slinton }
605