BSD 4_2 release
[unix-history] / usr / src / ucb / dbx / process.c
index 2ce2e43..3755987 100644 (file)
@@ -1,6 +1,6 @@
 /* Copyright (c) 1982 Regents of the University of California */
 
 /* Copyright (c) 1982 Regents of the University of California */
 
-static char sccsid[] = "@(#)process.c 1.4 2/20/83";
+static char sccsid[] = "@(#)process.c 1.12 8/19/83";
 
 /*
  * Process management.
 
 /*
  * Process management.
@@ -14,6 +14,7 @@ static char sccsid[] = "@(#)process.c 1.4 2/20/83";
 #include "machine.h"
 #include "events.h"
 #include "tree.h"
 #include "machine.h"
 #include "events.h"
 #include "tree.h"
+#include "eval.h"
 #include "operators.h"
 #include "source.h"
 #include "object.h"
 #include "operators.h"
 #include "source.h"
 #include "object.h"
@@ -32,6 +33,8 @@ typedef struct Process *Process;
 
 Process process;
 
 
 Process process;
 
+#define DEFSIG -1
+
 #include "machine.h"
 
 #endif
 #include "machine.h"
 
 #endif
@@ -58,14 +61,15 @@ typedef struct {
 
 struct Process {
     int pid;                   /* process being traced */
 
 struct Process {
     int pid;                   /* process being traced */
-    int mask;                  /* ps */
-    Word reg[NREG];            /* process's registers */
+    int mask;                  /* process status word */
+    Word reg[NREG];            /* process' registers */
     Word oreg[NREG];           /* registers when process last stopped */
     short status;              /* either STOPPED or FINISHED */
     short signo;               /* signal that stopped process */
     int exitval;               /* return value from exit() */
     long sigset;               /* bit array of traced signals */
     CacheWord word[CSIZE];     /* text segment cache */
     Word oreg[NREG];           /* registers when process last stopped */
     short status;              /* either STOPPED or FINISHED */
     short signo;               /* signal that stopped process */
     int exitval;               /* return value from exit() */
     long sigset;               /* bit array of traced signals */
     CacheWord word[CSIZE];     /* text segment cache */
+    Ttyinfo ttyinfo;           /* process' terminal characteristics */
 };
 
 /*
 };
 
 /*
@@ -77,7 +81,9 @@ typedef enum { TEXTSEG, DATASEG } PioSeg;
 
 private struct Process pbuf;
 
 
 private struct Process pbuf;
 
-#define MAXNCMDARGS 10         /* maximum number of arguments to RUN */
+#define MAXNCMDARGS 100         /* maximum number of arguments to RUN */
+
+extern int errno;
 
 private Boolean just_started;
 private int argc;
 
 private Boolean just_started;
 private int argc;
@@ -106,7 +112,10 @@ public process_init()
     defregname(identname("$pc", true), PROGCTR);
     if (coredump) {
        coredump_readin(process->mask, process->reg, process->signo);
     defregname(identname("$pc", true), PROGCTR);
     if (coredump) {
        coredump_readin(process->mask, process->reg, process->signo);
+       pc = process->reg[PROGCTR];
+       getsrcpos();
     }
     }
+    arginit();
 }
 
 /*
 }
 
 /*
@@ -279,7 +288,7 @@ public run()
     start(argv, infile, outfile);
     just_started = true;
     isstopped = false;
     start(argv, infile, outfile);
     just_started = true;
     isstopped = false;
-    cont();
+    cont(0);
 }
 
 /*
 }
 
 /*
@@ -297,7 +306,8 @@ private intr();
 #define succeeds    == true
 #define fails       == false
 
 #define succeeds    == true
 #define fails       == false
 
-public cont()
+public cont(signo)
+int signo;
 {
     dbintr = signal(SIGINT, intr);
     if (just_started) {
 {
     dbintr = signal(SIGINT, intr);
     if (just_started) {
@@ -307,20 +317,20 @@ public cont()
            error("can't continue execution");
        }
        isstopped = false;
            error("can't continue execution");
        }
        isstopped = false;
-       step();
+       stepover();
     }
     for (;;) {
        if (single_stepping) {
            printnews();
        } else {
            setallbps();
     }
     for (;;) {
        if (single_stepping) {
            printnews();
        } else {
            setallbps();
-           resume();
+           resume(signo);
            unsetallbps();
            if (bpact() fails) {
                printstatus();
            }
        }
            unsetallbps();
            if (bpact() fails) {
                printstatus();
            }
        }
-       step();
+       stepover();
     }
     /* NOTREACHED */
 }
     }
     /* NOTREACHED */
 }
@@ -349,7 +359,8 @@ public fixintr()
  * Resume execution.
  */
 
  * Resume execution.
  */
 
-public resume()
+public resume(signo)
+int signo;
 {
     register Process p;
 
 {
     register Process p;
 
@@ -358,13 +369,20 @@ public resume()
        printf("execution resumes at pc 0x%x\n", process->reg[PROGCTR]);
        fflush(stdout);
     }
        printf("execution resumes at pc 0x%x\n", process->reg[PROGCTR]);
        fflush(stdout);
     }
-    pcont(p);
+    pcont(p, signo);
     pc = process->reg[PROGCTR];
     if (traceexec) {
        printf("execution stops at pc 0x%x on sig %d\n",
            process->reg[PROGCTR], p->signo);
        fflush(stdout);
     }
     pc = process->reg[PROGCTR];
     if (traceexec) {
        printf("execution stops at pc 0x%x on sig %d\n",
            process->reg[PROGCTR], p->signo);
        fflush(stdout);
     }
+    if (p->status != STOPPED) {
+       if (p->signo != 0) {
+           error("program terminated by signal %d", p->signo);
+       } else if (not runfirst) {
+           error("program unexpectedly exited with %d", p->exitval);
+       }
+    }
 }
 
 /*
 }
 
 /*
@@ -400,9 +418,27 @@ public next()
     isstopped = true;
 }
 
     isstopped = true;
 }
 
-public step()
+/*
+ * Single-step over the current machine instruction.
+ *
+ * If we're single-stepping by source line we want to step to the
+ * next source line.  Otherwise we're going to continue so there's
+ * no reason to do all the work necessary to single-step to the next
+ * source line.
+ */
+
+private stepover()
 {
 {
-    dostep(false);
+    Boolean b;
+
+    if (single_stepping) {
+       dostep(false);
+    } else {
+       b = inst_tracing;
+       inst_tracing = true;
+       dostep(false);
+       inst_tracing = b;
+    }
 }
 
 /*
 }
 
 /*
@@ -415,7 +451,7 @@ public stepto(addr)
 Address addr;
 {
     setbp(addr);
 Address addr;
 {
     setbp(addr);
-    resume();
+    resume(DEFSIG);
     unsetbp(addr);
     if (not isbperr()) {
        printstatus();
     unsetbp(addr);
     if (not isbperr()) {
        printstatus();
@@ -429,6 +465,8 @@ Address addr;
 
 public printstatus()
 {
 
 public printstatus()
 {
+    int status;
+
     if (process->status == FINISHED) {
        exit(0);
     } else {
     if (process->status == FINISHED) {
        exit(0);
     } else {
@@ -465,9 +503,11 @@ public printloc()
     printf("in ");
     printname(stdout, curfunc);
     putchar(' ');
     printf("in ");
     printname(stdout, curfunc);
     putchar(' ');
-    if (curline > 0) {
+    if (curline > 0 and not useInstLoc) {
        printsrcpos();
     } else {
        printsrcpos();
     } else {
+       useInstLoc = false;
+       curline = 0;
        printf("at 0x%x", pc);
     }
 }
        printf("at 0x%x", pc);
     }
 }
@@ -513,14 +553,15 @@ Process p;
  * outside this module.
  *
  * They invoke "pio" which eventually leads to a call to "ptrace".
  * outside this module.
  *
  * They invoke "pio" which eventually leads to a call to "ptrace".
- * The system generates an I/O error when a ptrace fails, we catch
- * that here and assume its due to a misguided address.
+ * The system generates an I/O error when a ptrace fails.  During reads
+ * these are ignored, during writes they are reported as an error, and
+ * for anything else they cause a fatal error.
  */
 
 extern Intfunc *onsyserr();
 
 private badaddr;
  */
 
 extern Intfunc *onsyserr();
 
 private badaddr;
-private rwerr();
+private read_err(), write_err();
 
 /*
  * Read from the process' instruction area.
 
 /*
  * Read from the process' instruction area.
@@ -533,7 +574,7 @@ int nbytes;
 {
     Intfunc *f;
 
 {
     Intfunc *f;
 
-    f = onsyserr(EIO, rwerr);
+    f = onsyserr(EIO, read_err);
     badaddr = addr;
     if (coredump) {
        coredump_readtext(buff, addr, nbytes);
     badaddr = addr;
     if (coredump) {
        coredump_readtext(buff, addr, nbytes);
@@ -558,7 +599,7 @@ int nbytes;
     if (coredump) {
        error("no process to write to");
     }
     if (coredump) {
        error("no process to write to");
     }
-    f = onsyserr(EIO, rwerr);
+    f = onsyserr(EIO, write_err);
     badaddr = addr;
     pio(process, PWRITE, TEXTSEG, buff, addr, nbytes);
     onsyserr(EIO, f);
     badaddr = addr;
     pio(process, PWRITE, TEXTSEG, buff, addr, nbytes);
     onsyserr(EIO, f);
@@ -575,7 +616,7 @@ int nbytes;
 {
     Intfunc *f;
 
 {
     Intfunc *f;
 
-    f = onsyserr(EIO, rwerr);
+    f = onsyserr(EIO, read_err);
     badaddr = addr;
     if (coredump) {
        coredump_readdata(buff, addr, nbytes);
     badaddr = addr;
     if (coredump) {
        coredump_readdata(buff, addr, nbytes);
@@ -599,19 +640,28 @@ int nbytes;
     if (coredump) {
        error("no process to write to");
     }
     if (coredump) {
        error("no process to write to");
     }
-    f = onsyserr(EIO, rwerr);
+    f = onsyserr(EIO, write_err);
     badaddr = addr;
     pio(process, PWRITE, DATASEG, buff, addr, nbytes);
     onsyserr(EIO, f);
 }
 
 /*
     badaddr = addr;
     pio(process, PWRITE, DATASEG, buff, addr, nbytes);
     onsyserr(EIO, f);
 }
 
 /*
- * Error handler.
+ * Trap for errors in reading or writing to a process.
+ * The current approach is to "ignore" read errors and complain
+ * bitterly about write errors.
  */
 
  */
 
-private rwerr()
+private read_err()
 {
 {
-    error("bad read/write process address 0x%x", badaddr);
+    /*
+     * Ignore.
+     */
+}
+
+private write_err()
+{
+    error("can't write to process (address 0x%x)", badaddr);
 }
 
 /*
 }
 
 /*
@@ -620,7 +670,7 @@ private rwerr()
 
 /*
  * This magic macro enables us to look at the process' registers
 
 /*
  * This magic macro enables us to look at the process' registers
- * in its user structure.  Very gross.
+ * in its user structure.
  */
 
 #define regloc(reg)     (ctob(UPAGES) + ( sizeof(int) * (reg) ))
  */
 
 #define regloc(reg)     (ctob(UPAGES) + ( sizeof(int) * (reg) ))
@@ -667,17 +717,19 @@ String infile;
 String outfile;
 {
     int status;
 String outfile;
 {
     int status;
+    Fileid in, out;
 
 
-    if (p->pid != 0) {                 /* child already running? */
-       ptrace(PKILL, p->pid, 0, 0);    /* ... kill it! */
+    if (p->pid != 0) {                 /* child already running? */
+       ptrace(PKILL, p->pid, 0, 0);    /* ... kill it! */
+       pwait(p->pid, &status);         /* wait for it to exit */
+       unptraced(p->pid);
     }
     psigtrace(p, SIGTRAP, true);
     }
     psigtrace(p, SIGTRAP, true);
-    if ((p->pid = vfork()) == -1) {
+    p->pid = vfork();
+    if (p->pid == -1) {
        panic("can't fork");
     }
     if (ischild(p->pid)) {
        panic("can't fork");
     }
     if (ischild(p->pid)) {
-       Fileid in, out;
-
        traceme();
        if (infile != nil) {
            in = open(infile, 0);
        traceme();
        if (infile != nil) {
            in = open(infile, 0);
@@ -699,7 +751,7 @@ String outfile;
            }
            fswap(1, out);
        }
            }
            fswap(1, out);
        }
-       execvp(argv[0], argv);
+       execv(argv[0], argv);
        write(2, "can't exec ", 11);
        write(2, argv[0], strlen(argv[0]));
        write(2, "\n", 1);
        write(2, "can't exec ", 11);
        write(2, argv[0], strlen(argv[0]));
        write(2, "\n", 1);
@@ -710,20 +762,22 @@ String outfile;
     if (p->status != STOPPED) {
        error("program could not begin execution");
     }
     if (p->status != STOPPED) {
        error("program could not begin execution");
     }
+    ptraced(p->pid);
 }
 
 /*
 }
 
 /*
- * 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,
+ * Continue a stopped process.  The first 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.
  */
 
  * 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.
  */
 
-private pcont(p)
+private pcont(p, signo)
 Process p;
 Process p;
+int signo;
 {
     int status;
 
 {
     int status;
 
@@ -731,10 +785,10 @@ Process p;
        error("program not active");
     }
     do {
        error("program not active");
     }
     do {
-       setinfo(p);
+       setinfo(p, signo);
        sigs_off();
        if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) {
        sigs_off();
        if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) {
-           panic("can't continue process");
+           panic("error %d trying to continue process", errno);
        }
        pwait(p->pid, &status);
        sigs_on();
        }
        pwait(p->pid, &status);
        sigs_on();
@@ -751,7 +805,7 @@ Process p;
 {
     int status;
 
 {
     int status;
 
-    setinfo(p);
+    setinfo(p, DEFSIG);
     sigs_off();
     ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo);
     pwait(p->pid, &status);
     sigs_off();
     ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo);
     pwait(p->pid, &status);
@@ -836,6 +890,7 @@ register int status;
     p->exitval = ((status >> 8)&0377);
     if (p->signo != STOPPED) {
        p->status = FINISHED;
     p->exitval = ((status >> 8)&0377);
     if (p->signo != STOPPED) {
        p->status = FINISHED;
+       p->pid = 0;
     } else {
        p->status = p->signo;
        p->signo = p->exitval;
     } else {
        p->status = p->signo;
        p->signo = p->exitval;
@@ -845,6 +900,7 @@ register int status;
            p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0);
            p->oreg[i] = p->reg[i];
        }
            p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0);
            p->oreg[i] = p->reg[i];
        }
+       savetty(stdout, &(p->ttyinfo));
     }
 }
 
     }
 }
 
@@ -852,20 +908,26 @@ register int status;
  * Set process's user area information from given process structure.
  */
 
  * Set process's user area information from given process structure.
  */
 
-private setinfo(p)
+private setinfo(p, signo)
 register Process p;
 register Process p;
+int signo;
 {
     register int i;
     register int r;
 
 {
     register int i;
     register int r;
 
-    if (istraced(p)) {
-       p->signo = 0;
+    if (signo == DEFSIG) {
+       if (istraced(p)) {
+           p->signo = 0;
+       }
+    } else {
+       p->signo = signo;
     }
     for (i = 0; i < NREG; i++) {
        if ((r = p->reg[i]) != p->oreg[i]) {
            ptrace(UWRITE, p->pid, regloc(rloc[i]), r);
        }
     }
     }
     for (i = 0; i < NREG; i++) {
        if ((r = p->reg[i]) != p->oreg[i]) {
            ptrace(UWRITE, p->pid, regloc(rloc[i]), r);
        }
     }
+    restoretty(stdout, &(p->ttyinfo));
 }
 
 /*
 }
 
 /*