-/* Copyright (c) 1982 Regents of the University of California */
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
-static char sccsid[] = "@(#)process.c 1.4 %G%";
+#ifndef lint
+static char sccsid[] = "@(#)process.c 5.3 (Berkeley) %G%";
+#endif not lint
+
+static char rcsid[] = "$Header: process.c,v 1.4 88/01/10 00:49:31 donn Exp $";
/*
* Process management.
#include "machine.h"
#include "events.h"
#include "tree.h"
+#include "eval.h"
#include "operators.h"
#include "source.h"
#include "object.h"
#include "coredump.h"
#include <signal.h>
#include <errno.h>
-#include <sys/param.h>
-#include <machine/reg.h>
#include <sys/stat.h>
#ifndef public
Process process;
+#define DEFSIG -1
+
#include "machine.h"
#endif
#define FINISHED 0
/*
- * Cache-ing of instruction segment is done to reduce the number
- * of system calls.
+ * A cache of the instruction segment is kept to reduce the number
+ * of system calls. Might be better just to read the entire
+ * code space into memory.
*/
-#define CSIZE 1003 /* size of instruction cache */
+#define CACHESIZE 1003
typedef struct {
Word addr;
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 */
+ short sigcode; /* extra signal information */
int exitval; /* return value from exit() */
long sigset; /* bit array of traced signals */
- CacheWord word[CSIZE]; /* text segment cache */
+ CacheWord word[CACHESIZE]; /* text segment cache */
+ Ttyinfo ttyinfo; /* process' terminal characteristics */
+ Address sigstatus; /* process' handler for current signal */
};
/*
private struct Process pbuf;
-#define MAXNCMDARGS 10 /* maximum number of arguments to RUN */
+#define MAXNCMDARGS 1000 /* maximum number of arguments to RUN */
+
+extern int errno;
private Boolean just_started;
private int argc;
public process_init()
{
- register Integer i;
- Char buf[10];
+ register integer i;
+ char buf[10];
process = &pbuf;
process->status = (coredump) ? STOPPED : NOTSTARTED;
setsigtrace();
- for (i = 0; i < NREG; i++) {
- sprintf(buf, "$r%d", i);
- defregname(identname(buf, false), i);
- }
- defregname(identname("$ap", true), ARGP);
+# if vax || tahoe
+ for (i = 0; i < NREG; i++) {
+ sprintf(buf, "$r%d", i);
+ defregname(identname(buf, false), i);
+ }
+# ifdef vax
+ defregname(identname("$ap", true), ARGP);
+# endif
+# else
+# ifdef mc68000
+ for (i = 0; i < 8; i++) {
+ sprintf(buf, "$d%d", i);
+ defregname(identname(buf, false), i);
+ sprintf(buf, "$a%d", i);
+ defregname(identname(buf, false), i + 8);
+ }
+# endif
+# endif
defregname(identname("$fp", true), FRP);
defregname(identname("$sp", true), STKP);
defregname(identname("$pc", true), PROGCTR);
if (coredump) {
coredump_readin(process->mask, process->reg, process->signo);
+ pc = process->reg[PROGCTR];
}
+ arginit();
}
/*
} else {
argv[argc] = nil;
}
+ pstart(process, argv, infile, outfile);
if (remade(objname)) {
reinit(argv, infile, outfile);
}
- pstart(process, argv, infile, outfile);
if (process->status == STOPPED) {
- pc = 0;
- curfunc = program;
+ pc = CODESTART;
+ setcurfunc(program);
if (objsize != 0) {
cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr()));
event_once(cond, buildcmdlist(build(O_ENDX)));
psigtrace(p, SIGHUP, false);
psigtrace(p, SIGKILL, false);
psigtrace(p, SIGALRM, false);
- psigtrace(p, SIGTSTP, false);
- psigtrace(p, SIGCONT, false);
+# ifdef SIGTSTP
+ psigtrace(p, SIGTSTP, false);
+ psigtrace(p, SIGCONT, false);
+# endif
psigtrace(p, SIGCHLD, false);
+ psigtrace(p, SIGWINCH, false);
}
/*
start(argv, infile, outfile);
just_started = true;
isstopped = false;
- cont();
+ cont(0);
}
/*
private Intfunc *dbintr;
private intr();
-#define succeeds == true
-#define fails == false
-
-public cont()
+public cont(signo)
+integer signo;
{
+ integer s;
+
dbintr = signal(SIGINT, intr);
if (just_started) {
just_started = false;
error("can't continue execution");
}
isstopped = false;
- step();
+ stepover();
}
+ s = signo;
for (;;) {
if (single_stepping) {
printnews();
} else {
setallbps();
- resume();
+ resume(s);
unsetallbps();
- if (bpact() fails) {
+ s = DEFSIG;
+ if (not isbperr() or not bpact()) {
printstatus();
}
}
- step();
+ stepover();
}
/* NOTREACHED */
}
/*
- * This routine is called if we get an interrupt while "running" px
+ * This routine is called if we get an interrupt while "running"
* but actually in the debugger. Could happen, for example, while
* processing breakpoints.
*
* We basically just want to keep going; the assumption is
- * that when the process resumes it will get the interrupt
+ * that when the process resumes it will get the interrupt,
* which will then be handled.
*/
* Resume execution.
*/
-public resume()
+public resume(signo)
+int signo;
{
register Process p;
p = process;
- if (traceexec) {
- 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) {
+ if (p->exitval == 0) {
+ error("program exited");
+ } else {
+ error("program exited with code %d", p->exitval);
+ }
+ }
}
}
public next()
{
+ Address oldfrp, newfrp;
+
if (not isstopped) {
error("can't continue execution");
}
isstopped = false;
- dostep(true);
+ oldfrp = reg(FRP);
+ do {
+ dostep(true);
+ pc = reg(PROGCTR);
+ newfrp = reg(FRP);
+ } while (newfrp < oldfrp and newfrp != 0);
isstopped = true;
}
-public step()
+/*
+ * Continue execution until the current function returns, or,
+ * if the given argument is non-nil, until execution returns to
+ * somewhere within the given function.
+ */
+
+public rtnfunc (f)
+Symbol f;
{
- dostep(false);
+ Address addr;
+ Symbol t;
+
+ if (not isstopped) {
+ error("can't continue execution");
+ } else if (f != nil and not isactive(f)) {
+ error("%s is not active", symname(f));
+ } else {
+ addr = return_addr();
+ if (addr == nil) {
+ error("no place to return to");
+ } else {
+ isstopped = false;
+ contto(addr);
+ if (f != nil) {
+ for (;;) {
+ t = whatblock(pc);
+ addr = return_addr();
+ if (t == f or addr == nil) break;
+ contto(addr);
+ }
+ }
+ if (not bpact()) {
+ isstopped = true;
+ printstatus();
+ }
+ }
+ }
+}
+
+/*
+ * 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.
+ */
+
+public stepover()
+{
+ Boolean b;
+
+ if (traceexec) {
+ printf("!! stepping over 0x%x\n", process->reg[PROGCTR]);
+ }
+ if (single_stepping) {
+ dostep(false);
+ } else {
+ b = inst_tracing;
+ inst_tracing = true;
+ dostep(false);
+ inst_tracing = b;
+ }
+ if (traceexec) {
+ printf("!! stepped over to 0x%x\n", process->reg[PROGCTR]);
+ }
}
/*
- * Resume execution up to the given address. It is assumed that
- * no breakpoints exist between the current address and the one
- * we're stepping to. This saves us from setting all the breakpoints.
+ * Resume execution up to the given address. We can either ignore
+ * breakpoints (stepto) or catch them (contto).
*/
public stepto(addr)
Address addr;
{
- setbp(addr);
- resume();
- unsetbp(addr);
- if (not isbperr()) {
- printstatus();
+ xto(addr, false);
+}
+
+private contto (addr)
+Address addr;
+{
+ xto(addr, true);
+}
+
+private xto (addr, catchbps)
+Address addr;
+boolean catchbps;
+{
+ Address curpc;
+
+ if (catchbps) {
+ stepover();
+ }
+ curpc = process->reg[PROGCTR];
+ if (addr != curpc) {
+ if (traceexec) {
+ printf("!! stepping from 0x%x to 0x%x\n", curpc, addr);
+ }
+ if (catchbps) {
+ setallbps();
+ }
+ setbp(addr);
+ resume(DEFSIG);
+ unsetbp(addr);
+ if (catchbps) {
+ unsetallbps();
+ }
+ if (not isbperr()) {
+ printstatus();
+ }
}
}
* This routine does not return.
*/
-public printstatus()
+public printstatus ()
{
+ int status;
+
if (process->status == FINISHED) {
exit(0);
} else {
- curfunc = whatblock(pc);
+ if (runfirst) {
+ fprintf(stderr, "\nEntering debugger ...\n");
+ printheading();
+ init();
+ }
+ setcurfunc(whatblock(pc));
getsrcpos();
if (process->signo == SIGINT) {
isstopped = true;
}
erecover();
} else {
- fixbps();
fixintr();
isstopped = true;
printerror();
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);
}
}
}
/*
- * Return the signal number which stopped the process.
+ * Predicate to test if the reason the process stopped was because
+ * of a breakpoint. If so, as a side effect clear the local copy of
+ * signal handler associated with process. We must do this so as to
+ * not confuse future stepping or continuing by possibly concluding
+ * the process should continue with a SIGTRAP handler.
+ */
+
+public boolean isbperr()
+{
+ Process p;
+ boolean b;
+
+ p = process;
+ if (p->status == STOPPED and p->signo == SIGTRAP) {
+ b = true;
+ p->sigstatus = 0;
+ } else {
+ b = false;
+ }
+ return b;
+}
+
+/*
+ * Return the signal number that stopped the process.
*/
-public Integer errnum(p)
+public integer errnum (p)
Process p;
{
return p->signo;
}
+/*
+ * Return the signal code associated with the signal.
+ */
+
+public integer errcode (p)
+Process p;
+{
+ return p->sigcode;
+}
+
/*
* Return the termination code of the process.
*/
-public Integer exitcode(p)
+public integer exitcode (p)
Process p;
{
return p->exitval;
* 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);
badaddr = addr;
if (coredump) {
+ f = onsyserr(EFAULT, read_err);
coredump_readdata(buff, addr, nbytes);
+ onsyserr(EFAULT, f);
} else {
+ f = onsyserr(EIO, read_err);
pio(process, PREAD, DATASEG, buff, addr, nbytes);
+ onsyserr(EIO, f);
}
- onsyserr(EIO, f);
}
/*
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.
+ */
}
-/*
- * Ptrace interface.
- */
+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.
+ * Ptrace interface.
*/
-#define regloc(reg) (ctob(UPAGES) + ( sizeof(int) * (reg) ))
-
#define WMASK (~(sizeof(Word) - 1))
-#define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE))
+#define cachehash(addr) ((unsigned) ((addr >> 2) % CACHESIZE))
#define FIRSTSIG SIGINT
#define LASTSIG SIGQUIT
#define SSTEP 9 /* continue for approximately one instruction */
#define PKILL 8 /* terminate the process */
+#ifdef IRIS
+# define readreg(p, r) ptrace(10, p->pid, r, 0)
+# define writereg(p, r, v) ptrace(11, p->pid, r, v)
+#else
+# define readreg(p, r) ptrace(UREAD, p->pid, regloc(r), 0);
+# define writereg(p, r, v) ptrace(UWRITE, p->pid, regloc(r), v);
+#endif
+
/*
* Start up a new process by forking and exec-ing the
* given argument list, returning when the process is loaded
{
int status;
- if (p->pid != 0) { /* child already running? */
- ptrace(PKILL, p->pid, 0, 0); /* ... kill it! */
+ if (p->pid != 0) {
+ pterm(p);
+ cacheflush(p);
}
+ fflush(stdout);
psigtrace(p, SIGTRAP, true);
- if ((p->pid = vfork()) == -1) {
+# ifdef IRIS
+ p->pid = fork();
+# else
+ p->pid = vfork();
+# endif
+ if (p->pid == -1) {
panic("can't fork");
}
if (ischild(p->pid)) {
- Fileid in, out;
-
+ nocatcherrs();
traceme();
if (infile != nil) {
- in = open(infile, 0);
- if (in == -1) {
- write(2, "can't read ", 11);
- write(2, infile, strlen(infile));
- write(2, "\n", 1);
- _exit(1);
- }
- fswap(0, in);
+ infrom(infile);
}
if (outfile != nil) {
- out = creat(outfile, 0666);
- if (out == -1) {
- write(2, "can't write ", 12);
- write(2, outfile, strlen(outfile));
- write(2, "\n", 1);
- _exit(1);
- }
- fswap(1, out);
+ outto(outfile);
}
- execvp(argv[0], argv);
- write(2, "can't exec ", 11);
- write(2, argv[0], strlen(argv[0]));
- write(2, "\n", 1);
+ execv(argv[0], argv);
_exit(1);
}
pwait(p->pid, &status);
getinfo(p, status);
if (p->status != STOPPED) {
- error("program could not begin execution");
+ beginerrmsg();
+ fprintf(stderr, "warning: cannot execute %s\n", argv[0]);
+ } else {
+ ptraced(p->pid);
+ }
+}
+
+/*
+ * Terminate a ptrace'd process.
+ */
+
+public pterm (p)
+Process p;
+{
+ integer status;
+
+ if (p != nil and p->pid != 0) {
+ ptrace(PKILL, p->pid, 0, 0);
+ pwait(p->pid, &status);
+ unptraced(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;
+ int s, status;
if (p->pid == 0) {
- error("program not active");
+ error("program is not active");
}
+ s = signo;
do {
- setinfo(p);
+ setinfo(p, s);
+ if (traceexec) {
+ printf("!! pcont from 0x%x with signal %d (%d)\n",
+ p->reg[PROGCTR], s, p->signo);
+ fflush(stdout);
+ }
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();
getinfo(p, status);
+ if (p->status == STOPPED and traceexec and not istraced(p)) {
+ printf("!! ignored signal %d at 0x%x\n",
+ p->signo, p->reg[PROGCTR]);
+ fflush(stdout);
+ }
+ s = p->signo;
} while (p->status == STOPPED and not istraced(p));
+ if (traceexec) {
+ printf("!! pcont to 0x%x on signal %d\n", p->reg[PROGCTR], p->signo);
+ fflush(stdout);
+ }
}
/*
* Single step as best ptrace can.
*/
-public pstep(p)
+public pstep(p, signo)
Process p;
+integer signo;
{
- int status;
+ int s, status;
- setinfo(p);
- sigs_off();
- ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo);
- pwait(p->pid, &status);
- sigs_on();
- getinfo(p, status);
+ s = signo;
+ do {
+ setinfo(p, s);
+ if (traceexec) {
+ printf("!! pstep from 0x%x with signal %d (%d)\n",
+ p->reg[PROGCTR], s, p->signo);
+ fflush(stdout);
+ }
+ sigs_off();
+ if (ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo) < 0) {
+ panic("error %d trying to step process", errno);
+ }
+ pwait(p->pid, &status);
+ sigs_on();
+ getinfo(p, status);
+# if mc68000 || m68000
+ if (p->status == STOPPED and p->signo == SIGTRAP) {
+ p->reg[PROGCTR] += 2;
+ }
+# endif
+ if (p->status == STOPPED and traceexec and not istraced(p)) {
+ printf("!! pstep ignored signal %d at 0x%x\n",
+ p->signo, p->reg[PROGCTR]);
+ fflush(stdout);
+ }
+ s = p->signo;
+ } while (p->status == STOPPED and not istraced(p));
+ if (traceexec) {
+ printf("!! pstep to 0x%x on signal %d\n",
+ p->reg[PROGCTR], p->signo);
+ fflush(stdout);
+ }
+ if (p->status != STOPPED) {
+ if (p->exitval == 0) {
+ error("program exited\n");
+ } else {
+ error("program exited with code %d\n", p->exitval);
+ }
+ }
}
/*
* Get process information from user area.
*/
-private int rloc[] ={
- R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, AP, FP, SP, PC
-};
-
-private getinfo(p, status)
+private getinfo (p, status)
register Process p;
register int status;
{
register int i;
+ Address addr;
p->signo = (status&0177);
p->exitval = ((status >> 8)&0377);
if (p->signo != STOPPED) {
p->status = FINISHED;
+ p->pid = 0;
+ p->reg[PROGCTR] = 0;
} else {
p->status = p->signo;
p->signo = p->exitval;
p->exitval = 0;
- p->mask = ptrace(UREAD, p->pid, regloc(PS), 0);
+# ifdef IRIS
+ p->mask = readreg(p, RPS);
+# else
+ p->sigcode = ptrace(UREAD, p->pid, &((struct user *)0)->u_code, 0);
+ p->mask = readreg(p, PS);
+# endif
for (i = 0; i < NREG; i++) {
- p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0);
+ p->reg[i] = readreg(p, rloc[i]);
p->oreg[i] = p->reg[i];
}
+# ifdef mc68000
+ if (p->status == STOPPED and p->signo == SIGTRAP and
+ p->reg[PROGCTR] > CODESTART
+ ) {
+ p->reg[PROGCTR] -= 2;
+ }
+# endif
+ savetty(stdout, &(p->ttyinfo));
+ addr = (Address) &(((struct user *) 0)->u_signal[p->signo]);
+ p->sigstatus = (Address) ptrace(UREAD, p->pid, addr, 0);
}
}
* 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) and (p->sigstatus == 0 or p->sigstatus == 1)) {
+ 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);
+ writereg(p, rloc[i], r);
}
}
+ restoretty(stdout, &(p->ttyinfo));
+}
+
+/*
+ * Return the address associated with the current signal.
+ * (Plus two since the address points to the beginning of a procedure).
+ */
+
+public Address usignal (p)
+Process p;
+{
+ Address r;
+
+ r = p->sigstatus;
+ if (r != 0 and r != 1) {
+ r += FUNCOFFSET;
+ }
+ return r;
}
/*
byteoff = (nbytes&(~WMASK));
nbytes -= byteoff;
bufend = cp + nbytes;
+#ifdef tahoe
+ if (((int)cp)&WMASK) {
+ /*
+ * Must copy a byte at a time, buffer not word addressable.
+ */
+ while (cp < bufend) {
+ if (op == PREAD) {
+ w.pword = fetch(p, seg, newaddr);
+ for (i = 0; i < sizeof(Word); i++)
+ *cp++ = w.pbyte[i];
+ } else {
+ for (i = 0; i < sizeof(Word); i++)
+ w.pbyte[i] = *cp++;
+ store(p, seg, newaddr, w.pword);
+ }
+ newaddr += sizeof(Word);
+ }
+ } else {
+ /*
+ * Buffer, word aligned, act normally...
+ */
+#endif
while (cp < bufend) {
if (op == PREAD) {
*((Word *) cp) = fetch(p, seg, newaddr);
cp += sizeof(Word);
newaddr += sizeof(Word);
}
+#ifdef tahoe
+ }
+#endif
if (byteoff > 0) {
w.pword = fetch(p, seg, newaddr);
for (i = 0; i < byteoff; i++) {
}
}
+/*
+ * Flush the instruction cache associated with a process.
+ */
+
+private cacheflush (p)
+Process p;
+{
+ bzero(p->word, sizeof(p->word));
+}
+
public printptraceinfo()
{
printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites);
}
/*
- * Swap file numbers so as to redirect standard input and output.
+ * Redirect input.
+ * Assuming this is called from a child, we should be careful to avoid
+ * (possibly) shared standard I/O buffers.
+ */
+
+private infrom (filename)
+String filename;
+{
+ Fileid in;
+
+ in = open(filename, 0);
+ if (in == -1) {
+ write(2, "can't read ", 11);
+ write(2, filename, strlen(filename));
+ write(2, "\n", 1);
+ _exit(1);
+ }
+ fswap(0, in);
+}
+
+/*
+ * Redirect standard output.
+ * Same assumptions as for "infrom" above.
+ */
+
+private outto (filename)
+String filename;
+{
+ Fileid out;
+
+ out = creat(filename, 0666);
+ if (out == -1) {
+ write(2, "can't write ", 12);
+ write(2, filename, strlen(filename));
+ write(2, "\n", 1);
+ _exit(1);
+ }
+ fswap(1, out);
+}
+
+/*
+ * Swap file numbers, useful for redirecting standard input or output.
*/
private fswap(oldfd, newfd)
-int oldfd;
-int newfd;
+Fileid oldfd;
+Fileid newfd;
{
if (oldfd != newfd) {
close(oldfd);
close(newfd);
}
}
+
+/*
+ * Signal name manipulation.
+ */
+
+private String signames[NSIG] = {
+ 0,
+ "HUP", "INT", "QUIT", "ILL", "TRAP",
+ "IOT", "EMT", "FPE", "KILL", "BUS",
+ "SEGV", "SYS", "PIPE", "ALRM", "TERM",
+ 0, "STOP", "TSTP", "CONT", "CHLD",
+ "TTIN", "TTOU", "TINT", "XCPU", "XFSZ",
+ "VTALRM", "PROF", "WINCH", "USR1", "USR2"
+};
+
+/*
+ * Get the signal number associated with a given name.
+ * The name is first translated to upper case if necessary.
+ */
+
+public integer siglookup (s)
+String s;
+{
+ register char *p, *q;
+ char buf[100];
+ integer i;
+
+ p = s;
+ q = buf;
+ while (*p != '\0') {
+ if (*p >= 'a' and *p <= 'z') {
+ *q = (*p - 'a') + 'A';
+ } else {
+ *q = *p;
+ }
+ ++p;
+ ++q;
+ }
+ *q = '\0';
+ p = buf;
+ if (buf[0] == 'S' and buf[1] == 'I' and buf[2] == 'G') {
+ p += 3;
+ }
+ i = 1;
+ for (;;) {
+ if (i >= sizeof(signames) div sizeof(signames[0])) {
+ error("signal \"%s\" unknown", s);
+ i = 0;
+ break;
+ }
+ if (signames[i] != nil and streq(signames[i], p)) {
+ break;
+ }
+ ++i;
+ }
+ return i;
+}
+
+/*
+ * Print all signals being ignored by the debugger.
+ * These signals are auotmatically
+ * passed on to the debugged process.
+ */
+
+public printsigsignored (p)
+Process p;
+{
+ printsigs(~p->sigset);
+}
+
+/*
+ * Print all signals being intercepted by
+ * the debugger for the specified process.
+ */
+
+public printsigscaught(p)
+Process p;
+{
+ printsigs(p->sigset);
+}
+
+private printsigs (set)
+integer set;
+{
+ integer s;
+ char separator[2];
+
+ separator[0] = '\0';
+ for (s = 1; s < sizeof(signames) div sizeof(signames[0]); s++) {
+ if (set & setrep(s)) {
+ if (signames[s] != nil) {
+ printf("%s%s", separator, signames[s]);
+ separator[0] = ' ';
+ separator[1] = '\0';
+ }
+ }
+ }
+ if (separator[0] == ' ') {
+ putchar('\n');
+ }
+}