date and time created 82/01/18 19:20:49 by linton
authorMark Linton <linton@ucbvax.Berkeley.EDU>
Tue, 19 Jan 1982 11:20:49 +0000 (03:20 -0800)
committerMark Linton <linton@ucbvax.Berkeley.EDU>
Tue, 19 Jan 1982 11:20:49 +0000 (03:20 -0800)
SCCS-vsn: usr.bin/pascal/pdx/process/ptrace.c 1.1

usr/src/usr.bin/pascal/pdx/process/ptrace.c [new file with mode: 0644]

diff --git a/usr/src/usr.bin/pascal/pdx/process/ptrace.c b/usr/src/usr.bin/pascal/pdx/process/ptrace.c
new file mode 100644 (file)
index 0000000..7c2fc1d
--- /dev/null
@@ -0,0 +1,479 @@
+/* Copyright (c) 1982 Regents of the University of California */
+
+static char sccsid[] = "@(#)ptrace.c 1.1 %G%";
+
+/*
+ * routines for tracing the execution of a process
+ *
+ * The system call "ptrace" does all the work, these
+ * routines just try to interface easily to it.
+ */
+
+#include "defs.h"
+#include <signal.h>
+#include <sys/param.h>
+#include <sys/reg.h>
+#include "process.h"
+#include "object.h"
+#include "process.rep"
+
+#      if (isvaxpx)
+#              include "pxinfo.h"
+#      endif
+
+/*
+ * This magic macro enables us to look at the process' registers
+ * in its user structure.  Very gross.
+ */
+
+#define regloc(reg)            (ctob(UPAGES) + ( sizeof(int) * (reg) ))
+
+#define WMASK                  (~(sizeof(WORD) - 1))
+#define cachehash(addr)        ((unsigned) ((addr >> 2) % CSIZE))
+
+#define FIRSTSIG               SIGINT
+#define LASTSIG                        SIGQUIT
+#define ischild(pid)   ((pid) == 0)
+#define traceme()              ptrace(0, 0, 0, 0)
+#define setrep(n)              (1 << ((n)-1))
+#define istraced(p)            (p->sigset&setrep(p->signo))
+
+/*
+ * ptrace options (specified in first argument)
+ */
+
+#define UREAD  3               /* read from process's user structure */
+#define UWRITE 6               /* write to process's user structure */
+#define IREAD  1               /* read from process's instruction space */
+#define IWRITE 4               /* write to process's instruction space */
+#define DREAD  2               /* read from process's data space */
+#define DWRITE 5               /* write to process's data space */
+#define CONT   7               /* continue stopped process */
+#define SSTEP  9               /* continue for approximately one instruction */
+#define PKILL  8               /* terminate the process */
+
+/*
+ * Start up a new process by forking and exec-ing the
+ * given argument list, returning when the process is loaded
+ * and ready to execute.  The PROCESS information (pointed to
+ * by the first argument) is appropriately filled.
+ *
+ * If the given PROCESS structure is associated with an already running
+ * process, we terminate it.
+ */
+
+/* VARARGS2 */
+pstart(p, argv, infile, outfile)
+PROCESS *p;
+char **argv;
+char *infile;
+char *outfile;
+{
+       int status;
+       FILE *in, *out;
+
+       if (p->pid != 0) {                                      /* child already running? */
+               ptrace(PKILL, p->pid, 0, 0);    /* ... kill it! */
+       }
+       psigtrace(p, SIGTRAP, TRUE);
+       if ((p->pid = fork()) == -1) {
+               panic("can't fork");
+       }
+       if (ischild(p->pid)) {
+               traceme();
+               if (infile != NIL) {
+                       if ((in = fopen(infile, "r")) == NIL) {
+                               printf("can't read %s\n", infile);
+                               exit(1);
+                       }
+                       fswap(0, fileno(in));
+               }
+               if (outfile != NIL) {
+                       if ((out = fopen(outfile, "w")) == NIL) {
+                               printf("can't write %s\n", outfile);
+                               exit(1);
+                       }
+                       fswap(1, fileno(out));
+               }
+               execvp(argv[0], argv);
+               panic("can't exec %s", argv[0]);
+       }
+       pwait(p->pid, &status);
+       getinfo(p, status);
+       if (p->status != STOPPED) {
+               error("program could not begin execution");
+       }
+}
+
+/*
+ * Continue a stopped process.  The argument points to a PROCESS structure.
+ * Before the process is restarted it's user area is modified according to
+ * the values in the structure.  When this routine finishes,
+ * the structure has the new values from the process's user area.
+ *
+ * Pcont terminates when the process stops with a signal pending that
+ * is being traced (via psigtrace), or when the process terminates.
+ */
+
+pcont(p)
+PROCESS *p;
+{
+       int status;
+
+       if (p->pid == 0) {
+               error("program not active");
+       }
+       do {
+               setinfo(p);
+               sigs_off();
+               if (ptrace(CONT, p->pid, p->pc, p->signo) < 0) {
+                       panic("can't continue process");
+               }
+               pwait(p->pid, &status);
+               sigs_on();
+               getinfo(p, status);
+       } while (p->status == STOPPED && !istraced(p));
+}
+
+/*
+ * single step as best ptrace can
+ */
+
+pstep(p)
+PROCESS *p;
+{
+       int status;
+
+       setinfo(p);
+       sigs_off();
+       ptrace(SSTEP, p->pid, p->pc, p->signo);
+       pwait(p->pid, &status);
+       sigs_on();
+       getinfo(p, status);
+}
+
+/*
+ * Return from execution when the given signal is pending.
+ */
+
+psigtrace(p, sig, sw)
+PROCESS *p;
+int sig;
+int sw;
+{
+       if (sw) {
+               p->sigset |= setrep(sig);
+       } else {
+               p->sigset &= ~setrep(sig);
+       }
+}
+
+/*
+ * Don't catch any signals.
+ * Particularly useful when letting a process finish uninhibited (i.e. px).
+ */
+
+unsetsigtraces(p)
+PROCESS *p;
+{
+       p->sigset = 0;
+}
+
+/*
+ * turn off attention to signals not being caught
+ */
+
+typedef int INTFUNC();
+
+LOCAL INTFUNC *sigfunc[NSIG];
+
+LOCAL sigs_off()
+{
+       register int i;
+
+       for (i = FIRSTSIG; i < LASTSIG; i++) {
+               if (i != SIGKILL) {
+                       sigfunc[i] = signal(i, SIG_IGN);
+               }
+       }
+}
+
+/*
+ * turn back on attention to signals
+ */
+
+LOCAL sigs_on()
+{
+       register int i;
+
+       for (i = FIRSTSIG; i < LASTSIG; i++) {
+               if (i != SIGKILL) {
+                       signal(i, sigfunc[i]);
+               }
+       }
+}
+
+/*
+ * get PROCESS information from process's user area
+ */
+
+LOCAL int rloc[] ={
+       R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11,
+};
+
+LOCAL getinfo(p, status)
+register PROCESS *p;
+register int status;
+{
+       register int i;
+
+       p->signo = (status&0177);
+       p->exitval = ((status >> 8)&0377);
+       if (p->signo == STOPPED) {
+               p->status = p->signo;
+               p->signo = p->exitval;
+               p->exitval = 0;
+       } else {
+               p->status = FINISHED;
+               return;
+       }
+       for (i = 0; i < NREG; i++) {
+               p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0);
+               p->oreg[i] = p->reg[i];
+       }
+       p->fp = p->ofp = ptrace(UREAD, p->pid, regloc(FP), 0);
+       p->ap = p->oap = ptrace(UREAD, p->pid, regloc(AP), 0);
+       p->sp = p->osp = ptrace(UREAD, p->pid, regloc(SP), 0);
+       p->pc = p->opc = ptrace(UREAD, p->pid, regloc(PC), 0);
+}
+
+/*
+ * set process's user area information from given PROCESS structure
+ */
+
+LOCAL setinfo(p)
+register PROCESS *p;
+{
+       register int i;
+       register int r;
+
+       if (istraced(p)) {
+               p->signo = 0;
+       }
+       for (i = 0; i < NREG; i++) {
+               if ((r = p->reg[i]) != p->oreg[i]) {
+                       ptrace(UWRITE, p->pid, regloc(rloc[i]), r);
+               }
+       }
+       if ((r = p->fp) != p->ofp) {
+               ptrace(UWRITE, p->pid, regloc(FP), r);
+       }
+       if ((r = p->sp) != p->osp) {
+               ptrace(UWRITE, p->pid, regloc(SP), r);
+       }
+       if ((r = p->ap) != p->oap) {
+               ptrace(UWRITE, p->pid, regloc(AP), r);
+       }
+       if ((r = p->pc) != p->opc) {
+               ptrace(UWRITE, p->pid, regloc(PC), r);
+       }
+}
+
+/*
+ * Structure for reading and writing by words, but dealing with bytes.
+ */
+
+typedef union {
+       WORD pword;
+       BYTE pbyte[sizeof(WORD)];
+} PWORD;
+
+/*
+ * Read (write) from (to) the process' address space.
+ * We must deal with ptrace's inability to look anywhere other
+ * than at a word boundary.
+ */
+
+LOCAL WORD fetch();
+LOCAL store();
+
+pio(p, op, seg, buff, addr, nbytes)
+PROCESS *p;
+PIO_OP op;
+PIO_SEG seg;
+char *buff;
+ADDRESS addr;
+int nbytes;
+{
+       register int i;
+       register ADDRESS newaddr;
+       register char *cp;
+       char *bufend;
+       PWORD w;
+       ADDRESS wordaddr;
+       int byteoff;
+
+       if (p->status != STOPPED) {
+               error("program is not active");
+       }
+       cp = buff;
+       newaddr = addr;
+       wordaddr = (newaddr&WMASK);
+       if (wordaddr != newaddr) {
+               w.pword = fetch(p, seg, wordaddr);
+               for (i = newaddr - wordaddr; i<sizeof(WORD) && nbytes>0; i++) {
+                       if (op == PREAD) {
+                               *cp++ = w.pbyte[i];
+                       } else {
+                               w.pbyte[i] = *cp++;
+                       }
+                       nbytes--;
+               }
+               if (op == PWRITE) {
+                       store(p, seg, wordaddr, w.pword);
+               }
+               newaddr = wordaddr + sizeof(WORD);
+       }
+       byteoff = (nbytes&(~WMASK));
+       nbytes -= byteoff;
+       bufend = cp + nbytes;
+       while (cp < bufend) {
+               if (op == PREAD) {
+                       *((WORD *) cp) = fetch(p, seg, newaddr);
+               } else {
+                       store(p, seg, newaddr, *((WORD *) cp));
+               }
+               cp += sizeof(WORD);
+               newaddr += sizeof(WORD);
+       }
+       if (byteoff > 0) {
+               w.pword = fetch(p, seg, newaddr);
+               for (i = 0; i < byteoff; i++) {
+                       if (op == PREAD) {
+                               *cp++ = w.pbyte[i];
+                       } else {
+                               w.pbyte[i] = *cp++;
+                       }
+               }
+               if (op == PWRITE) {
+                       store(p, seg, newaddr, w.pword);
+               }
+       }
+}
+
+/*
+ * Get a word from a process at the given address.
+ * The address is assumed to be on a word boundary.
+ *
+ * We use a simple cache scheme to avoid redundant references to
+ * the instruction space (which is assumed to be pure).  In the
+ * case of px, the "instruction" space lies between ENDOFF and
+ * ENDOFF + objsize.
+ *
+ * It is necessary to use a write-through scheme so that
+ * breakpoints right next to each other don't interfere.
+ */
+
+LOCAL WORD fetch(p, seg, addr)
+PROCESS *p;
+PIO_SEG seg;
+register int addr;
+{
+       register CACHEWORD *wp;
+       register WORD w;
+
+       switch (seg) {
+               case TEXTSEG:
+#                      if (isvaxpx)
+                               panic("tried to fetch from px i-space");
+                               /* NOTREACHED */
+#                      else
+                               wp = &p->word[cachehash(addr)];
+                               if (addr == 0 || wp->addr != addr) {
+                                       w = ptrace(IREAD, p->pid, addr, 0);
+                                       wp->addr = addr;
+                                       wp->val = w;
+                               } else {
+                                       w = wp->val;
+                               }
+                               break;
+#                      endif
+
+               case DATASEG:
+#                      if (isvaxpx)
+                               if (addr >= ENDOFF && addr < ENDOFF + objsize) {
+                                       wp = &p->word[cachehash(addr)];
+                                       if (addr == 0 || wp->addr != addr) {
+                                               w = ptrace(DREAD, p->pid, addr, 0);
+                                               wp->addr = addr;
+                                               wp->val = w;
+                                       } else {
+                                               w = wp->val;
+                                       }
+                               } else {
+                                       w = ptrace(DREAD, p->pid, addr, 0);
+                               }
+#                      else
+                               w = ptrace(DREAD, p->pid, addr, 0);
+#                      endif
+                       break;
+
+               default:
+                       panic("fetch: bad seg %d", seg);
+                       /* NOTREACHED */
+       }
+       return(w);
+}
+
+/*
+ * Put a word into the process' address space at the given address.
+ * The address is assumed to be on a word boundary.
+ */
+
+LOCAL store(p, seg, addr, data)
+PROCESS *p;
+PIO_SEG seg;
+int addr;
+WORD data;
+{
+       register CACHEWORD *wp;
+
+       switch (seg) {
+               case TEXTSEG:
+                       wp = &p->word[cachehash(addr)];
+                       wp->addr = addr;
+                       wp->val = data;
+                       ptrace(IWRITE, p->pid, addr, data);
+                       break;
+
+               case DATASEG:
+#                      if (isvaxpx)
+                               if (addr >= ENDOFF && addr < ENDOFF + objsize) {
+                                       wp = &p->word[cachehash(addr)];
+                                       wp->addr = addr;
+                                       wp->val = data;
+                               }
+#                      endif
+                       ptrace(DWRITE, p->pid, addr, data);
+                       break;
+
+               default:
+                       panic("store: bad seg %d", seg);
+                       /*NOTREACHED*/
+       }
+}
+
+/*
+ * Swap file numbers so as to redirect standard input and output.
+ */
+
+LOCAL fswap(oldfd, newfd)
+int oldfd;
+int newfd;
+{
+       if (oldfd != newfd) {
+               close(oldfd);
+               dup(newfd);
+               close(newfd);
+       }
+}