#define DEBUG
/* $Header:runpcs.c 12.0$ */
/* $ACIS:runpcs.c 12.0$ */
/* $Source: /ibm/acis/usr/src/bin/adb_ca/RCS/runpcs.c,v $ */
#ifndef lint
static char *rcsid = "$Header:runpcs.c 12.0$";
#endif

/*
 *
 *      UNIX debugger
 *
 */
#include "defs.h"
extern  MAP     txtmap;
MSG             NOFORK;
MSG             ENDPCS;
MSG             BADWAIT;
CHAR            *lp;
ADDR            sigint;
ADDR            sigqit;
/* breakpoints */
BKPTR           bkpthead;
REGLIST         reglist[];
extern int	NumReglistElements;
CHAR            lastc;
INT             fcor;
INT             fsym;
STRING          errflg;
L_INT           errno;
INT             signo;
INT             sigcode;
L_INT           dot;
STRING          symfil;
INT             wtflag;
INT             pid;
L_INT           expv;
INT             adrflg;
L_INT           loopcnt;

#ifdef PTRACEDEBUG
#define PTRACE(a,b,c,d) DEBUG_ptrace(a,b,c,d,__LINE__,__FILE__)
#include <stdio.h>
int DEBUG_ptrace(a,b,c,d,l,f)
int a, b, *c, d, l;
char *f;
{
if(debug) fprintf(stderr,"ptrace:%d:%s:%d %x %x\n",l,f,a,c,d);
return(ptrace(a,b,c,d));
}
#else
#define PTRACE(a,b,c,d) ptrace(a,b,c,d)
#endif

/* service routines for sub process control */
getsig(sig)
{       return(expr(0) ? expv : sig);
}
ADDR userpc = 1;
runpcs(runmode,execsig)
{
        INT             rc;
        REG BKPTR       bkpt;
        IF adrflg THEN userpc=dot; FI
        printf("%s: running\n", symfil);
        WHILE --loopcnt>=0
        DO
#ifdef DEBUG
                if(debug) printf("\ncontinue %x %d\n",userpc,execsig);
#endif
                IF runmode==SINGLE
                THEN delbp(); /* hardware handles single-stepping */
                ELSE /* continuing from a breakpoint is hard */
                        IF bkpt=scanbkpt(userpc)
                        THEN execbkpt(bkpt,execsig); execsig=0;
                        FI
                        setbp();
                FI
                PTRACE(runmode,pid,userpc,execsig);
                bpwait(); chkerr(); execsig=0; delbp(); readregs();
                IF (signo==0) ANDF (bkpt=scanbkpt(userpc))
                THEN /* stopped by BPT instruction */
                        dot=bkpt->loc;
                        IF bkpt->flag==BKPTEXEC
                        ORF ((bkpt->flag=BKPTEXEC)
                                ANDF bkpt->comm[0]!=EOR
                                ANDF command(bkpt->comm,':')
                                ANDF --bkpt->count)
                        THEN execbkpt(bkpt,execsig); execsig=0; loopcnt++;
                        ELSE bkpt->count=bkpt->initcnt; rc=1;
                        FI
                ELSE execsig=signo; rc=0;
                FI
        OD
        return(rc);
}
#define BPOUT 0
#define BPIN 1
INT bpstate = BPOUT;
endpcs()
{
        REG BKPTR       bkptr;
        IF pid
        THEN PTRACE(EXIT,pid,0,0); pid=0; userpc=1;
             FOR bkptr=bkpthead; bkptr; bkptr=bkptr->nxtbkpt
             DO IF bkptr->flag
                THEN bkptr->flag=BKPTSET;
                FI
             OD
        FI
        bpstate=BPOUT;
}
#ifdef VFORK
nullsig()
{
}
#endif
setup()
{
        close(fsym); fsym = -1;
#ifndef VFORK
        IF (pid = fork()) == 0
#else
        IF (pid = vfork()) == 0
#endif
        THEN PTRACE(SETTRC,0,0,0);
#ifdef VFORK
             signal(SIGTRAP,nullsig);
#endif
             signal(SIGINT,sigint); signal(SIGQUIT,sigqit);
             doexec(); exit(0);
        ELIF pid == -1
        THEN error(NOFORK);
        ELSE bpwait(); readregs(); lp[0]=EOR; lp[1]=0;
             fsym=open(symfil,wtflag);
             IF errflg
             THEN printf("%s: cannot execute\n",symfil);
                  endpcs(); error(0);
             FI
        FI
        bpstate=BPOUT;
}
execbkpt(bkptr,execsig)
BKPTR   bkptr;
{
#ifdef DEBUG
        if(debug) printf("exbkpt: %d\n",bkptr->count);
#endif
        delbp();
        PTRACE(SINGLE,pid,bkptr->loc,execsig);
        bkptr->flag=BKPTSET;
        bpwait(); chkerr(); readregs();
}
doexec()
{
        STRING          argl[MAXARG];
        CHAR            args[LINSIZ];
        STRING          p, *ap, filnam;
        extern STRING environ;
        ap=argl; p=args;
        *ap++=symfil;
        REP     IF rdc()==EOR THEN break; FI
                *ap = p;
                /*
                 * First thing is to look for direction characters
                 * and get filename.  Do not use up the args for filenames.
                 * Then get rid of spaces before next args.
                 */
                IF lastc=='<'
                THEN    REP readchar(); PER lastc==SP ORF lastc==TB DONE
                        filnam = p;
                        WHILE lastc!=EOR ANDF lastc!=SP ANDF lastc!=TB ANDF lastc!='>'
                                DO *p++=lastc; readchar(); OD
                        *p = 0;
                        close(0);
                        IF open(filnam,0)<0
                        THEN    printf("%s: cannot open\n",filnam); _exit(0);
                        FI
                        p = *ap;
                ELIF lastc=='>'
                THEN    REP readchar(); PER lastc==SP ORF lastc==TB DONE
                        filnam = p;
                        WHILE lastc!=EOR ANDF lastc!=SP ANDF lastc!=TB ANDF lastc!='<'
                                DO *p++=lastc; readchar(); OD
                        *p = '\0';
                        close(1);
                        IF creat(filnam,0666)<0
                        THEN    printf("%s: cannot create\n",filnam); _exit(0);
                        FI
                        p = *ap;
                ELSE
                        WHILE lastc!=EOR ANDF lastc!=SP ANDF lastc!=TB ANDF lastc!='>' ANDF lastc!='<'
                                DO *p++=lastc; readchar(); OD
                        *p++ = '\0';
                        ap++;
                FI
        PER lastc!=EOR DONE
        *ap++=0;
        exect(symfil, argl, environ);
        perror(symfil);
}
BKPTR   scanbkpt(adr)
ADDR adr;
{
        REG BKPTR       bkptr;
        FOR bkptr=bkpthead; bkptr; bkptr=bkptr->nxtbkpt
        DO IF bkptr->flag ANDF bkptr->loc==adr
           THEN break;
           FI
        OD
        return(bkptr);
}
delbp()
{
        REG BKPTR       bkptr;
        REG INT         wspace;
 
        IF bpstate!=BPOUT
        THEN FOR bkptr=bkpthead; bkptr; bkptr=bkptr->nxtbkpt DO
                 IF bkptr->flag
                 THEN wspace = (bkptr->loc < txtmap.e1) ? WIUSER : WDUSER;
                      PTRACE( wspace, pid, WORDALIGN(bkptr->loc), bkptr->ins );
                 FI
              OD
              bpstate=BPOUT;
        FI
}
setbp()
{
        REG ADDR        a;
        REG BKPTR       bkptr;
        REG INT         rspace, wspace, s;
 
        IF bpstate!=BPIN
        THEN FOR bkptr=bkpthead; bkptr; bkptr=bkptr->nxtbkpt DO
                 IF bkptr->flag
                 THEN IF bkptr->loc < txtmap.e1
                      THEN rspace = RIUSER;
                           wspace = WIUSER;
                      ELSE rspace = RDUSER;
                           wspace = WDUSER;
                      FI
                      a = WORDALIGN(bkptr->loc);
                      bkptr->ins = PTRACE( rspace, pid, a, 0 );
                      s = 8 * (bkptr->loc - a);
                      PTRACE( wspace, pid, a,
                        (BPT << (16-s)) | (bkptr->ins & (BPMASK << s)) );
                      IF errno
                      THEN prints("cannot set breakpoint: ");
                           psymoff( bkptr->loc, ISYM, "\n" );
                      FI
                 FI
             OD
             bpstate=BPIN;
        FI
}
bpwait()
{
        REG ADDR w;
	int roff;
	static int firsttime = 1;
        ADDR stat;
        signal(SIGINT, 1);
        WHILE (w = wait(&stat))!=pid ANDF w != -1 DONE
        signal(SIGINT,sigint);
        IF w == -1
        THEN pid=0;
             errflg=BADWAIT;
        ELIF (stat & 0177) != 0177
        THEN sigcode = 0;
             IF signo = stat&0177
             THEN sigprint();
             FI
             IF stat&0200
             THEN prints(" - core dumped");
                  close(fcor);
                  setcor();
             FI
             pid=0;
             errflg=ENDPCS;
        ELSE signo = stat>>8;
	     if(firsttime) {
	     	firsttime = 0;
		init_regs();
	     }
	     roff = getRegByName("ucode");
             sigcode = PTRACE(RUREGS, pid, roff, 0);
             IF signo!=SIGTRAP
             THEN sigprint();
             ELSE signo=0;
             FI
             flushbuf();
        FI
}
readregs()
{
        /*get REG values from pcs*/
        REG i;
        FOR i=NumReglistElements; --i>=0;
        DO *(ADDR *)(((ADDR)&u)+reglist[i].roffs) =
                    PTRACE(RUREGS, pid, reglist[i].roffs, 0);
        OD
/* Get some miscellenea from the u area: */
        userpc = User_iar;
	StackBottom = PTRACE(RUREGS, pid, getRegByName("stack"), 0); /* Not yet bottom. */
	if(StackBottom == -1 && errno != 0)
		printf("Bad stacksiz from u area.\n");
	StackBottom = USRSTACK - ctob(StackBottom);	/* Now bottom. */
	DataTop = PTRACE(RUREGS, pid, getRegByName("data"), 0);	/* Not yet top. */
	if(DataTop == -1 && errno != 0)
		printf("Bad data size from u area.\n");
	DataTop = DATABASE + ctob(DataTop);		/* Now top. */

dprintf(("readregs: U_FLOATMASK =%d\n",U_FLOATMASK));
dprintf(("readregs: RUREGS = %d\n",RUREGS));
dprintf(("readregs: Uadjust = %d\n",Uadjust));

	user.u_floatmask=PTRACE(RUREGS, pid, U_FLOATMASK+Uadjust, 0);

dprintf((" readregs: user.u_floatmask = %d\n",user.u_floatmask));

	if(user.u_floatmask == -1 && errno != 0)
		printf("Unable to access user.u_floatmask.\n");
}

/* Initialize the displacement of the contiguous user's registers in
 * the kernel stack */
init_regs() {
    register int i, val;
    register char *regptr;
    int r0_offset;
    char name[512];
    extern char *ar0;
    
    /* Adjust the uarea members of reglist for different uarea sizes */
    /* The roffs fields of these items are !zero */
    for(i=0; reglist[i].roffs; i++) {
	reglist[i].roffs += ((int)(char *)Uadjust);
    }
	    /* get register pointer from uarea */
    if(pid)
	regptr = (char *) ptrace(RUREGS, pid, U_AR0 + Uadjust, 0);
    else
	regptr = ar0;	/* set setup.c */
	    /* calc offset of r0 from base of upages area */
    r0_offset =  (int)(regptr - (ENDOFP1 - ctob(UPAGES)));
    
    /* Set the register offset from the base of the upages area.
     * ICSCS -> MQ are assumed contiguous in the uarea and include R0-r15.
     * There is no need to adjust because these values are via ar0 */
    val = r0_offset - ((int)(char *)sizeof(int));
    setRegByName("icscs", val);	    /* set icscs */

    for(val += sizeof(int), i=0; i < MAXREGNO; i++, val += sizeof(int)) {
	    sprintf(name,"r%d", i);
	    setRegByName(name, val);
    }
    setRegByName("iar", val);
    setRegByName("mq",  val + sizeof(int));
}


adjustUserStruct() {	/* Calculate the uarea adjustment */
    register int nlistVal;
    struct nlist list[] = {{"userSIZE"},{""}};

    nlist("/vmunix", list);
    nlistVal = list[0].n_value;
    if(nlistVal == 0) {
	printf("Warning:did not find userSIZE in /vmunix name list.\n");
	return;
    }
    
    Uadjust =  ADB_USIZE - nlistVal;
    dprintf(("uarea adjustment = %D\n", Uadjust));
}

static
setRegByName(name,val)
register char *name;
int val;
{
	register REGPTR p;
	for(p=reglist; p < &reglist[NumReglistElements]; p++)
	    if(strcmp(p->rname, name) == 0) {
		p->roffs = val;
		return;
	}
	error("setRegByName internal error");
}

