static char rcsid[] = "$Header: runpcs.c,v 800.1 85/10/08 14:31:12 root Exp $";
static char sccsid[]="%W% %Y% %Q% %G%";

#
/****************************************************************************

	DEBUGGER

****************************************************************************/
#include "defs.h"
#define	BKPTI	0x4E420000

MSG		NOFORK;
MSG		NOPCS;
MSG		ENDPCS;
MSG		BADWAIT;
FILE		*outfile;
CHAR		*lp;
INT		errno;
INT		(*sigint)();
INT		(*sigqit)();
STRING		signals[];
STRING	corfil;
BKPTR		lbpt;
BKPTR		bkpthead;
REGLIST		reglist[];
CHAR		lastc;
INT		fcor;
INT		fsym;
STRING		errflg;
INT		signum;
L_INT		dot;
STRING		symfil;
INT		wtflag;
INT		pid;
L_INT		expv;
INT		adrflg;
L_INT		loopcnt;

/* service routines for sub process control */

getsig(sig)
{
	return( expr(0) ? expv : sig );
}

ADDR userpc = 1;

runpcs(runmode, execsig)
{
	register BKPTR	bkpt;
	int		code, status, rc = 1;

	if (!pid) error(NOPCS);
	if (adrflg)
	{
		userpc = dot;
	}

	while( --loopcnt >= 0 )
	{
#ifdef DEBUGADB
	    printf("\ncontinue %x %d\n", userpc, execsig );
#endif
	    if( runmode != SINGLE )	/* hardware handles single-stepping */
	    {
		if( bkpt = scanbkpt( userpc ) )
		{
		    execbkpt( bkpt, execsig );
		    execsig = 0;
		}
		setbp();
	    }

	/* execute the process */

	    ioctl(0, TIOCSETP, &subtty);
	    ioctl(0, TIOCSETC, &subtch);

	    ptrace( runmode, pid, userpc, execsig );

	    bpwait(); chkerr(); execsig = 0; delbp(); readregs();

	    if( ( signum == 0 ) && ( bkpt = scanbkpt( userpc - 2 ) ) )
	    {
	    /* we've hit a breakpoint instruction. backup the pc */

		userpc = reglist[pc].rval = bkpt->loc;

#ifdef DEBUGADB
		printf("\n BPT code; '%s'%o'%o'%d",
		    bkpt->comm, bkpt->comm[0], EOR, bkpt->flag);
#endif
		dot = bkpt->loc;
		if( bkpt->flag == SINGLE )	/* single step or exec */
		{				/*  a subroutine ? */
		    bkpt->flag = 0;		/* now it disappears */
		    execsig = 0;
		    rc = 0;
		}
		else if( ( bkpt->flag == BKPTEXEC ) ||
			   ( ( bkpt->flag = BKPTEXEC )
			   && ( bkpt->comm[0] != EOR )
			   && ( command( bkpt->comm, ':' ) )
			   && --bkpt->count ) )
		{
		    execbkpt( bkpt, execsig );
		    execsig = 0;
		    loopcnt++;
		}
		else
		{
		    bkpt->count = bkpt->initcnt;
		    rc = 1;
		}
	    }
	    else
	    {
	        execsig = signum;
		rc = 0;
	    }
	}
	return( rc );
}
/*
		printf("subroutine call completed"); printc(EOR);
		putreg(pid, reglist[pc].roffs, lbpt->flag);
		putreg(pid, reglist[sp].roffs, lbpt->initcnt);
		reglist[pc].rval = lbpt->flag;
		reglist[sp].rval = lbpt->initcnt;
		dot = lbpt->count; lbpt->flag = 0; lbpt = 0;
		return(lbpt);
 */

#define BPOUT 0
#define BPIN 1
INT bpstate = BPOUT;

endpcs()
{
	register BKPTR	bkptr;

	if (pid)
	{
		printf("sub-process %d killed\n", pid);
		ptrace(EXIT, pid, 0, 0); pid = 0; userpc = 1;
		for(bkptr = bkpthead; bkptr; bkptr = bkptr->nxtbkpt)
			if (bkptr->flag) bkptr->flag = BKPTSET;
	}
	bpstate = BPOUT;
}

setup()
{
	int	status;

	close(fsym); fsym = -1;
	if ((pid = fork()) == 0)
	{
		ptrace(SETTRC, 0, 0, 0);
		signal(SIGINT, sigint);
		signal(SIGQUIT, sigqit);
		doexec(); exit(0);
	}
	else if (pid == -1)
	{
		pid = 0;
		error(NOFORK);
	}
	else
	{
	    bpwait(); readregs();
	    lp[0] = EOR; lp[1] = NULL;
	    fsym = open(symfil, wtflag);
	    if( errflg )
	    {
		printf("cannot execute %s\n", symfil );
		endpcs(); error(0);
	    }
	}
	bpstate = BPOUT;
}

execbkpt(bkptr, execsig )
BKPTR	bkptr;
{
#ifdef DEBUGADB
	printf("exbkpt: %d\n", bkptr->count );
#endif
	ioctl(0, TIOCSETP, &subtty);
	ioctl(0, TIOCSETC, &subtch);
	ptrace(SINGLE, pid, bkptr->loc, execsig);
	bkptr->flag = BKPTSET;
	bpwait(); chkerr(); readregs();
}

doexec()
{
	char		*argl[MAXARG];
	char		args[LINSIZ];
	register char	*p, **ap, *fname;
	extern char *environ;

	ap = argl; p = args; *ap++ = symfil;
	do
	{
		if (rdc() == EOR) break;
		*ap = p;
		while ((lastc != EOR) && (lastc != SPACE) && (lastc != TB))
		{
			*p++ = lastc;
			readchar();
		}
		*p++ = NULL; fname = *ap + 1;
		if (**ap == '<')
		{
			close(0);
			if (open(fname, 0) < 0)	
			{
				printf("cannot open %s\n", fname);
				exit(0);
			}
		}
		else if (**ap == '>')
		{
			close(1);
			if (creat(fname, 0666) < 0)
			{
				printf("cannot create %s\n", fname);
				exit(0);
			}
		}
		else ap++;
	}
	while (lastc != EOR);
	
	*ap++ = NULL;
	execv(symfil, argl, environ);
}

BKPTR
scanbkpt(adr)
ADDR adr;
{

	register BKPTR	bkptr;

	for(bkptr = bkpthead; bkptr; bkptr = bkptr->nxtbkpt)
	if (bkptr->flag && (bkptr->loc == adr)) break;
	return(bkptr);
}

delbp()
{
	register BKPTR	bkptr;

	if (pid && (bpstate != BPOUT))
	for(bkptr = bkpthead; bkptr; bkptr = bkptr->nxtbkpt)
		if (bkptr->flag &&( ( ptrace(RIUSER, pid, bkptr->loc, 0) & 0xFFFF0000) == BKPTI ) )
			ptrace(WIUSER, pid, bkptr->loc, bkptr->ins);
	bpstate = BPOUT;
}

setbp()
{
	register BKPTR	bkptr;
	register INT tmp;

	if (pid && (bpstate != BPIN) )
	for(bkptr = bkpthead; bkptr; bkptr = bkptr->nxtbkpt)
	if (bkptr->flag)
	{
		tmp = ptrace(RIUSER, pid, bkptr->loc, 0);
		if( ( tmp & 0xFFFF0000 ) != BKPTI )
			bkptr->ins = tmp;
		ptrace(WIUSER, pid, bkptr->loc, BKPTI);
		if (errno)
		{
			prints("cannot set breakpoint: ");
			psymoff(bkptr->loc, ISYM, "\n");
		}
	}
	bpstate = BPIN;
}

bpwait()
{
register ADDR w;
ADDR stat;

	signal(SIGINT, 1);
	while(((w = wait(&stat))!=pid) && ( w != -1 ));
	signal(SIGINT,sigint);
	ioctl(0, TIOCGETP, &subtty);
	ioctl(0, TIOCGETC, &subtch);
	ioctl(0, TIOCSETP, &adbtty);
	ioctl(0, TIOCSETC, &adbtch);
	if( w == -1 )
	{
	    pid=0;
	    error(BADWAIT);
	}
	else if( (stat & 0177) != 0177 )
	{
	    pid = 0;
	    if( ( signum = stat&0177) != 0 )
	    {
		printf( signals[signum] );
	    }
	    if( stat&0200 )
	    {
		prints(" - core dumped");
		close(fcor);
		corfil = "core";
		setcor();
	    }
	    error(ENDPCS);
	}
	else
	{
	    signum = ( stat>>8 ) & 0377;
#ifdef s32
	    if ((signum != SIGTRAP) && (signum != SIGIOT) && (signum != SIGCHLD))
#else s32
	    if ((signum != SIGTRAP) && (signum != SIGIOT))
#endif s32
		prints(signals[signum]);
	    else signum = 0;
	    flushbuf();
	}
}

readregs()
{
	register REGPTR	regptr;

	for(regptr = reglist; regptr <= &reglist[ps]; regptr++)
		regptr->rval = getreg(pid, regptr->roffs);

	userpc = (ADDR) reglist[pc].rval;
}
