148096Sbostic /*-
262144Sbostic  * Copyright (c) 1980, 1993
362144Sbostic  *	The Regents of the University of California.  All rights reserved.
448096Sbostic  *
548096Sbostic  * %sccs.include.redist.c%
622510Sdist  */
710768Slinton 
822510Sdist #ifndef lint
9*67271Shibler static char sccsid[] = "@(#)ptrace.c	8.3 (Berkeley) 05/31/94";
1048096Sbostic #endif /* not lint */
115507Slinton 
125507Slinton /*
135507Slinton  * routines for tracing the execution of a process
145507Slinton  *
155507Slinton  * The system call "ptrace" does all the work, these
165507Slinton  * routines just try to interface easily to it.
175507Slinton  */
185507Slinton 
195507Slinton #include "defs.h"
205507Slinton #include <signal.h>
215507Slinton #include <sys/param.h>
2210004Ssam #include <machine/reg.h>
235507Slinton #include "process.h"
245507Slinton #include "object.h"
255507Slinton #include "process.rep"
265507Slinton 
276072Slinton #       include "pxinfo.h"
285507Slinton 
2930848Smckusick #ifdef mc68000
30*67271Shibler #if defined(hp300) || defined(luna68k)
31*67271Shibler #include <sys/user.h>
32*67271Shibler #	define U_PAGE 0xfff00000
33*67271Shibler #	define U_AR0  (int)&((struct user *)0)->u_ar0
34*67271Shibler #else
3510768Slinton #	define U_PAGE 0x2400
3610768Slinton #	define U_AR0  (14*sizeof(int))
37*67271Shibler #endif
3810768Slinton 	LOCAL int ar0val = -1;
3910768Slinton #endif
4010768Slinton 
415507Slinton /*
425507Slinton  * This magic macro enables us to look at the process' registers
435507Slinton  * in its user structure.  Very gross.
445507Slinton  */
455507Slinton 
4630848Smckusick #if defined(vax) || defined(tahoe)
4710768Slinton #	define regloc(reg)     (ctob(UPAGES) + ( sizeof(int) * (reg) ))
4810768Slinton #else
49*67271Shibler #if defined(hp300) || defined(luna68k)
50*67271Shibler #	define regloc(reg)     \
51*67271Shibler 	(ar0val + ( sizeof(int) * (reg) + ((reg) >= PS ? 2 : 0) ))
52*67271Shibler #else
5310768Slinton #	define regloc(reg)     (ar0val + ( sizeof(int) * (reg) ))
5410768Slinton #endif
55*67271Shibler #endif
565507Slinton 
576072Slinton #define WMASK           (~(sizeof(WORD) - 1))
586072Slinton #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE))
595507Slinton 
606072Slinton #define ischild(pid)    ((pid) == 0)
616072Slinton #define traceme()       ptrace(0, 0, 0, 0)
626072Slinton #define setrep(n)       (1 << ((n)-1))
636072Slinton #define istraced(p)     (p->sigset&setrep(p->signo))
645507Slinton 
655507Slinton /*
665507Slinton  * ptrace options (specified in first argument)
675507Slinton  */
685507Slinton 
696072Slinton #define UREAD   3       /* read from process's user structure */
706072Slinton #define UWRITE  6       /* write to process's user structure */
716072Slinton #define IREAD   1       /* read from process's instruction space */
726072Slinton #define IWRITE  4       /* write to process's instruction space */
736072Slinton #define DREAD   2       /* read from process's data space */
746072Slinton #define DWRITE  5       /* write to process's data space */
756072Slinton #define CONT    7       /* continue stopped process */
766072Slinton #define SSTEP   9       /* continue for approximately one instruction */
776072Slinton #define PKILL   8       /* terminate the process */
785507Slinton 
795507Slinton /*
805507Slinton  * Start up a new process by forking and exec-ing the
815507Slinton  * given argument list, returning when the process is loaded
825507Slinton  * and ready to execute.  The PROCESS information (pointed to
835507Slinton  * by the first argument) is appropriately filled.
845507Slinton  *
855507Slinton  * If the given PROCESS structure is associated with an already running
865507Slinton  * process, we terminate it.
875507Slinton  */
885507Slinton 
895507Slinton /* VARARGS2 */
pstart(p,cmd,argv,infile,outfile)905607Slinton pstart(p, cmd, argv, infile, outfile)
915507Slinton PROCESS *p;
925607Slinton char *cmd;
935507Slinton char **argv;
945507Slinton char *infile;
955507Slinton char *outfile;
965507Slinton {
976072Slinton     int status;
986072Slinton     FILE *in, *out;
995507Slinton 
1006072Slinton     if (p->pid != 0) {                  /* child already running? */
1016072Slinton 	ptrace(PKILL, p->pid, 0, 0);    /* ... kill it! */
1026072Slinton     }
10331082Smckusick #ifdef tahoe
10430848Smckusick     INTFP = (ADDRESS)0;
10531082Smckusick #endif tahoe
1066072Slinton     psigtrace(p, SIGTRAP, TRUE);
1076072Slinton     if ((p->pid = fork()) == -1) {
1086072Slinton 	panic("can't fork");
1096072Slinton     }
1106072Slinton     if (ischild(p->pid)) {
1116072Slinton 	traceme();
1126072Slinton 	if (infile != NIL) {
1136072Slinton 	    if ((in = fopen(infile, "r")) == NIL) {
1146072Slinton 		printf("can't read %s\n", infile);
1156072Slinton 		exit(1);
1166072Slinton 	    }
1176072Slinton 	    fswap(0, fileno(in));
1185507Slinton 	}
1196072Slinton 	if (outfile != NIL) {
1206072Slinton 	    if ((out = fopen(outfile, "w")) == NIL) {
1216072Slinton 		printf("can't write %s\n", outfile);
1226072Slinton 		exit(1);
1236072Slinton 	    }
1246072Slinton 	    fswap(1, fileno(out));
1255507Slinton 	}
1266072Slinton 	execvp(cmd, argv);
1276072Slinton 	panic("can't exec %s", argv[0]);
1286072Slinton     }
1296072Slinton     pwait(p->pid, &status);
1306072Slinton     getinfo(p, status);
1315507Slinton }
1325507Slinton 
1335507Slinton /*
1345507Slinton  * Continue a stopped process.  The argument points to a PROCESS structure.
1355507Slinton  * Before the process is restarted it's user area is modified according to
1365507Slinton  * the values in the structure.  When this routine finishes,
1375507Slinton  * the structure has the new values from the process's user area.
1385507Slinton  *
1395507Slinton  * Pcont terminates when the process stops with a signal pending that
1405507Slinton  * is being traced (via psigtrace), or when the process terminates.
1415507Slinton  */
1425507Slinton 
pcont(p)1435507Slinton pcont(p)
1445507Slinton PROCESS *p;
1455507Slinton {
1466072Slinton     int status;
1475507Slinton 
1486072Slinton     if (p->pid == 0) {
1496072Slinton 	error("program not active");
1506072Slinton     }
1516072Slinton     do {
1526072Slinton 	setinfo(p);
1536072Slinton 	sigs_off();
1546072Slinton 	if (ptrace(CONT, p->pid, p->pc, p->signo) < 0) {
1556072Slinton 	    panic("can't continue process");
1565507Slinton 	}
1576072Slinton 	pwait(p->pid, &status);
1586072Slinton 	sigs_on();
1596072Slinton 	getinfo(p, status);
1606072Slinton     } while (p->status == STOPPED && !istraced(p));
1615507Slinton }
1625507Slinton 
1635507Slinton /*
1645507Slinton  * single step as best ptrace can
1655507Slinton  */
1665507Slinton 
pstep(p)1675507Slinton pstep(p)
1685507Slinton PROCESS *p;
1695507Slinton {
1706072Slinton     int status;
1715507Slinton 
1726072Slinton     setinfo(p);
1736072Slinton     sigs_off();
1746072Slinton     ptrace(SSTEP, p->pid, p->pc, p->signo);
1756072Slinton     pwait(p->pid, &status);
1766072Slinton     sigs_on();
1776072Slinton     getinfo(p, status);
1785507Slinton }
1795507Slinton 
1805507Slinton /*
1815507Slinton  * Return from execution when the given signal is pending.
1825507Slinton  */
1835507Slinton 
psigtrace(p,sig,sw)1845507Slinton psigtrace(p, sig, sw)
1855507Slinton PROCESS *p;
1865507Slinton int sig;
1875507Slinton int sw;
1885507Slinton {
1896072Slinton     if (sw) {
1906072Slinton 	p->sigset |= setrep(sig);
1916072Slinton     } else {
1926072Slinton 	p->sigset &= ~setrep(sig);
1936072Slinton     }
1945507Slinton }
1955507Slinton 
1965507Slinton /*
1975507Slinton  * Don't catch any signals.
1985507Slinton  * Particularly useful when letting a process finish uninhibited (i.e. px).
1995507Slinton  */
2005507Slinton 
unsetsigtraces(p)2015507Slinton unsetsigtraces(p)
2025507Slinton PROCESS *p;
2035507Slinton {
2046072Slinton     p->sigset = 0;
2055507Slinton }
2065507Slinton 
2075507Slinton /*
2085507Slinton  * turn off attention to signals not being caught
2095507Slinton  */
2105507Slinton 
21145437Sbostic LOCAL void *onintr, *onquit;
2125507Slinton 
sigs_off()2135507Slinton LOCAL sigs_off()
2145507Slinton {
21530848Smckusick     onintr = signal(SIGINT, SIG_IGN);
21630848Smckusick     onquit = signal(SIGQUIT, SIG_IGN);
2175507Slinton }
2185507Slinton 
2195507Slinton /*
2205507Slinton  * turn back on attention to signals
2215507Slinton  */
2225507Slinton 
sigs_on()2235507Slinton LOCAL sigs_on()
2245507Slinton {
22530848Smckusick     (void) signal(SIGINT, onintr);
22630848Smckusick     (void) signal(SIGQUIT, onquit);
2275507Slinton }
2285507Slinton 
2295507Slinton /*
2305507Slinton  * get PROCESS information from process's user area
2315507Slinton  */
2325507Slinton 
23310768Slinton #if vax
23410768Slinton     LOCAL int rloc[] ={
23510768Slinton 	R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11,
23610768Slinton     };
23730848Smckusick #endif
23830848Smckusick #if tahoe
23910768Slinton     LOCAL int rloc[] ={
24030848Smckusick 	R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12,
24130848Smckusick     };
24230848Smckusick #endif
24330848Smckusick #if mc68000
24430848Smckusick     LOCAL int rloc[] ={
24567255Smckusick 	D0, D1, D2, D3, D4, D5, D6, D7, A0, A1, A2, A3, A4, A5,
24610768Slinton     };
24710768Slinton #endif
2485507Slinton 
getinfo(p,status)2495507Slinton LOCAL getinfo(p, status)
2505507Slinton register PROCESS *p;
2515507Slinton register int status;
2525507Slinton {
2536072Slinton     register int i;
2545507Slinton 
2556072Slinton     p->signo = (status&0177);
2566072Slinton     p->exitval = ((status >> 8)&0377);
2576072Slinton     if (p->signo == STOPPED) {
2586072Slinton 	p->status = p->signo;
2596072Slinton 	p->signo = p->exitval;
2606072Slinton 	p->exitval = 0;
2616072Slinton     } else {
2626072Slinton 	p->status = FINISHED;
2636072Slinton 	return;
2646072Slinton     }
26530848Smckusick #if !defined(vax) && !defined(tahoe)
26610768Slinton     if (ar0val < 0){
26710768Slinton 	ar0val = ptrace(UREAD, p->pid, U_AR0, 0);
26810768Slinton 	ar0val -= U_PAGE;
26910768Slinton     }
27010768Slinton #endif
2716072Slinton     for (i = 0; i < NREG; i++) {
2726072Slinton 	p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0);
2736072Slinton 	p->oreg[i] = p->reg[i];
2746072Slinton     }
27530848Smckusick #if defined(vax) || defined(tahoe)
2766072Slinton     p->fp = p->ofp = ptrace(UREAD, p->pid, regloc(FP), 0);
2776072Slinton     p->sp = p->osp = ptrace(UREAD, p->pid, regloc(SP), 0);
2786072Slinton     p->pc = p->opc = ptrace(UREAD, p->pid, regloc(PC), 0);
27930848Smckusick #endif
28030848Smckusick #ifdef vax
28130848Smckusick     p->ap = p->oap = ptrace(UREAD, p->pid, regloc(AP), 0);
28230848Smckusick #endif
28330848Smckusick #ifdef mc68000
28467255Smckusick     p->fp = p->ofp = ptrace(UREAD, p->pid, regloc(A6), 0);
28510768Slinton     p->ap = p->oap = p->fp;
28610768Slinton     p->sp = p->osp = ptrace(UREAD, p->pid, regloc(SP), 0);
28710768Slinton     p->pc = p->opc = ptrace(UREAD, p->pid, regloc(PC), 0);
28810768Slinton #endif
2895507Slinton }
2905507Slinton 
2915507Slinton /*
2925507Slinton  * set process's user area information from given PROCESS structure
2935507Slinton  */
2945507Slinton 
setinfo(p)2955507Slinton LOCAL setinfo(p)
2965507Slinton register PROCESS *p;
2975507Slinton {
2986072Slinton     register int i;
2996072Slinton     register int r;
3005507Slinton 
3016072Slinton     if (istraced(p)) {
3026072Slinton 	p->signo = 0;
3036072Slinton     }
3046072Slinton     for (i = 0; i < NREG; i++) {
3056072Slinton 	if ((r = p->reg[i]) != p->oreg[i]) {
3066072Slinton 	    ptrace(UWRITE, p->pid, regloc(rloc[i]), r);
3075507Slinton 	}
3086072Slinton     }
30930848Smckusick #if vax || tahoe
3106072Slinton     if ((r = p->fp) != p->ofp) {
3116072Slinton 	ptrace(UWRITE, p->pid, regloc(FP), r);
3126072Slinton     }
31330848Smckusick #endif
31430848Smckusick #if vax
3156072Slinton     if ((r = p->ap) != p->oap) {
3166072Slinton 	ptrace(UWRITE, p->pid, regloc(AP), r);
3176072Slinton     }
31830848Smckusick #endif
31930848Smckusick #if mc68000
32010768Slinton     if ((r = p->fp) != p->ofp) {
32167255Smckusick 	ptrace(UWRITE, p->pid, regloc(A6), r);
32210768Slinton     }
32330848Smckusick #endif
32410768Slinton     if ((r = p->sp) != p->osp) {
32510768Slinton 	ptrace(UWRITE, p->pid, regloc(SP), r);
32610768Slinton     }
3276072Slinton     if ((r = p->pc) != p->opc) {
3286072Slinton 	ptrace(UWRITE, p->pid, regloc(PC), r);
3296072Slinton     }
3305507Slinton }
3315507Slinton 
3325507Slinton /*
3335507Slinton  * Structure for reading and writing by words, but dealing with bytes.
3345507Slinton  */
3355507Slinton 
3365507Slinton typedef union {
3376072Slinton     WORD pword;
3386072Slinton     BYTE pbyte[sizeof(WORD)];
3395507Slinton } PWORD;
3405507Slinton 
3415507Slinton /*
3425507Slinton  * Read (write) from (to) the process' address space.
3435507Slinton  * We must deal with ptrace's inability to look anywhere other
3445507Slinton  * than at a word boundary.
3455507Slinton  */
3465507Slinton 
3475507Slinton LOCAL WORD fetch();
3485507Slinton LOCAL store();
3495507Slinton 
pio(p,op,seg,buff,addr,nbytes)3505507Slinton pio(p, op, seg, buff, addr, nbytes)
3515507Slinton PROCESS *p;
3525507Slinton PIO_OP op;
3535507Slinton PIO_SEG seg;
3545507Slinton char *buff;
3555507Slinton ADDRESS addr;
3565507Slinton int nbytes;
3575507Slinton {
35830848Smckusick     register int i, k;
3596072Slinton     register ADDRESS newaddr;
3606072Slinton     register char *cp;
3616072Slinton     char *bufend;
3626072Slinton     PWORD w;
3636072Slinton     ADDRESS wordaddr;
3646072Slinton     int byteoff;
3655507Slinton 
3666072Slinton     if (p->status != STOPPED) {
3676072Slinton 	error("program is not active");
3686072Slinton     }
3696072Slinton     cp = buff;
3706072Slinton     newaddr = addr;
3716072Slinton     wordaddr = (newaddr&WMASK);
3726072Slinton     if (wordaddr != newaddr) {
3736072Slinton 	w.pword = fetch(p, seg, wordaddr);
3746072Slinton 	for (i = newaddr - wordaddr; i<sizeof(WORD) && nbytes>0; i++) {
3756072Slinton 	    if (op == PREAD) {
3766072Slinton 		*cp++ = w.pbyte[i];
3776072Slinton 	    } else {
3786072Slinton 		w.pbyte[i] = *cp++;
3796072Slinton 	    }
3806072Slinton 	    nbytes--;
3815507Slinton 	}
3826072Slinton 	if (op == PWRITE) {
3836072Slinton 	    store(p, seg, wordaddr, w.pword);
3845507Slinton 	}
3856072Slinton 	newaddr = wordaddr + sizeof(WORD);
3866072Slinton     }
3876072Slinton     byteoff = (nbytes&(~WMASK));
3886072Slinton     nbytes -= byteoff;
3896072Slinton     bufend = cp + nbytes;
3906072Slinton     while (cp < bufend) {
3916072Slinton 	if (op == PREAD) {
39230848Smckusick 	    w.pword = fetch(p, seg, newaddr);
39330848Smckusick 	    for (k = 0; k < sizeof(WORD); k++) {
39430848Smckusick 		*cp++ = w.pbyte[k];
39530848Smckusick 	    }
3966072Slinton 	} else {
39730848Smckusick 	    for (k = 0; k < sizeof(WORD); k++) {
39830848Smckusick 		w.pbyte[k] = *cp++;
39930848Smckusick 	    }
40030848Smckusick 	    store(p, seg, newaddr, w.pword);
4015507Slinton 	}
4026072Slinton 	newaddr += sizeof(WORD);
4036072Slinton     }
4046072Slinton     if (byteoff > 0) {
4056072Slinton 	w.pword = fetch(p, seg, newaddr);
4066072Slinton 	for (i = 0; i < byteoff; i++) {
4076072Slinton 	    if (op == PREAD) {
4086072Slinton 		*cp++ = w.pbyte[i];
4096072Slinton 	    } else {
4106072Slinton 		w.pbyte[i] = *cp++;
4116072Slinton 	    }
4125507Slinton 	}
4136072Slinton 	if (op == PWRITE) {
4146072Slinton 	    store(p, seg, newaddr, w.pword);
4156072Slinton 	}
4166072Slinton     }
4175507Slinton }
4185507Slinton 
4195507Slinton /*
4205507Slinton  * Get a word from a process at the given address.
4215507Slinton  * The address is assumed to be on a word boundary.
4225507Slinton  *
4235507Slinton  * We use a simple cache scheme to avoid redundant references to
4245507Slinton  * the instruction space (which is assumed to be pure).  In the
4255507Slinton  * case of px, the "instruction" space lies between ENDOFF and
4265507Slinton  * ENDOFF + objsize.
4275507Slinton  *
4285507Slinton  * It is necessary to use a write-through scheme so that
4295507Slinton  * breakpoints right next to each other don't interfere.
4305507Slinton  */
4315507Slinton 
fetch(p,seg,addr)4325507Slinton LOCAL WORD fetch(p, seg, addr)
4335507Slinton PROCESS *p;
4345507Slinton PIO_SEG seg;
4355507Slinton register int addr;
4365507Slinton {
4376072Slinton     register CACHEWORD *wp;
4386072Slinton     register WORD w;
4395507Slinton 
4406072Slinton     switch (seg) {
4416072Slinton 	case TEXTSEG:
44230848Smckusick 	    panic("tried to fetch from px i-space");
44330848Smckusick 	    /* NOTREACHED */
44430848Smckusick 
44530848Smckusick 	case DATASEG:
44630848Smckusick 	    if (addr >= ENDOFF && addr < ENDOFF + objsize) {
4476072Slinton 		wp = &p->word[cachehash(addr)];
4486072Slinton 		if (addr == 0 || wp->addr != addr) {
44930848Smckusick 		    w = ptrace(DREAD, p->pid, addr, 0);
4506072Slinton 		    wp->addr = addr;
4516072Slinton 		    wp->val = w;
4526072Slinton 		} else {
4536072Slinton 		    w = wp->val;
4546072Slinton 		}
45530848Smckusick 	    } else {
4566072Slinton 		w = ptrace(DREAD, p->pid, addr, 0);
45730848Smckusick 	    }
4586072Slinton 	    break;
4595507Slinton 
4606072Slinton 	default:
4616072Slinton 	    panic("fetch: bad seg %d", seg);
4626072Slinton 	    /* NOTREACHED */
4636072Slinton     }
4646072Slinton     return(w);
4655507Slinton }
4665507Slinton 
4675507Slinton /*
4685507Slinton  * Put a word into the process' address space at the given address.
4695507Slinton  * The address is assumed to be on a word boundary.
4705507Slinton  */
4715507Slinton 
store(p,seg,addr,data)4725507Slinton LOCAL store(p, seg, addr, data)
4735507Slinton PROCESS *p;
4745507Slinton PIO_SEG seg;
4755507Slinton int addr;
4765507Slinton WORD data;
4775507Slinton {
4786072Slinton     register CACHEWORD *wp;
4795507Slinton 
4806072Slinton     switch (seg) {
4816072Slinton 	case TEXTSEG:
4826072Slinton 	    wp = &p->word[cachehash(addr)];
4836072Slinton 	    wp->addr = addr;
4846072Slinton 	    wp->val = data;
4856072Slinton 	    ptrace(IWRITE, p->pid, addr, data);
4866072Slinton 	    break;
4875507Slinton 
4886072Slinton 	case DATASEG:
48930848Smckusick 	    if (addr >= ENDOFF && addr < ENDOFF + objsize) {
49030848Smckusick 		wp = &p->word[cachehash(addr)];
49130848Smckusick 		wp->addr = addr;
49230848Smckusick 		wp->val = data;
49330848Smckusick 	    }
4946072Slinton 	    ptrace(DWRITE, p->pid, addr, data);
4956072Slinton 	    break;
4965507Slinton 
4976072Slinton 	default:
4986072Slinton 	    panic("store: bad seg %d", seg);
4996072Slinton 	    /*NOTREACHED*/
5006072Slinton     }
5015507Slinton }
5025507Slinton 
5035507Slinton /*
5046072Slinton  * Initialize the instruction cache for a process.
5056072Slinton  * This is particularly necessary after the program has been remade.
5066072Slinton  */
5076072Slinton 
initcache(process)5086072Slinton initcache(process)
5096072Slinton PROCESS *process;
5106072Slinton {
5116072Slinton     register int i;
5126072Slinton 
5136072Slinton     for (i = 0; i < CSIZE; i++) {
5146072Slinton 	process->word[i].addr = 0;
5156072Slinton     }
5166072Slinton }
5176072Slinton 
5186072Slinton /*
5195507Slinton  * Swap file numbers so as to redirect standard input and output.
5205507Slinton  */
5215507Slinton 
fswap(oldfd,newfd)5225507Slinton LOCAL fswap(oldfd, newfd)
5235507Slinton int oldfd;
5245507Slinton int newfd;
5255507Slinton {
5266072Slinton     if (oldfd != newfd) {
5276072Slinton 	close(oldfd);
5286072Slinton 	dup(newfd);
5296072Slinton 	close(newfd);
5306072Slinton     }
5315507Slinton }
53230848Smckusick 
53330848Smckusick #ifdef tahoe
53430848Smckusick BOOLEAN didret;
53530848Smckusick 
53630848Smckusick void
chkret(p,status)53730848Smckusick chkret(p, status)
53830848Smckusick PROCESS *p;
53930848Smckusick int status;
54030848Smckusick {
54130848Smckusick 	if (((status == (SIGILL << 8) | STOPPED) ||
54230848Smckusick 	    (status == (SIGTRAP << 8) | STOPPED))) {
54330848Smckusick 		didret = FALSE;
54430848Smckusick 	} else {
54530848Smckusick 		didret = TRUE;
54630848Smckusick 	}
54730848Smckusick }
54830848Smckusick 
54930848Smckusick void
doret(p)55030848Smckusick doret(p)
55130848Smckusick PROCESS *p;
55230848Smckusick {
55330848Smckusick 	register count = 0;
55430848Smckusick 
55530848Smckusick 	if (!didret) {
55630848Smckusick 	    do {
55730848Smckusick 		if (++count > 5) {
55830848Smckusick 		    panic("px would not return to interpreter");
55930848Smckusick 		}
56030848Smckusick 		p->pc = RETLOC;
56130848Smckusick 		pstep(p);
56230848Smckusick 	    } while(INTFP && p->fp != INTFP);
56330848Smckusick 	    didret = TRUE;
56430848Smckusick 	}
56530848Smckusick }
56630848Smckusick #endif
567