1*5507Slinton /* Copyright (c) 1982 Regents of the University of California */
2*5507Slinton 
3*5507Slinton static char sccsid[] = "@(#)ptrace.c 1.1 01/18/82";
4*5507Slinton 
5*5507Slinton /*
6*5507Slinton  * routines for tracing the execution of a process
7*5507Slinton  *
8*5507Slinton  * The system call "ptrace" does all the work, these
9*5507Slinton  * routines just try to interface easily to it.
10*5507Slinton  */
11*5507Slinton 
12*5507Slinton #include "defs.h"
13*5507Slinton #include <signal.h>
14*5507Slinton #include <sys/param.h>
15*5507Slinton #include <sys/reg.h>
16*5507Slinton #include "process.h"
17*5507Slinton #include "object.h"
18*5507Slinton #include "process.rep"
19*5507Slinton 
20*5507Slinton #	if (isvaxpx)
21*5507Slinton #		include "pxinfo.h"
22*5507Slinton #	endif
23*5507Slinton 
24*5507Slinton /*
25*5507Slinton  * This magic macro enables us to look at the process' registers
26*5507Slinton  * in its user structure.  Very gross.
27*5507Slinton  */
28*5507Slinton 
29*5507Slinton #define regloc(reg)		(ctob(UPAGES) + ( sizeof(int) * (reg) ))
30*5507Slinton 
31*5507Slinton #define WMASK			(~(sizeof(WORD) - 1))
32*5507Slinton #define cachehash(addr)	((unsigned) ((addr >> 2) % CSIZE))
33*5507Slinton 
34*5507Slinton #define FIRSTSIG		SIGINT
35*5507Slinton #define LASTSIG			SIGQUIT
36*5507Slinton #define ischild(pid)	((pid) == 0)
37*5507Slinton #define traceme()		ptrace(0, 0, 0, 0)
38*5507Slinton #define setrep(n)		(1 << ((n)-1))
39*5507Slinton #define istraced(p)		(p->sigset&setrep(p->signo))
40*5507Slinton 
41*5507Slinton /*
42*5507Slinton  * ptrace options (specified in first argument)
43*5507Slinton  */
44*5507Slinton 
45*5507Slinton #define UREAD	3		/* read from process's user structure */
46*5507Slinton #define UWRITE	6		/* write to process's user structure */
47*5507Slinton #define IREAD	1		/* read from process's instruction space */
48*5507Slinton #define IWRITE	4		/* write to process's instruction space */
49*5507Slinton #define DREAD	2		/* read from process's data space */
50*5507Slinton #define DWRITE	5		/* write to process's data space */
51*5507Slinton #define CONT	7		/* continue stopped process */
52*5507Slinton #define SSTEP	9		/* continue for approximately one instruction */
53*5507Slinton #define PKILL	8		/* terminate the process */
54*5507Slinton 
55*5507Slinton /*
56*5507Slinton  * Start up a new process by forking and exec-ing the
57*5507Slinton  * given argument list, returning when the process is loaded
58*5507Slinton  * and ready to execute.  The PROCESS information (pointed to
59*5507Slinton  * by the first argument) is appropriately filled.
60*5507Slinton  *
61*5507Slinton  * If the given PROCESS structure is associated with an already running
62*5507Slinton  * process, we terminate it.
63*5507Slinton  */
64*5507Slinton 
65*5507Slinton /* VARARGS2 */
66*5507Slinton pstart(p, argv, infile, outfile)
67*5507Slinton PROCESS *p;
68*5507Slinton char **argv;
69*5507Slinton char *infile;
70*5507Slinton char *outfile;
71*5507Slinton {
72*5507Slinton 	int status;
73*5507Slinton 	FILE *in, *out;
74*5507Slinton 
75*5507Slinton 	if (p->pid != 0) {					/* child already running? */
76*5507Slinton 		ptrace(PKILL, p->pid, 0, 0);	/* ... kill it! */
77*5507Slinton 	}
78*5507Slinton 	psigtrace(p, SIGTRAP, TRUE);
79*5507Slinton 	if ((p->pid = fork()) == -1) {
80*5507Slinton 		panic("can't fork");
81*5507Slinton 	}
82*5507Slinton 	if (ischild(p->pid)) {
83*5507Slinton 		traceme();
84*5507Slinton 		if (infile != NIL) {
85*5507Slinton 			if ((in = fopen(infile, "r")) == NIL) {
86*5507Slinton 				printf("can't read %s\n", infile);
87*5507Slinton 				exit(1);
88*5507Slinton 			}
89*5507Slinton 			fswap(0, fileno(in));
90*5507Slinton 		}
91*5507Slinton 		if (outfile != NIL) {
92*5507Slinton 			if ((out = fopen(outfile, "w")) == NIL) {
93*5507Slinton 				printf("can't write %s\n", outfile);
94*5507Slinton 				exit(1);
95*5507Slinton 			}
96*5507Slinton 			fswap(1, fileno(out));
97*5507Slinton 		}
98*5507Slinton 		execvp(argv[0], argv);
99*5507Slinton 		panic("can't exec %s", argv[0]);
100*5507Slinton 	}
101*5507Slinton 	pwait(p->pid, &status);
102*5507Slinton 	getinfo(p, status);
103*5507Slinton 	if (p->status != STOPPED) {
104*5507Slinton 		error("program could not begin execution");
105*5507Slinton 	}
106*5507Slinton }
107*5507Slinton 
108*5507Slinton /*
109*5507Slinton  * Continue a stopped process.  The argument points to a PROCESS structure.
110*5507Slinton  * Before the process is restarted it's user area is modified according to
111*5507Slinton  * the values in the structure.  When this routine finishes,
112*5507Slinton  * the structure has the new values from the process's user area.
113*5507Slinton  *
114*5507Slinton  * Pcont terminates when the process stops with a signal pending that
115*5507Slinton  * is being traced (via psigtrace), or when the process terminates.
116*5507Slinton  */
117*5507Slinton 
118*5507Slinton pcont(p)
119*5507Slinton PROCESS *p;
120*5507Slinton {
121*5507Slinton 	int status;
122*5507Slinton 
123*5507Slinton 	if (p->pid == 0) {
124*5507Slinton 		error("program not active");
125*5507Slinton 	}
126*5507Slinton 	do {
127*5507Slinton 		setinfo(p);
128*5507Slinton 		sigs_off();
129*5507Slinton 		if (ptrace(CONT, p->pid, p->pc, p->signo) < 0) {
130*5507Slinton 			panic("can't continue process");
131*5507Slinton 		}
132*5507Slinton 		pwait(p->pid, &status);
133*5507Slinton 		sigs_on();
134*5507Slinton 		getinfo(p, status);
135*5507Slinton 	} while (p->status == STOPPED && !istraced(p));
136*5507Slinton }
137*5507Slinton 
138*5507Slinton /*
139*5507Slinton  * single step as best ptrace can
140*5507Slinton  */
141*5507Slinton 
142*5507Slinton pstep(p)
143*5507Slinton PROCESS *p;
144*5507Slinton {
145*5507Slinton 	int status;
146*5507Slinton 
147*5507Slinton 	setinfo(p);
148*5507Slinton 	sigs_off();
149*5507Slinton 	ptrace(SSTEP, p->pid, p->pc, p->signo);
150*5507Slinton 	pwait(p->pid, &status);
151*5507Slinton 	sigs_on();
152*5507Slinton 	getinfo(p, status);
153*5507Slinton }
154*5507Slinton 
155*5507Slinton /*
156*5507Slinton  * Return from execution when the given signal is pending.
157*5507Slinton  */
158*5507Slinton 
159*5507Slinton psigtrace(p, sig, sw)
160*5507Slinton PROCESS *p;
161*5507Slinton int sig;
162*5507Slinton int sw;
163*5507Slinton {
164*5507Slinton 	if (sw) {
165*5507Slinton 		p->sigset |= setrep(sig);
166*5507Slinton 	} else {
167*5507Slinton 		p->sigset &= ~setrep(sig);
168*5507Slinton 	}
169*5507Slinton }
170*5507Slinton 
171*5507Slinton /*
172*5507Slinton  * Don't catch any signals.
173*5507Slinton  * Particularly useful when letting a process finish uninhibited (i.e. px).
174*5507Slinton  */
175*5507Slinton 
176*5507Slinton unsetsigtraces(p)
177*5507Slinton PROCESS *p;
178*5507Slinton {
179*5507Slinton 	p->sigset = 0;
180*5507Slinton }
181*5507Slinton 
182*5507Slinton /*
183*5507Slinton  * turn off attention to signals not being caught
184*5507Slinton  */
185*5507Slinton 
186*5507Slinton typedef int INTFUNC();
187*5507Slinton 
188*5507Slinton LOCAL INTFUNC *sigfunc[NSIG];
189*5507Slinton 
190*5507Slinton LOCAL sigs_off()
191*5507Slinton {
192*5507Slinton 	register int i;
193*5507Slinton 
194*5507Slinton 	for (i = FIRSTSIG; i < LASTSIG; i++) {
195*5507Slinton 		if (i != SIGKILL) {
196*5507Slinton 			sigfunc[i] = signal(i, SIG_IGN);
197*5507Slinton 		}
198*5507Slinton 	}
199*5507Slinton }
200*5507Slinton 
201*5507Slinton /*
202*5507Slinton  * turn back on attention to signals
203*5507Slinton  */
204*5507Slinton 
205*5507Slinton LOCAL sigs_on()
206*5507Slinton {
207*5507Slinton 	register int i;
208*5507Slinton 
209*5507Slinton 	for (i = FIRSTSIG; i < LASTSIG; i++) {
210*5507Slinton 		if (i != SIGKILL) {
211*5507Slinton 			signal(i, sigfunc[i]);
212*5507Slinton 		}
213*5507Slinton 	}
214*5507Slinton }
215*5507Slinton 
216*5507Slinton /*
217*5507Slinton  * get PROCESS information from process's user area
218*5507Slinton  */
219*5507Slinton 
220*5507Slinton LOCAL int rloc[] ={
221*5507Slinton 	R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11,
222*5507Slinton };
223*5507Slinton 
224*5507Slinton LOCAL getinfo(p, status)
225*5507Slinton register PROCESS *p;
226*5507Slinton register int status;
227*5507Slinton {
228*5507Slinton 	register int i;
229*5507Slinton 
230*5507Slinton 	p->signo = (status&0177);
231*5507Slinton 	p->exitval = ((status >> 8)&0377);
232*5507Slinton 	if (p->signo == STOPPED) {
233*5507Slinton 		p->status = p->signo;
234*5507Slinton 		p->signo = p->exitval;
235*5507Slinton 		p->exitval = 0;
236*5507Slinton 	} else {
237*5507Slinton 		p->status = FINISHED;
238*5507Slinton 		return;
239*5507Slinton 	}
240*5507Slinton 	for (i = 0; i < NREG; i++) {
241*5507Slinton 		p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0);
242*5507Slinton 		p->oreg[i] = p->reg[i];
243*5507Slinton 	}
244*5507Slinton 	p->fp = p->ofp = ptrace(UREAD, p->pid, regloc(FP), 0);
245*5507Slinton 	p->ap = p->oap = ptrace(UREAD, p->pid, regloc(AP), 0);
246*5507Slinton 	p->sp = p->osp = ptrace(UREAD, p->pid, regloc(SP), 0);
247*5507Slinton 	p->pc = p->opc = ptrace(UREAD, p->pid, regloc(PC), 0);
248*5507Slinton }
249*5507Slinton 
250*5507Slinton /*
251*5507Slinton  * set process's user area information from given PROCESS structure
252*5507Slinton  */
253*5507Slinton 
254*5507Slinton LOCAL setinfo(p)
255*5507Slinton register PROCESS *p;
256*5507Slinton {
257*5507Slinton 	register int i;
258*5507Slinton 	register int r;
259*5507Slinton 
260*5507Slinton 	if (istraced(p)) {
261*5507Slinton 		p->signo = 0;
262*5507Slinton 	}
263*5507Slinton 	for (i = 0; i < NREG; i++) {
264*5507Slinton 		if ((r = p->reg[i]) != p->oreg[i]) {
265*5507Slinton 			ptrace(UWRITE, p->pid, regloc(rloc[i]), r);
266*5507Slinton 		}
267*5507Slinton 	}
268*5507Slinton 	if ((r = p->fp) != p->ofp) {
269*5507Slinton 		ptrace(UWRITE, p->pid, regloc(FP), r);
270*5507Slinton 	}
271*5507Slinton 	if ((r = p->sp) != p->osp) {
272*5507Slinton 		ptrace(UWRITE, p->pid, regloc(SP), r);
273*5507Slinton 	}
274*5507Slinton 	if ((r = p->ap) != p->oap) {
275*5507Slinton 		ptrace(UWRITE, p->pid, regloc(AP), r);
276*5507Slinton 	}
277*5507Slinton 	if ((r = p->pc) != p->opc) {
278*5507Slinton 		ptrace(UWRITE, p->pid, regloc(PC), r);
279*5507Slinton 	}
280*5507Slinton }
281*5507Slinton 
282*5507Slinton /*
283*5507Slinton  * Structure for reading and writing by words, but dealing with bytes.
284*5507Slinton  */
285*5507Slinton 
286*5507Slinton typedef union {
287*5507Slinton 	WORD pword;
288*5507Slinton 	BYTE pbyte[sizeof(WORD)];
289*5507Slinton } PWORD;
290*5507Slinton 
291*5507Slinton /*
292*5507Slinton  * Read (write) from (to) the process' address space.
293*5507Slinton  * We must deal with ptrace's inability to look anywhere other
294*5507Slinton  * than at a word boundary.
295*5507Slinton  */
296*5507Slinton 
297*5507Slinton LOCAL WORD fetch();
298*5507Slinton LOCAL store();
299*5507Slinton 
300*5507Slinton pio(p, op, seg, buff, addr, nbytes)
301*5507Slinton PROCESS *p;
302*5507Slinton PIO_OP op;
303*5507Slinton PIO_SEG seg;
304*5507Slinton char *buff;
305*5507Slinton ADDRESS addr;
306*5507Slinton int nbytes;
307*5507Slinton {
308*5507Slinton 	register int i;
309*5507Slinton 	register ADDRESS newaddr;
310*5507Slinton 	register char *cp;
311*5507Slinton 	char *bufend;
312*5507Slinton 	PWORD w;
313*5507Slinton 	ADDRESS wordaddr;
314*5507Slinton 	int byteoff;
315*5507Slinton 
316*5507Slinton 	if (p->status != STOPPED) {
317*5507Slinton 		error("program is not active");
318*5507Slinton 	}
319*5507Slinton 	cp = buff;
320*5507Slinton 	newaddr = addr;
321*5507Slinton 	wordaddr = (newaddr&WMASK);
322*5507Slinton 	if (wordaddr != newaddr) {
323*5507Slinton 		w.pword = fetch(p, seg, wordaddr);
324*5507Slinton 		for (i = newaddr - wordaddr; i<sizeof(WORD) && nbytes>0; i++) {
325*5507Slinton 			if (op == PREAD) {
326*5507Slinton 				*cp++ = w.pbyte[i];
327*5507Slinton 			} else {
328*5507Slinton 				w.pbyte[i] = *cp++;
329*5507Slinton 			}
330*5507Slinton 			nbytes--;
331*5507Slinton 		}
332*5507Slinton 		if (op == PWRITE) {
333*5507Slinton 			store(p, seg, wordaddr, w.pword);
334*5507Slinton 		}
335*5507Slinton 		newaddr = wordaddr + sizeof(WORD);
336*5507Slinton 	}
337*5507Slinton 	byteoff = (nbytes&(~WMASK));
338*5507Slinton 	nbytes -= byteoff;
339*5507Slinton 	bufend = cp + nbytes;
340*5507Slinton 	while (cp < bufend) {
341*5507Slinton 		if (op == PREAD) {
342*5507Slinton 			*((WORD *) cp) = fetch(p, seg, newaddr);
343*5507Slinton 		} else {
344*5507Slinton 			store(p, seg, newaddr, *((WORD *) cp));
345*5507Slinton 		}
346*5507Slinton 		cp += sizeof(WORD);
347*5507Slinton 		newaddr += sizeof(WORD);
348*5507Slinton 	}
349*5507Slinton 	if (byteoff > 0) {
350*5507Slinton 		w.pword = fetch(p, seg, newaddr);
351*5507Slinton 		for (i = 0; i < byteoff; i++) {
352*5507Slinton 			if (op == PREAD) {
353*5507Slinton 				*cp++ = w.pbyte[i];
354*5507Slinton 			} else {
355*5507Slinton 				w.pbyte[i] = *cp++;
356*5507Slinton 			}
357*5507Slinton 		}
358*5507Slinton 		if (op == PWRITE) {
359*5507Slinton 			store(p, seg, newaddr, w.pword);
360*5507Slinton 		}
361*5507Slinton 	}
362*5507Slinton }
363*5507Slinton 
364*5507Slinton /*
365*5507Slinton  * Get a word from a process at the given address.
366*5507Slinton  * The address is assumed to be on a word boundary.
367*5507Slinton  *
368*5507Slinton  * We use a simple cache scheme to avoid redundant references to
369*5507Slinton  * the instruction space (which is assumed to be pure).  In the
370*5507Slinton  * case of px, the "instruction" space lies between ENDOFF and
371*5507Slinton  * ENDOFF + objsize.
372*5507Slinton  *
373*5507Slinton  * It is necessary to use a write-through scheme so that
374*5507Slinton  * breakpoints right next to each other don't interfere.
375*5507Slinton  */
376*5507Slinton 
377*5507Slinton LOCAL WORD fetch(p, seg, addr)
378*5507Slinton PROCESS *p;
379*5507Slinton PIO_SEG seg;
380*5507Slinton register int addr;
381*5507Slinton {
382*5507Slinton 	register CACHEWORD *wp;
383*5507Slinton 	register WORD w;
384*5507Slinton 
385*5507Slinton 	switch (seg) {
386*5507Slinton 		case TEXTSEG:
387*5507Slinton #			if (isvaxpx)
388*5507Slinton 				panic("tried to fetch from px i-space");
389*5507Slinton 				/* NOTREACHED */
390*5507Slinton #			else
391*5507Slinton 				wp = &p->word[cachehash(addr)];
392*5507Slinton 				if (addr == 0 || wp->addr != addr) {
393*5507Slinton 					w = ptrace(IREAD, p->pid, addr, 0);
394*5507Slinton 					wp->addr = addr;
395*5507Slinton 					wp->val = w;
396*5507Slinton 				} else {
397*5507Slinton 					w = wp->val;
398*5507Slinton 				}
399*5507Slinton 				break;
400*5507Slinton #			endif
401*5507Slinton 
402*5507Slinton 		case DATASEG:
403*5507Slinton #			if (isvaxpx)
404*5507Slinton 				if (addr >= ENDOFF && addr < ENDOFF + objsize) {
405*5507Slinton 					wp = &p->word[cachehash(addr)];
406*5507Slinton 					if (addr == 0 || wp->addr != addr) {
407*5507Slinton 						w = ptrace(DREAD, p->pid, addr, 0);
408*5507Slinton 						wp->addr = addr;
409*5507Slinton 						wp->val = w;
410*5507Slinton 					} else {
411*5507Slinton 						w = wp->val;
412*5507Slinton 					}
413*5507Slinton 				} else {
414*5507Slinton 					w = ptrace(DREAD, p->pid, addr, 0);
415*5507Slinton 				}
416*5507Slinton #			else
417*5507Slinton 				w = ptrace(DREAD, p->pid, addr, 0);
418*5507Slinton #			endif
419*5507Slinton 			break;
420*5507Slinton 
421*5507Slinton 		default:
422*5507Slinton 			panic("fetch: bad seg %d", seg);
423*5507Slinton 			/* NOTREACHED */
424*5507Slinton 	}
425*5507Slinton 	return(w);
426*5507Slinton }
427*5507Slinton 
428*5507Slinton /*
429*5507Slinton  * Put a word into the process' address space at the given address.
430*5507Slinton  * The address is assumed to be on a word boundary.
431*5507Slinton  */
432*5507Slinton 
433*5507Slinton LOCAL store(p, seg, addr, data)
434*5507Slinton PROCESS *p;
435*5507Slinton PIO_SEG seg;
436*5507Slinton int addr;
437*5507Slinton WORD data;
438*5507Slinton {
439*5507Slinton 	register CACHEWORD *wp;
440*5507Slinton 
441*5507Slinton 	switch (seg) {
442*5507Slinton 		case TEXTSEG:
443*5507Slinton 			wp = &p->word[cachehash(addr)];
444*5507Slinton 			wp->addr = addr;
445*5507Slinton 			wp->val = data;
446*5507Slinton 			ptrace(IWRITE, p->pid, addr, data);
447*5507Slinton 			break;
448*5507Slinton 
449*5507Slinton 		case DATASEG:
450*5507Slinton #			if (isvaxpx)
451*5507Slinton 				if (addr >= ENDOFF && addr < ENDOFF + objsize) {
452*5507Slinton 					wp = &p->word[cachehash(addr)];
453*5507Slinton 					wp->addr = addr;
454*5507Slinton 					wp->val = data;
455*5507Slinton 				}
456*5507Slinton #			endif
457*5507Slinton 			ptrace(DWRITE, p->pid, addr, data);
458*5507Slinton 			break;
459*5507Slinton 
460*5507Slinton 		default:
461*5507Slinton 			panic("store: bad seg %d", seg);
462*5507Slinton 			/*NOTREACHED*/
463*5507Slinton 	}
464*5507Slinton }
465*5507Slinton 
466*5507Slinton /*
467*5507Slinton  * Swap file numbers so as to redirect standard input and output.
468*5507Slinton  */
469*5507Slinton 
470*5507Slinton LOCAL fswap(oldfd, newfd)
471*5507Slinton int oldfd;
472*5507Slinton int newfd;
473*5507Slinton {
474*5507Slinton 	if (oldfd != newfd) {
475*5507Slinton 		close(oldfd);
476*5507Slinton 		dup(newfd);
477*5507Slinton 		close(newfd);
478*5507Slinton 	}
479*5507Slinton }
480