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