15507Slinton /* Copyright (c) 1982 Regents of the University of California */
25507Slinton 
3*6072Slinton static char sccsid[] = "@(#)ptrace.c 1.3 03/08/82";
45507Slinton 
55507Slinton /*
65507Slinton  * routines for tracing the execution of a process
75507Slinton  *
85507Slinton  * The system call "ptrace" does all the work, these
95507Slinton  * routines just try to interface easily to it.
105507Slinton  */
115507Slinton 
125507Slinton #include "defs.h"
135507Slinton #include <signal.h>
145507Slinton #include <sys/param.h>
155507Slinton #include <sys/reg.h>
165507Slinton #include "process.h"
175507Slinton #include "object.h"
185507Slinton #include "process.rep"
195507Slinton 
20*6072Slinton #   if (isvaxpx)
21*6072Slinton #       include "pxinfo.h"
22*6072Slinton #   endif
235507Slinton 
245507Slinton /*
255507Slinton  * This magic macro enables us to look at the process' registers
265507Slinton  * in its user structure.  Very gross.
275507Slinton  */
285507Slinton 
29*6072Slinton #define regloc(reg)     (ctob(UPAGES) + ( sizeof(int) * (reg) ))
305507Slinton 
31*6072Slinton #define WMASK           (~(sizeof(WORD) - 1))
32*6072Slinton #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE))
335507Slinton 
34*6072Slinton #define FIRSTSIG        SIGINT
35*6072Slinton #define LASTSIG         SIGQUIT
36*6072Slinton #define ischild(pid)    ((pid) == 0)
37*6072Slinton #define traceme()       ptrace(0, 0, 0, 0)
38*6072Slinton #define setrep(n)       (1 << ((n)-1))
39*6072Slinton #define istraced(p)     (p->sigset&setrep(p->signo))
405507Slinton 
415507Slinton /*
425507Slinton  * ptrace options (specified in first argument)
435507Slinton  */
445507Slinton 
45*6072Slinton #define UREAD   3       /* read from process's user structure */
46*6072Slinton #define UWRITE  6       /* write to process's user structure */
47*6072Slinton #define IREAD   1       /* read from process's instruction space */
48*6072Slinton #define IWRITE  4       /* write to process's instruction space */
49*6072Slinton #define DREAD   2       /* read from process's data space */
50*6072Slinton #define DWRITE  5       /* write to process's data space */
51*6072Slinton #define CONT    7       /* continue stopped process */
52*6072Slinton #define SSTEP   9       /* continue for approximately one instruction */
53*6072Slinton #define PKILL   8       /* terminate the process */
545507Slinton 
555507Slinton /*
565507Slinton  * Start up a new process by forking and exec-ing the
575507Slinton  * given argument list, returning when the process is loaded
585507Slinton  * and ready to execute.  The PROCESS information (pointed to
595507Slinton  * by the first argument) is appropriately filled.
605507Slinton  *
615507Slinton  * If the given PROCESS structure is associated with an already running
625507Slinton  * process, we terminate it.
635507Slinton  */
645507Slinton 
655507Slinton /* VARARGS2 */
665607Slinton pstart(p, cmd, argv, infile, outfile)
675507Slinton PROCESS *p;
685607Slinton char *cmd;
695507Slinton char **argv;
705507Slinton char *infile;
715507Slinton char *outfile;
725507Slinton {
73*6072Slinton     int status;
74*6072Slinton     FILE *in, *out;
755507Slinton 
76*6072Slinton     if (p->pid != 0) {                  /* child already running? */
77*6072Slinton 	ptrace(PKILL, p->pid, 0, 0);    /* ... kill it! */
78*6072Slinton     }
79*6072Slinton     psigtrace(p, SIGTRAP, TRUE);
80*6072Slinton     if ((p->pid = fork()) == -1) {
81*6072Slinton 	panic("can't fork");
82*6072Slinton     }
83*6072Slinton     if (ischild(p->pid)) {
84*6072Slinton 	traceme();
85*6072Slinton 	if (infile != NIL) {
86*6072Slinton 	    if ((in = fopen(infile, "r")) == NIL) {
87*6072Slinton 		printf("can't read %s\n", infile);
88*6072Slinton 		exit(1);
89*6072Slinton 	    }
90*6072Slinton 	    fswap(0, fileno(in));
915507Slinton 	}
92*6072Slinton 	if (outfile != NIL) {
93*6072Slinton 	    if ((out = fopen(outfile, "w")) == NIL) {
94*6072Slinton 		printf("can't write %s\n", outfile);
95*6072Slinton 		exit(1);
96*6072Slinton 	    }
97*6072Slinton 	    fswap(1, fileno(out));
985507Slinton 	}
99*6072Slinton 	execvp(cmd, argv);
100*6072Slinton 	panic("can't exec %s", argv[0]);
101*6072Slinton     }
102*6072Slinton     pwait(p->pid, &status);
103*6072Slinton     getinfo(p, status);
1045507Slinton }
1055507Slinton 
1065507Slinton /*
1075507Slinton  * Continue a stopped process.  The argument points to a PROCESS structure.
1085507Slinton  * Before the process is restarted it's user area is modified according to
1095507Slinton  * the values in the structure.  When this routine finishes,
1105507Slinton  * the structure has the new values from the process's user area.
1115507Slinton  *
1125507Slinton  * Pcont terminates when the process stops with a signal pending that
1135507Slinton  * is being traced (via psigtrace), or when the process terminates.
1145507Slinton  */
1155507Slinton 
1165507Slinton pcont(p)
1175507Slinton PROCESS *p;
1185507Slinton {
119*6072Slinton     int status;
1205507Slinton 
121*6072Slinton     if (p->pid == 0) {
122*6072Slinton 	error("program not active");
123*6072Slinton     }
124*6072Slinton     do {
125*6072Slinton 	setinfo(p);
126*6072Slinton 	sigs_off();
127*6072Slinton 	if (ptrace(CONT, p->pid, p->pc, p->signo) < 0) {
128*6072Slinton 	    panic("can't continue process");
1295507Slinton 	}
130*6072Slinton 	pwait(p->pid, &status);
131*6072Slinton 	sigs_on();
132*6072Slinton 	getinfo(p, status);
133*6072Slinton     } while (p->status == STOPPED && !istraced(p));
1345507Slinton }
1355507Slinton 
1365507Slinton /*
1375507Slinton  * single step as best ptrace can
1385507Slinton  */
1395507Slinton 
1405507Slinton pstep(p)
1415507Slinton PROCESS *p;
1425507Slinton {
143*6072Slinton     int status;
1445507Slinton 
145*6072Slinton     setinfo(p);
146*6072Slinton     sigs_off();
147*6072Slinton     ptrace(SSTEP, p->pid, p->pc, p->signo);
148*6072Slinton     pwait(p->pid, &status);
149*6072Slinton     sigs_on();
150*6072Slinton     getinfo(p, status);
1515507Slinton }
1525507Slinton 
1535507Slinton /*
1545507Slinton  * Return from execution when the given signal is pending.
1555507Slinton  */
1565507Slinton 
1575507Slinton psigtrace(p, sig, sw)
1585507Slinton PROCESS *p;
1595507Slinton int sig;
1605507Slinton int sw;
1615507Slinton {
162*6072Slinton     if (sw) {
163*6072Slinton 	p->sigset |= setrep(sig);
164*6072Slinton     } else {
165*6072Slinton 	p->sigset &= ~setrep(sig);
166*6072Slinton     }
1675507Slinton }
1685507Slinton 
1695507Slinton /*
1705507Slinton  * Don't catch any signals.
1715507Slinton  * Particularly useful when letting a process finish uninhibited (i.e. px).
1725507Slinton  */
1735507Slinton 
1745507Slinton unsetsigtraces(p)
1755507Slinton PROCESS *p;
1765507Slinton {
177*6072Slinton     p->sigset = 0;
1785507Slinton }
1795507Slinton 
1805507Slinton /*
1815507Slinton  * turn off attention to signals not being caught
1825507Slinton  */
1835507Slinton 
1845507Slinton typedef int INTFUNC();
1855507Slinton 
1865507Slinton LOCAL INTFUNC *sigfunc[NSIG];
1875507Slinton 
1885507Slinton LOCAL sigs_off()
1895507Slinton {
190*6072Slinton     register int i;
1915507Slinton 
192*6072Slinton     for (i = FIRSTSIG; i < LASTSIG; i++) {
193*6072Slinton 	if (i != SIGKILL) {
194*6072Slinton 	    sigfunc[i] = signal(i, SIG_IGN);
1955507Slinton 	}
196*6072Slinton     }
1975507Slinton }
1985507Slinton 
1995507Slinton /*
2005507Slinton  * turn back on attention to signals
2015507Slinton  */
2025507Slinton 
2035507Slinton LOCAL sigs_on()
2045507Slinton {
205*6072Slinton     register int i;
2065507Slinton 
207*6072Slinton     for (i = FIRSTSIG; i < LASTSIG; i++) {
208*6072Slinton 	if (i != SIGKILL) {
209*6072Slinton 	    signal(i, sigfunc[i]);
2105507Slinton 	}
211*6072Slinton     }
2125507Slinton }
2135507Slinton 
2145507Slinton /*
2155507Slinton  * get PROCESS information from process's user area
2165507Slinton  */
2175507Slinton 
2185507Slinton LOCAL int rloc[] ={
219*6072Slinton     R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11,
2205507Slinton };
2215507Slinton 
2225507Slinton LOCAL getinfo(p, status)
2235507Slinton register PROCESS *p;
2245507Slinton register int status;
2255507Slinton {
226*6072Slinton     register int i;
2275507Slinton 
228*6072Slinton     p->signo = (status&0177);
229*6072Slinton     p->exitval = ((status >> 8)&0377);
230*6072Slinton     if (p->signo == STOPPED) {
231*6072Slinton 	p->status = p->signo;
232*6072Slinton 	p->signo = p->exitval;
233*6072Slinton 	p->exitval = 0;
234*6072Slinton     } else {
235*6072Slinton 	p->status = FINISHED;
236*6072Slinton 	return;
237*6072Slinton     }
238*6072Slinton     for (i = 0; i < NREG; i++) {
239*6072Slinton 	p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0);
240*6072Slinton 	p->oreg[i] = p->reg[i];
241*6072Slinton     }
242*6072Slinton     p->fp = p->ofp = ptrace(UREAD, p->pid, regloc(FP), 0);
243*6072Slinton     p->ap = p->oap = ptrace(UREAD, p->pid, regloc(AP), 0);
244*6072Slinton     p->sp = p->osp = ptrace(UREAD, p->pid, regloc(SP), 0);
245*6072Slinton     p->pc = p->opc = ptrace(UREAD, p->pid, regloc(PC), 0);
2465507Slinton }
2475507Slinton 
2485507Slinton /*
2495507Slinton  * set process's user area information from given PROCESS structure
2505507Slinton  */
2515507Slinton 
2525507Slinton LOCAL setinfo(p)
2535507Slinton register PROCESS *p;
2545507Slinton {
255*6072Slinton     register int i;
256*6072Slinton     register int r;
2575507Slinton 
258*6072Slinton     if (istraced(p)) {
259*6072Slinton 	p->signo = 0;
260*6072Slinton     }
261*6072Slinton     for (i = 0; i < NREG; i++) {
262*6072Slinton 	if ((r = p->reg[i]) != p->oreg[i]) {
263*6072Slinton 	    ptrace(UWRITE, p->pid, regloc(rloc[i]), r);
2645507Slinton 	}
265*6072Slinton     }
266*6072Slinton     if ((r = p->fp) != p->ofp) {
267*6072Slinton 	ptrace(UWRITE, p->pid, regloc(FP), r);
268*6072Slinton     }
269*6072Slinton     if ((r = p->sp) != p->osp) {
270*6072Slinton 	ptrace(UWRITE, p->pid, regloc(SP), r);
271*6072Slinton     }
272*6072Slinton     if ((r = p->ap) != p->oap) {
273*6072Slinton 	ptrace(UWRITE, p->pid, regloc(AP), r);
274*6072Slinton     }
275*6072Slinton     if ((r = p->pc) != p->opc) {
276*6072Slinton 	ptrace(UWRITE, p->pid, regloc(PC), r);
277*6072Slinton     }
2785507Slinton }
2795507Slinton 
2805507Slinton /*
2815507Slinton  * Structure for reading and writing by words, but dealing with bytes.
2825507Slinton  */
2835507Slinton 
2845507Slinton typedef union {
285*6072Slinton     WORD pword;
286*6072Slinton     BYTE pbyte[sizeof(WORD)];
2875507Slinton } PWORD;
2885507Slinton 
2895507Slinton /*
2905507Slinton  * Read (write) from (to) the process' address space.
2915507Slinton  * We must deal with ptrace's inability to look anywhere other
2925507Slinton  * than at a word boundary.
2935507Slinton  */
2945507Slinton 
2955507Slinton LOCAL WORD fetch();
2965507Slinton LOCAL store();
2975507Slinton 
2985507Slinton pio(p, op, seg, buff, addr, nbytes)
2995507Slinton PROCESS *p;
3005507Slinton PIO_OP op;
3015507Slinton PIO_SEG seg;
3025507Slinton char *buff;
3035507Slinton ADDRESS addr;
3045507Slinton int nbytes;
3055507Slinton {
306*6072Slinton     register int i;
307*6072Slinton     register ADDRESS newaddr;
308*6072Slinton     register char *cp;
309*6072Slinton     char *bufend;
310*6072Slinton     PWORD w;
311*6072Slinton     ADDRESS wordaddr;
312*6072Slinton     int byteoff;
3135507Slinton 
314*6072Slinton     if (p->status != STOPPED) {
315*6072Slinton 	error("program is not active");
316*6072Slinton     }
317*6072Slinton     cp = buff;
318*6072Slinton     newaddr = addr;
319*6072Slinton     wordaddr = (newaddr&WMASK);
320*6072Slinton     if (wordaddr != newaddr) {
321*6072Slinton 	w.pword = fetch(p, seg, wordaddr);
322*6072Slinton 	for (i = newaddr - wordaddr; i<sizeof(WORD) && nbytes>0; i++) {
323*6072Slinton 	    if (op == PREAD) {
324*6072Slinton 		*cp++ = w.pbyte[i];
325*6072Slinton 	    } else {
326*6072Slinton 		w.pbyte[i] = *cp++;
327*6072Slinton 	    }
328*6072Slinton 	    nbytes--;
3295507Slinton 	}
330*6072Slinton 	if (op == PWRITE) {
331*6072Slinton 	    store(p, seg, wordaddr, w.pword);
3325507Slinton 	}
333*6072Slinton 	newaddr = wordaddr + sizeof(WORD);
334*6072Slinton     }
335*6072Slinton     byteoff = (nbytes&(~WMASK));
336*6072Slinton     nbytes -= byteoff;
337*6072Slinton     bufend = cp + nbytes;
338*6072Slinton     while (cp < bufend) {
339*6072Slinton 	if (op == PREAD) {
340*6072Slinton 	    *((WORD *) cp) = fetch(p, seg, newaddr);
341*6072Slinton 	} else {
342*6072Slinton 	    store(p, seg, newaddr, *((WORD *) cp));
3435507Slinton 	}
344*6072Slinton 	cp += sizeof(WORD);
345*6072Slinton 	newaddr += sizeof(WORD);
346*6072Slinton     }
347*6072Slinton     if (byteoff > 0) {
348*6072Slinton 	w.pword = fetch(p, seg, newaddr);
349*6072Slinton 	for (i = 0; i < byteoff; i++) {
350*6072Slinton 	    if (op == PREAD) {
351*6072Slinton 		*cp++ = w.pbyte[i];
352*6072Slinton 	    } else {
353*6072Slinton 		w.pbyte[i] = *cp++;
354*6072Slinton 	    }
3555507Slinton 	}
356*6072Slinton 	if (op == PWRITE) {
357*6072Slinton 	    store(p, seg, newaddr, w.pword);
358*6072Slinton 	}
359*6072Slinton     }
3605507Slinton }
3615507Slinton 
3625507Slinton /*
3635507Slinton  * Get a word from a process at the given address.
3645507Slinton  * The address is assumed to be on a word boundary.
3655507Slinton  *
3665507Slinton  * We use a simple cache scheme to avoid redundant references to
3675507Slinton  * the instruction space (which is assumed to be pure).  In the
3685507Slinton  * case of px, the "instruction" space lies between ENDOFF and
3695507Slinton  * ENDOFF + objsize.
3705507Slinton  *
3715507Slinton  * It is necessary to use a write-through scheme so that
3725507Slinton  * breakpoints right next to each other don't interfere.
3735507Slinton  */
3745507Slinton 
3755507Slinton LOCAL WORD fetch(p, seg, addr)
3765507Slinton PROCESS *p;
3775507Slinton PIO_SEG seg;
3785507Slinton register int addr;
3795507Slinton {
380*6072Slinton     register CACHEWORD *wp;
381*6072Slinton     register WORD w;
3825507Slinton 
383*6072Slinton     switch (seg) {
384*6072Slinton 	case TEXTSEG:
385*6072Slinton #           if (isvaxpx)
386*6072Slinton 		panic("tried to fetch from px i-space");
387*6072Slinton 		/* NOTREACHED */
388*6072Slinton #           else
389*6072Slinton 		wp = &p->word[cachehash(addr)];
390*6072Slinton 		if (addr == 0 || wp->addr != addr) {
391*6072Slinton 		    w = ptrace(IREAD, p->pid, addr, 0);
392*6072Slinton 		    wp->addr = addr;
393*6072Slinton 		    wp->val = w;
394*6072Slinton 		} else {
395*6072Slinton 		    w = wp->val;
396*6072Slinton 		}
397*6072Slinton 		break;
398*6072Slinton #           endif
3995507Slinton 
400*6072Slinton 	case DATASEG:
401*6072Slinton #           if (isvaxpx)
402*6072Slinton 		if (addr >= ENDOFF && addr < ENDOFF + objsize) {
403*6072Slinton 		    wp = &p->word[cachehash(addr)];
404*6072Slinton 		    if (addr == 0 || wp->addr != addr) {
405*6072Slinton 			w = ptrace(DREAD, p->pid, addr, 0);
406*6072Slinton 			wp->addr = addr;
407*6072Slinton 			wp->val = w;
408*6072Slinton 		    } else {
409*6072Slinton 			w = wp->val;
410*6072Slinton 		    }
411*6072Slinton 		} else {
412*6072Slinton 		    w = ptrace(DREAD, p->pid, addr, 0);
413*6072Slinton 		}
414*6072Slinton #           else
415*6072Slinton 		w = ptrace(DREAD, p->pid, addr, 0);
416*6072Slinton #           endif
417*6072Slinton 	    break;
4185507Slinton 
419*6072Slinton 	default:
420*6072Slinton 	    panic("fetch: bad seg %d", seg);
421*6072Slinton 	    /* NOTREACHED */
422*6072Slinton     }
423*6072Slinton     return(w);
4245507Slinton }
4255507Slinton 
4265507Slinton /*
4275507Slinton  * Put a word into the process' address space at the given address.
4285507Slinton  * The address is assumed to be on a word boundary.
4295507Slinton  */
4305507Slinton 
4315507Slinton LOCAL store(p, seg, addr, data)
4325507Slinton PROCESS *p;
4335507Slinton PIO_SEG seg;
4345507Slinton int addr;
4355507Slinton WORD data;
4365507Slinton {
437*6072Slinton     register CACHEWORD *wp;
4385507Slinton 
439*6072Slinton     switch (seg) {
440*6072Slinton 	case TEXTSEG:
441*6072Slinton 	    wp = &p->word[cachehash(addr)];
442*6072Slinton 	    wp->addr = addr;
443*6072Slinton 	    wp->val = data;
444*6072Slinton 	    ptrace(IWRITE, p->pid, addr, data);
445*6072Slinton 	    break;
4465507Slinton 
447*6072Slinton 	case DATASEG:
448*6072Slinton #           if (isvaxpx)
449*6072Slinton 		if (addr >= ENDOFF && addr < ENDOFF + objsize) {
450*6072Slinton 		    wp = &p->word[cachehash(addr)];
451*6072Slinton 		    wp->addr = addr;
452*6072Slinton 		    wp->val = data;
453*6072Slinton 		}
454*6072Slinton #           endif
455*6072Slinton 	    ptrace(DWRITE, p->pid, addr, data);
456*6072Slinton 	    break;
4575507Slinton 
458*6072Slinton 	default:
459*6072Slinton 	    panic("store: bad seg %d", seg);
460*6072Slinton 	    /*NOTREACHED*/
461*6072Slinton     }
4625507Slinton }
4635507Slinton 
4645507Slinton /*
465*6072Slinton  * Initialize the instruction cache for a process.
466*6072Slinton  * This is particularly necessary after the program has been remade.
467*6072Slinton  */
468*6072Slinton 
469*6072Slinton initcache(process)
470*6072Slinton PROCESS *process;
471*6072Slinton {
472*6072Slinton     register int i;
473*6072Slinton 
474*6072Slinton     for (i = 0; i < CSIZE; i++) {
475*6072Slinton 	process->word[i].addr = 0;
476*6072Slinton     }
477*6072Slinton }
478*6072Slinton 
479*6072Slinton /*
4805507Slinton  * Swap file numbers so as to redirect standard input and output.
4815507Slinton  */
4825507Slinton 
4835507Slinton LOCAL fswap(oldfd, newfd)
4845507Slinton int oldfd;
4855507Slinton int newfd;
4865507Slinton {
487*6072Slinton     if (oldfd != newfd) {
488*6072Slinton 	close(oldfd);
489*6072Slinton 	dup(newfd);
490*6072Slinton 	close(newfd);
491*6072Slinton     }
4925507Slinton }
493