/* 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.
#include "machine.h"
#include "events.h"
#include "tree.h"
+#include "eval.h"
#include "operators.h"
#include "source.h"
#include "object.h"
Process process;
+#define DEFSIG -1
+
#include "machine.h"
#endif
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 */
+ Ttyinfo ttyinfo; /* process' terminal characteristics */
};
/*
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;
defregname(identname("$pc", true), PROGCTR);
if (coredump) {
coredump_readin(process->mask, process->reg, process->signo);
+ pc = process->reg[PROGCTR];
+ getsrcpos();
}
+ arginit();
}
/*
start(argv, infile, outfile);
just_started = true;
isstopped = false;
- cont();
+ cont(0);
}
/*
#define succeeds == true
#define fails == false
-public cont()
+public cont(signo)
+int signo;
{
dbintr = signal(SIGINT, intr);
if (just_started) {
error("can't continue execution");
}
isstopped = false;
- step();
+ stepover();
}
for (;;) {
if (single_stepping) {
printnews();
} else {
setallbps();
- resume();
+ resume(signo);
unsetallbps();
if (bpact() fails) {
printstatus();
}
}
- step();
+ stepover();
}
/* NOTREACHED */
}
* Resume execution.
*/
-public resume()
+public resume(signo)
+int signo;
{
register Process p;
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);
}
+ 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);
+ }
+ }
}
/*
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;
+ }
}
/*
Address addr;
{
setbp(addr);
- resume();
+ resume(DEFSIG);
unsetbp(addr);
if (not isbperr()) {
printstatus();
public printstatus()
{
+ int status;
+
if (process->status == FINISHED) {
exit(0);
} else {
printf("in ");
printname(stdout, curfunc);
putchar(' ');
- if (curline > 0) {
+ if (curline > 0 and not useInstLoc) {
printsrcpos();
} else {
+ useInstLoc = false;
+ curline = 0;
printf("at 0x%x", pc);
}
}
* 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;
-private rwerr();
+private read_err(), write_err();
/*
* Read from the process' instruction area.
{
Intfunc *f;
- f = onsyserr(EIO, rwerr);
+ f = onsyserr(EIO, read_err);
badaddr = addr;
if (coredump) {
coredump_readtext(buff, addr, nbytes);
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);
{
Intfunc *f;
- f = onsyserr(EIO, rwerr);
+ f = onsyserr(EIO, read_err);
badaddr = addr;
if (coredump) {
coredump_readdata(buff, addr, nbytes);
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);
}
/*
- * 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);
}
/*
/*
* 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) ))
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);
- if ((p->pid = vfork()) == -1) {
+ p->pid = vfork();
+ if (p->pid == -1) {
panic("can't fork");
}
if (ischild(p->pid)) {
- Fileid in, out;
-
traceme();
if (infile != nil) {
in = open(infile, 0);
}
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);
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.
*/
-private pcont(p)
+private pcont(p, signo)
Process p;
+int signo;
{
int status;
error("program not active");
}
do {
- setinfo(p);
+ setinfo(p, signo);
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();
{
int status;
- setinfo(p);
+ setinfo(p, DEFSIG);
sigs_off();
ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo);
pwait(p->pid, &status);
p->exitval = ((status >> 8)&0377);
if (p->signo != STOPPED) {
p->status = FINISHED;
+ p->pid = 0;
} else {
p->status = p->signo;
p->signo = p->exitval;
p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0);
p->oreg[i] = p->reg[i];
}
+ savetty(stdout, &(p->ttyinfo));
}
}
* Set process's user area information from given process structure.
*/
-private setinfo(p)
+private setinfo(p, signo)
register Process p;
+int signo;
{
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);
}
}
+ restoretty(stdout, &(p->ttyinfo));
}
/*