122510Sdist /*
222510Sdist  * Copyright (c) 1980 Regents of the University of California.
322510Sdist  * All rights reserved.  The Berkeley software License Agreement
422510Sdist  * specifies the terms and conditions for redistribution.
522510Sdist  */
610768Slinton 
722510Sdist #ifndef lint
8*30848Smckusick static char sccsid[] = "@(#)ptrace.c	5.2 (Berkeley) 04/07/87";
922510Sdist #endif not lint
105507Slinton 
115507Slinton /*
125507Slinton  * routines for tracing the execution of a process
135507Slinton  *
145507Slinton  * The system call "ptrace" does all the work, these
155507Slinton  * routines just try to interface easily to it.
165507Slinton  */
175507Slinton 
185507Slinton #include "defs.h"
195507Slinton #include <signal.h>
205507Slinton #include <sys/param.h>
2110004Ssam #include <machine/reg.h>
225507Slinton #include "process.h"
235507Slinton #include "object.h"
245507Slinton #include "process.rep"
255507Slinton 
266072Slinton #       include "pxinfo.h"
275507Slinton 
28*30848Smckusick #ifdef mc68000
2910768Slinton #	define U_PAGE 0x2400
3010768Slinton #	define U_AR0  (14*sizeof(int))
3110768Slinton 	LOCAL int ar0val = -1;
3210768Slinton #endif
3310768Slinton 
345507Slinton /*
355507Slinton  * This magic macro enables us to look at the process' registers
365507Slinton  * in its user structure.  Very gross.
375507Slinton  */
385507Slinton 
39*30848Smckusick #if defined(vax) || defined(tahoe)
4010768Slinton #	define regloc(reg)     (ctob(UPAGES) + ( sizeof(int) * (reg) ))
4110768Slinton #else
4210768Slinton #	define regloc(reg)     (ar0val + ( sizeof(int) * (reg) ))
4310768Slinton #endif
445507Slinton 
456072Slinton #define WMASK           (~(sizeof(WORD) - 1))
466072Slinton #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE))
475507Slinton 
486072Slinton #define ischild(pid)    ((pid) == 0)
496072Slinton #define traceme()       ptrace(0, 0, 0, 0)
506072Slinton #define setrep(n)       (1 << ((n)-1))
516072Slinton #define istraced(p)     (p->sigset&setrep(p->signo))
525507Slinton 
535507Slinton /*
545507Slinton  * ptrace options (specified in first argument)
555507Slinton  */
565507Slinton 
576072Slinton #define UREAD   3       /* read from process's user structure */
586072Slinton #define UWRITE  6       /* write to process's user structure */
596072Slinton #define IREAD   1       /* read from process's instruction space */
606072Slinton #define IWRITE  4       /* write to process's instruction space */
616072Slinton #define DREAD   2       /* read from process's data space */
626072Slinton #define DWRITE  5       /* write to process's data space */
636072Slinton #define CONT    7       /* continue stopped process */
646072Slinton #define SSTEP   9       /* continue for approximately one instruction */
656072Slinton #define PKILL   8       /* terminate the process */
665507Slinton 
675507Slinton /*
685507Slinton  * Start up a new process by forking and exec-ing the
695507Slinton  * given argument list, returning when the process is loaded
705507Slinton  * and ready to execute.  The PROCESS information (pointed to
715507Slinton  * by the first argument) is appropriately filled.
725507Slinton  *
735507Slinton  * If the given PROCESS structure is associated with an already running
745507Slinton  * process, we terminate it.
755507Slinton  */
765507Slinton 
775507Slinton /* VARARGS2 */
785607Slinton pstart(p, cmd, argv, infile, outfile)
795507Slinton PROCESS *p;
805607Slinton char *cmd;
815507Slinton char **argv;
825507Slinton char *infile;
835507Slinton char *outfile;
845507Slinton {
856072Slinton     int status;
866072Slinton     FILE *in, *out;
875507Slinton 
886072Slinton     if (p->pid != 0) {                  /* child already running? */
896072Slinton 	ptrace(PKILL, p->pid, 0, 0);    /* ... kill it! */
906072Slinton     }
91*30848Smckusick     INTFP = (ADDRESS)0;
926072Slinton     psigtrace(p, SIGTRAP, TRUE);
936072Slinton     if ((p->pid = fork()) == -1) {
946072Slinton 	panic("can't fork");
956072Slinton     }
966072Slinton     if (ischild(p->pid)) {
976072Slinton 	traceme();
986072Slinton 	if (infile != NIL) {
996072Slinton 	    if ((in = fopen(infile, "r")) == NIL) {
1006072Slinton 		printf("can't read %s\n", infile);
1016072Slinton 		exit(1);
1026072Slinton 	    }
1036072Slinton 	    fswap(0, fileno(in));
1045507Slinton 	}
1056072Slinton 	if (outfile != NIL) {
1066072Slinton 	    if ((out = fopen(outfile, "w")) == NIL) {
1076072Slinton 		printf("can't write %s\n", outfile);
1086072Slinton 		exit(1);
1096072Slinton 	    }
1106072Slinton 	    fswap(1, fileno(out));
1115507Slinton 	}
1126072Slinton 	execvp(cmd, argv);
1136072Slinton 	panic("can't exec %s", argv[0]);
1146072Slinton     }
1156072Slinton     pwait(p->pid, &status);
1166072Slinton     getinfo(p, status);
1175507Slinton }
1185507Slinton 
1195507Slinton /*
1205507Slinton  * Continue a stopped process.  The argument points to a PROCESS structure.
1215507Slinton  * Before the process is restarted it's user area is modified according to
1225507Slinton  * the values in the structure.  When this routine finishes,
1235507Slinton  * the structure has the new values from the process's user area.
1245507Slinton  *
1255507Slinton  * Pcont terminates when the process stops with a signal pending that
1265507Slinton  * is being traced (via psigtrace), or when the process terminates.
1275507Slinton  */
1285507Slinton 
1295507Slinton pcont(p)
1305507Slinton PROCESS *p;
1315507Slinton {
1326072Slinton     int status;
1335507Slinton 
1346072Slinton     if (p->pid == 0) {
1356072Slinton 	error("program not active");
1366072Slinton     }
1376072Slinton     do {
1386072Slinton 	setinfo(p);
1396072Slinton 	sigs_off();
1406072Slinton 	if (ptrace(CONT, p->pid, p->pc, p->signo) < 0) {
1416072Slinton 	    panic("can't continue process");
1425507Slinton 	}
1436072Slinton 	pwait(p->pid, &status);
1446072Slinton 	sigs_on();
1456072Slinton 	getinfo(p, status);
1466072Slinton     } while (p->status == STOPPED && !istraced(p));
1475507Slinton }
1485507Slinton 
1495507Slinton /*
1505507Slinton  * single step as best ptrace can
1515507Slinton  */
1525507Slinton 
1535507Slinton pstep(p)
1545507Slinton PROCESS *p;
1555507Slinton {
1566072Slinton     int status;
1575507Slinton 
1586072Slinton     setinfo(p);
1596072Slinton     sigs_off();
1606072Slinton     ptrace(SSTEP, p->pid, p->pc, p->signo);
1616072Slinton     pwait(p->pid, &status);
1626072Slinton     sigs_on();
1636072Slinton     getinfo(p, status);
1645507Slinton }
1655507Slinton 
1665507Slinton /*
1675507Slinton  * Return from execution when the given signal is pending.
1685507Slinton  */
1695507Slinton 
1705507Slinton psigtrace(p, sig, sw)
1715507Slinton PROCESS *p;
1725507Slinton int sig;
1735507Slinton int sw;
1745507Slinton {
1756072Slinton     if (sw) {
1766072Slinton 	p->sigset |= setrep(sig);
1776072Slinton     } else {
1786072Slinton 	p->sigset &= ~setrep(sig);
1796072Slinton     }
1805507Slinton }
1815507Slinton 
1825507Slinton /*
1835507Slinton  * Don't catch any signals.
1845507Slinton  * Particularly useful when letting a process finish uninhibited (i.e. px).
1855507Slinton  */
1865507Slinton 
1875507Slinton unsetsigtraces(p)
1885507Slinton PROCESS *p;
1895507Slinton {
1906072Slinton     p->sigset = 0;
1915507Slinton }
1925507Slinton 
1935507Slinton /*
1945507Slinton  * turn off attention to signals not being caught
1955507Slinton  */
1965507Slinton 
1975507Slinton typedef int INTFUNC();
1985507Slinton 
199*30848Smckusick LOCAL INTFUNC *onintr, *onquit;
2005507Slinton 
2015507Slinton LOCAL sigs_off()
2025507Slinton {
203*30848Smckusick     onintr = signal(SIGINT, SIG_IGN);
204*30848Smckusick     onquit = signal(SIGQUIT, SIG_IGN);
2055507Slinton }
2065507Slinton 
2075507Slinton /*
2085507Slinton  * turn back on attention to signals
2095507Slinton  */
2105507Slinton 
2115507Slinton LOCAL sigs_on()
2125507Slinton {
213*30848Smckusick     (void) signal(SIGINT, onintr);
214*30848Smckusick     (void) signal(SIGQUIT, onquit);
2155507Slinton }
2165507Slinton 
2175507Slinton /*
2185507Slinton  * get PROCESS information from process's user area
2195507Slinton  */
2205507Slinton 
22110768Slinton #if vax
22210768Slinton     LOCAL int rloc[] ={
22310768Slinton 	R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11,
22410768Slinton     };
225*30848Smckusick #endif
226*30848Smckusick #if tahoe
22710768Slinton     LOCAL int rloc[] ={
228*30848Smckusick 	R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12,
229*30848Smckusick     };
230*30848Smckusick #endif
231*30848Smckusick #if mc68000
232*30848Smckusick     LOCAL int rloc[] ={
23310768Slinton 	R0, R1, R2, R3, R4, R5, R6, R7, AR0, AR1, AR2, AR3, AR4, AR5,
23410768Slinton     };
23510768Slinton #endif
2365507Slinton 
2375507Slinton LOCAL getinfo(p, status)
2385507Slinton register PROCESS *p;
2395507Slinton register int status;
2405507Slinton {
2416072Slinton     register int i;
2425507Slinton 
2436072Slinton     p->signo = (status&0177);
2446072Slinton     p->exitval = ((status >> 8)&0377);
2456072Slinton     if (p->signo == STOPPED) {
2466072Slinton 	p->status = p->signo;
2476072Slinton 	p->signo = p->exitval;
2486072Slinton 	p->exitval = 0;
2496072Slinton     } else {
2506072Slinton 	p->status = FINISHED;
2516072Slinton 	return;
2526072Slinton     }
253*30848Smckusick #if !defined(vax) && !defined(tahoe)
25410768Slinton     if (ar0val < 0){
25510768Slinton 	ar0val = ptrace(UREAD, p->pid, U_AR0, 0);
25610768Slinton 	ar0val -= U_PAGE;
25710768Slinton     }
25810768Slinton #endif
2596072Slinton     for (i = 0; i < NREG; i++) {
2606072Slinton 	p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0);
2616072Slinton 	p->oreg[i] = p->reg[i];
2626072Slinton     }
263*30848Smckusick #if defined(vax) || defined(tahoe)
2646072Slinton     p->fp = p->ofp = ptrace(UREAD, p->pid, regloc(FP), 0);
2656072Slinton     p->sp = p->osp = ptrace(UREAD, p->pid, regloc(SP), 0);
2666072Slinton     p->pc = p->opc = ptrace(UREAD, p->pid, regloc(PC), 0);
267*30848Smckusick #endif
268*30848Smckusick #ifdef vax
269*30848Smckusick     p->ap = p->oap = ptrace(UREAD, p->pid, regloc(AP), 0);
270*30848Smckusick #endif
271*30848Smckusick #ifdef mc68000
27210768Slinton     p->fp = p->ofp = ptrace(UREAD, p->pid, regloc(AR6), 0);
27310768Slinton     p->ap = p->oap = p->fp;
27410768Slinton     p->sp = p->osp = ptrace(UREAD, p->pid, regloc(SP), 0);
27510768Slinton     p->pc = p->opc = ptrace(UREAD, p->pid, regloc(PC), 0);
27610768Slinton #endif
2775507Slinton }
2785507Slinton 
2795507Slinton /*
2805507Slinton  * set process's user area information from given PROCESS structure
2815507Slinton  */
2825507Slinton 
2835507Slinton LOCAL setinfo(p)
2845507Slinton register PROCESS *p;
2855507Slinton {
2866072Slinton     register int i;
2876072Slinton     register int r;
2885507Slinton 
2896072Slinton     if (istraced(p)) {
2906072Slinton 	p->signo = 0;
2916072Slinton     }
2926072Slinton     for (i = 0; i < NREG; i++) {
2936072Slinton 	if ((r = p->reg[i]) != p->oreg[i]) {
2946072Slinton 	    ptrace(UWRITE, p->pid, regloc(rloc[i]), r);
2955507Slinton 	}
2966072Slinton     }
297*30848Smckusick #if vax || tahoe
2986072Slinton     if ((r = p->fp) != p->ofp) {
2996072Slinton 	ptrace(UWRITE, p->pid, regloc(FP), r);
3006072Slinton     }
301*30848Smckusick #endif
302*30848Smckusick #if vax
3036072Slinton     if ((r = p->ap) != p->oap) {
3046072Slinton 	ptrace(UWRITE, p->pid, regloc(AP), r);
3056072Slinton     }
306*30848Smckusick #endif
307*30848Smckusick #if mc68000
30810768Slinton     if ((r = p->fp) != p->ofp) {
30910768Slinton 	ptrace(UWRITE, p->pid, regloc(AR6), r);
31010768Slinton     }
311*30848Smckusick #endif
31210768Slinton     if ((r = p->sp) != p->osp) {
31310768Slinton 	ptrace(UWRITE, p->pid, regloc(SP), r);
31410768Slinton     }
3156072Slinton     if ((r = p->pc) != p->opc) {
3166072Slinton 	ptrace(UWRITE, p->pid, regloc(PC), r);
3176072Slinton     }
3185507Slinton }
3195507Slinton 
3205507Slinton /*
3215507Slinton  * Structure for reading and writing by words, but dealing with bytes.
3225507Slinton  */
3235507Slinton 
3245507Slinton typedef union {
3256072Slinton     WORD pword;
3266072Slinton     BYTE pbyte[sizeof(WORD)];
3275507Slinton } PWORD;
3285507Slinton 
3295507Slinton /*
3305507Slinton  * Read (write) from (to) the process' address space.
3315507Slinton  * We must deal with ptrace's inability to look anywhere other
3325507Slinton  * than at a word boundary.
3335507Slinton  */
3345507Slinton 
3355507Slinton LOCAL WORD fetch();
3365507Slinton LOCAL store();
3375507Slinton 
3385507Slinton pio(p, op, seg, buff, addr, nbytes)
3395507Slinton PROCESS *p;
3405507Slinton PIO_OP op;
3415507Slinton PIO_SEG seg;
3425507Slinton char *buff;
3435507Slinton ADDRESS addr;
3445507Slinton int nbytes;
3455507Slinton {
346*30848Smckusick     register int i, k;
3476072Slinton     register ADDRESS newaddr;
3486072Slinton     register char *cp;
3496072Slinton     char *bufend;
3506072Slinton     PWORD w;
3516072Slinton     ADDRESS wordaddr;
3526072Slinton     int byteoff;
3535507Slinton 
3546072Slinton     if (p->status != STOPPED) {
3556072Slinton 	error("program is not active");
3566072Slinton     }
3576072Slinton     cp = buff;
3586072Slinton     newaddr = addr;
3596072Slinton     wordaddr = (newaddr&WMASK);
3606072Slinton     if (wordaddr != newaddr) {
3616072Slinton 	w.pword = fetch(p, seg, wordaddr);
3626072Slinton 	for (i = newaddr - wordaddr; i<sizeof(WORD) && nbytes>0; i++) {
3636072Slinton 	    if (op == PREAD) {
3646072Slinton 		*cp++ = w.pbyte[i];
3656072Slinton 	    } else {
3666072Slinton 		w.pbyte[i] = *cp++;
3676072Slinton 	    }
3686072Slinton 	    nbytes--;
3695507Slinton 	}
3706072Slinton 	if (op == PWRITE) {
3716072Slinton 	    store(p, seg, wordaddr, w.pword);
3725507Slinton 	}
3736072Slinton 	newaddr = wordaddr + sizeof(WORD);
3746072Slinton     }
3756072Slinton     byteoff = (nbytes&(~WMASK));
3766072Slinton     nbytes -= byteoff;
3776072Slinton     bufend = cp + nbytes;
3786072Slinton     while (cp < bufend) {
3796072Slinton 	if (op == PREAD) {
380*30848Smckusick 	    w.pword = fetch(p, seg, newaddr);
381*30848Smckusick 	    for (k = 0; k < sizeof(WORD); k++) {
382*30848Smckusick 		*cp++ = w.pbyte[k];
383*30848Smckusick 	    }
3846072Slinton 	} else {
385*30848Smckusick 	    for (k = 0; k < sizeof(WORD); k++) {
386*30848Smckusick 		w.pbyte[k] = *cp++;
387*30848Smckusick 	    }
388*30848Smckusick 	    store(p, seg, newaddr, w.pword);
3895507Slinton 	}
3906072Slinton 	newaddr += sizeof(WORD);
3916072Slinton     }
3926072Slinton     if (byteoff > 0) {
3936072Slinton 	w.pword = fetch(p, seg, newaddr);
3946072Slinton 	for (i = 0; i < byteoff; i++) {
3956072Slinton 	    if (op == PREAD) {
3966072Slinton 		*cp++ = w.pbyte[i];
3976072Slinton 	    } else {
3986072Slinton 		w.pbyte[i] = *cp++;
3996072Slinton 	    }
4005507Slinton 	}
4016072Slinton 	if (op == PWRITE) {
4026072Slinton 	    store(p, seg, newaddr, w.pword);
4036072Slinton 	}
4046072Slinton     }
4055507Slinton }
4065507Slinton 
4075507Slinton /*
4085507Slinton  * Get a word from a process at the given address.
4095507Slinton  * The address is assumed to be on a word boundary.
4105507Slinton  *
4115507Slinton  * We use a simple cache scheme to avoid redundant references to
4125507Slinton  * the instruction space (which is assumed to be pure).  In the
4135507Slinton  * case of px, the "instruction" space lies between ENDOFF and
4145507Slinton  * ENDOFF + objsize.
4155507Slinton  *
4165507Slinton  * It is necessary to use a write-through scheme so that
4175507Slinton  * breakpoints right next to each other don't interfere.
4185507Slinton  */
4195507Slinton 
4205507Slinton LOCAL WORD fetch(p, seg, addr)
4215507Slinton PROCESS *p;
4225507Slinton PIO_SEG seg;
4235507Slinton register int addr;
4245507Slinton {
4256072Slinton     register CACHEWORD *wp;
4266072Slinton     register WORD w;
4275507Slinton 
4286072Slinton     switch (seg) {
4296072Slinton 	case TEXTSEG:
430*30848Smckusick 	    panic("tried to fetch from px i-space");
431*30848Smckusick 	    /* NOTREACHED */
432*30848Smckusick 
433*30848Smckusick 	case DATASEG:
434*30848Smckusick 	    if (addr >= ENDOFF && addr < ENDOFF + objsize) {
4356072Slinton 		wp = &p->word[cachehash(addr)];
4366072Slinton 		if (addr == 0 || wp->addr != addr) {
437*30848Smckusick 		    w = ptrace(DREAD, p->pid, addr, 0);
4386072Slinton 		    wp->addr = addr;
4396072Slinton 		    wp->val = w;
4406072Slinton 		} else {
4416072Slinton 		    w = wp->val;
4426072Slinton 		}
443*30848Smckusick 	    } else {
4446072Slinton 		w = ptrace(DREAD, p->pid, addr, 0);
445*30848Smckusick 	    }
4466072Slinton 	    break;
4475507Slinton 
4486072Slinton 	default:
4496072Slinton 	    panic("fetch: bad seg %d", seg);
4506072Slinton 	    /* NOTREACHED */
4516072Slinton     }
4526072Slinton     return(w);
4535507Slinton }
4545507Slinton 
4555507Slinton /*
4565507Slinton  * Put a word into the process' address space at the given address.
4575507Slinton  * The address is assumed to be on a word boundary.
4585507Slinton  */
4595507Slinton 
4605507Slinton LOCAL store(p, seg, addr, data)
4615507Slinton PROCESS *p;
4625507Slinton PIO_SEG seg;
4635507Slinton int addr;
4645507Slinton WORD data;
4655507Slinton {
4666072Slinton     register CACHEWORD *wp;
4675507Slinton 
4686072Slinton     switch (seg) {
4696072Slinton 	case TEXTSEG:
4706072Slinton 	    wp = &p->word[cachehash(addr)];
4716072Slinton 	    wp->addr = addr;
4726072Slinton 	    wp->val = data;
4736072Slinton 	    ptrace(IWRITE, p->pid, addr, data);
4746072Slinton 	    break;
4755507Slinton 
4766072Slinton 	case DATASEG:
477*30848Smckusick 	    if (addr >= ENDOFF && addr < ENDOFF + objsize) {
478*30848Smckusick 		wp = &p->word[cachehash(addr)];
479*30848Smckusick 		wp->addr = addr;
480*30848Smckusick 		wp->val = data;
481*30848Smckusick 	    }
4826072Slinton 	    ptrace(DWRITE, p->pid, addr, data);
4836072Slinton 	    break;
4845507Slinton 
4856072Slinton 	default:
4866072Slinton 	    panic("store: bad seg %d", seg);
4876072Slinton 	    /*NOTREACHED*/
4886072Slinton     }
4895507Slinton }
4905507Slinton 
4915507Slinton /*
4926072Slinton  * Initialize the instruction cache for a process.
4936072Slinton  * This is particularly necessary after the program has been remade.
4946072Slinton  */
4956072Slinton 
4966072Slinton initcache(process)
4976072Slinton PROCESS *process;
4986072Slinton {
4996072Slinton     register int i;
5006072Slinton 
5016072Slinton     for (i = 0; i < CSIZE; i++) {
5026072Slinton 	process->word[i].addr = 0;
5036072Slinton     }
5046072Slinton }
5056072Slinton 
5066072Slinton /*
5075507Slinton  * Swap file numbers so as to redirect standard input and output.
5085507Slinton  */
5095507Slinton 
5105507Slinton LOCAL fswap(oldfd, newfd)
5115507Slinton int oldfd;
5125507Slinton int newfd;
5135507Slinton {
5146072Slinton     if (oldfd != newfd) {
5156072Slinton 	close(oldfd);
5166072Slinton 	dup(newfd);
5176072Slinton 	close(newfd);
5186072Slinton     }
5195507Slinton }
520*30848Smckusick 
521*30848Smckusick #ifdef tahoe
522*30848Smckusick BOOLEAN didret;
523*30848Smckusick 
524*30848Smckusick void
525*30848Smckusick chkret(p, status)
526*30848Smckusick PROCESS *p;
527*30848Smckusick int status;
528*30848Smckusick {
529*30848Smckusick 	if (((status == (SIGILL << 8) | STOPPED) ||
530*30848Smckusick 	    (status == (SIGTRAP << 8) | STOPPED))) {
531*30848Smckusick 		didret = FALSE;
532*30848Smckusick 	} else {
533*30848Smckusick 		didret = TRUE;
534*30848Smckusick 	}
535*30848Smckusick }
536*30848Smckusick 
537*30848Smckusick void
538*30848Smckusick doret(p)
539*30848Smckusick PROCESS *p;
540*30848Smckusick {
541*30848Smckusick 	register count = 0;
542*30848Smckusick 
543*30848Smckusick 	if (!didret) {
544*30848Smckusick 	    do {
545*30848Smckusick 		if (++count > 5) {
546*30848Smckusick 		    panic("px would not return to interpreter");
547*30848Smckusick 		}
548*30848Smckusick 		p->pc = RETLOC;
549*30848Smckusick 		pstep(p);
550*30848Smckusick 	    } while(INTFP && p->fp != INTFP);
551*30848Smckusick 	    didret = TRUE;
552*30848Smckusick 	}
553*30848Smckusick }
554*30848Smckusick #endif
555