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