xref: /csrg-svn/old/dbx/process.c (revision 16931)
19677Slinton /* Copyright (c) 1982 Regents of the University of California */
29677Slinton 
3*16931Ssam static	char sccsid[] = "@(#)process.c	1.15 (Berkeley) 08/12/84";
49677Slinton 
59677Slinton /*
69677Slinton  * Process management.
79677Slinton  *
89677Slinton  * This module contains the routines to manage the execution and
99677Slinton  * tracing of the debuggee process.
109677Slinton  */
119677Slinton 
129677Slinton #include "defs.h"
139677Slinton #include "process.h"
149677Slinton #include "machine.h"
159677Slinton #include "events.h"
169677Slinton #include "tree.h"
1714757Slinton #include "eval.h"
189677Slinton #include "operators.h"
199677Slinton #include "source.h"
209677Slinton #include "object.h"
219677Slinton #include "mappings.h"
229677Slinton #include "main.h"
239677Slinton #include "coredump.h"
249677Slinton #include <signal.h>
259677Slinton #include <errno.h>
269677Slinton #include <sys/param.h>
2716617Ssam #include <sys/dir.h>
2816617Ssam #include <sys/user.h>
299843Slinton #include <machine/reg.h>
309677Slinton #include <sys/stat.h>
319677Slinton 
329677Slinton #ifndef public
339677Slinton 
349677Slinton typedef struct Process *Process;
359677Slinton 
369677Slinton Process process;
379677Slinton 
3814757Slinton #define DEFSIG -1
3914757Slinton 
409677Slinton #include "machine.h"
419677Slinton 
429677Slinton #endif
439677Slinton 
449677Slinton #define NOTSTARTED 1
459677Slinton #define STOPPED 0177
469677Slinton #define FINISHED 0
479677Slinton 
489677Slinton /*
4916617Ssam  * A cache of the instruction segment is kept to reduce the number
5016617Ssam  * of system calls.  Might be better just to read the entire
5116617Ssam  * code space into memory.
529677Slinton  */
539677Slinton 
549677Slinton #define CSIZE 1003       /* size of instruction cache */
559677Slinton 
569677Slinton typedef struct {
579677Slinton     Word addr;
589677Slinton     Word val;
599677Slinton } CacheWord;
609677Slinton 
619677Slinton /*
629677Slinton  * This structure holds the information we need from the user structure.
639677Slinton  */
649677Slinton 
659677Slinton struct Process {
669677Slinton     int pid;			/* process being traced */
6711768Slinton     int mask;			/* process status word */
6811768Slinton     Word reg[NREG];		/* process' registers */
699677Slinton     Word oreg[NREG];		/* registers when process last stopped */
709677Slinton     short status;		/* either STOPPED or FINISHED */
719677Slinton     short signo;		/* signal that stopped process */
72*16931Ssam     short sigcode;		/* auxiliary signal info code */
739677Slinton     int exitval;		/* return value from exit() */
749677Slinton     long sigset;		/* bit array of traced signals */
759677Slinton     CacheWord word[CSIZE];	/* text segment cache */
7611768Slinton     Ttyinfo ttyinfo;		/* process' terminal characteristics */
7716617Ssam     Address sigstatus;		/* process' handler for current signal */
789677Slinton };
799677Slinton 
809677Slinton /*
819677Slinton  * These definitions are for the arguments to "pio".
829677Slinton  */
839677Slinton 
849677Slinton typedef enum { PREAD, PWRITE } PioOp;
859677Slinton typedef enum { TEXTSEG, DATASEG } PioSeg;
869677Slinton 
879677Slinton private struct Process pbuf;
889677Slinton 
8913841Slinton #define MAXNCMDARGS 100         /* maximum number of arguments to RUN */
909677Slinton 
9114395Slinton extern int errno;
9214395Slinton 
939677Slinton private Boolean just_started;
949677Slinton private int argc;
959677Slinton private String argv[MAXNCMDARGS];
969677Slinton private String infile, outfile;
979677Slinton 
989677Slinton /*
999677Slinton  * Initialize process information.
1009677Slinton  */
1019677Slinton 
1029677Slinton public process_init()
1039677Slinton {
1049677Slinton     register Integer i;
1059677Slinton     Char buf[10];
1069677Slinton 
1079677Slinton     process = &pbuf;
1089677Slinton     process->status = (coredump) ? STOPPED : NOTSTARTED;
1099677Slinton     setsigtrace();
1109677Slinton     for (i = 0; i < NREG; i++) {
1119677Slinton 	sprintf(buf, "$r%d", i);
1129677Slinton 	defregname(identname(buf, false), i);
1139677Slinton     }
1149677Slinton     defregname(identname("$ap", true), ARGP);
1159677Slinton     defregname(identname("$fp", true), FRP);
1169677Slinton     defregname(identname("$sp", true), STKP);
1179677Slinton     defregname(identname("$pc", true), PROGCTR);
1189677Slinton     if (coredump) {
1199677Slinton 	coredump_readin(process->mask, process->reg, process->signo);
12012484Slinton 	pc = process->reg[PROGCTR];
12112484Slinton 	getsrcpos();
1229677Slinton     }
12312484Slinton     arginit();
1249677Slinton }
1259677Slinton 
1269677Slinton /*
1279677Slinton  * Routines to get at process information from outside this module.
1289677Slinton  */
1299677Slinton 
1309677Slinton public Word reg(n)
1319677Slinton Integer n;
1329677Slinton {
1339677Slinton     register Word w;
1349677Slinton 
1359677Slinton     if (n == NREG) {
1369677Slinton 	w = process->mask;
1379677Slinton     } else {
1389677Slinton 	w = process->reg[n];
1399677Slinton     }
1409677Slinton     return w;
1419677Slinton }
1429677Slinton 
1439677Slinton public setreg(n, w)
1449677Slinton Integer n;
1459677Slinton Word w;
1469677Slinton {
1479677Slinton     process->reg[n] = w;
1489677Slinton }
1499677Slinton 
1509677Slinton /*
1519677Slinton  * Begin execution.
1529677Slinton  *
1539677Slinton  * We set a breakpoint at the end of the code so that the
1549677Slinton  * process data doesn't disappear after the program terminates.
1559677Slinton  */
1569677Slinton 
1579677Slinton private Boolean remade();
1589677Slinton 
1599677Slinton public start(argv, infile, outfile)
1609677Slinton String argv[];
1619677Slinton String infile, outfile;
1629677Slinton {
1639677Slinton     String pargv[4];
1649677Slinton     Node cond;
1659677Slinton 
1669677Slinton     if (coredump) {
1679677Slinton 	coredump = false;
1689677Slinton 	fclose(corefile);
1699677Slinton 	coredump_close();
1709677Slinton     }
1719677Slinton     if (argv == nil) {
1729677Slinton 	argv = pargv;
1739677Slinton 	pargv[0] = objname;
1749677Slinton 	pargv[1] = nil;
1759677Slinton     } else {
1769677Slinton 	argv[argc] = nil;
1779677Slinton     }
1789677Slinton     if (remade(objname)) {
1799677Slinton 	reinit(argv, infile, outfile);
1809677Slinton     }
1819677Slinton     pstart(process, argv, infile, outfile);
1829677Slinton     if (process->status == STOPPED) {
1839677Slinton 	pc = 0;
18416617Ssam 	setcurfunc(program);
1859677Slinton 	if (objsize != 0) {
1869677Slinton 	    cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr()));
1879677Slinton 	    event_once(cond, buildcmdlist(build(O_ENDX)));
1889677Slinton 	}
1899677Slinton     }
1909677Slinton }
1919677Slinton 
1929677Slinton /*
1939677Slinton  * Check to see if the object file has changed since the symbolic
1949677Slinton  * information last was read.
1959677Slinton  */
1969677Slinton 
1979677Slinton private time_t modtime;
1989677Slinton 
1999677Slinton private Boolean remade(filename)
2009677Slinton String filename;
2019677Slinton {
2029677Slinton     struct stat s;
2039677Slinton     Boolean b;
2049677Slinton 
2059677Slinton     stat(filename, &s);
2069677Slinton     b = (Boolean) (modtime != 0 and modtime < s.st_mtime);
2079677Slinton     modtime = s.st_mtime;
2089677Slinton     return b;
2099677Slinton }
2109677Slinton 
2119677Slinton /*
2129677Slinton  * Set up what signals we want to trace.
2139677Slinton  */
2149677Slinton 
2159677Slinton private setsigtrace()
2169677Slinton {
2179677Slinton     register Integer i;
2189677Slinton     register Process p;
2199677Slinton 
2209677Slinton     p = process;
2219677Slinton     for (i = 1; i <= NSIG; i++) {
2229677Slinton 	psigtrace(p, i, true);
2239677Slinton     }
2249677Slinton     psigtrace(p, SIGHUP, false);
2259677Slinton     psigtrace(p, SIGKILL, false);
2269677Slinton     psigtrace(p, SIGALRM, false);
2279677Slinton     psigtrace(p, SIGTSTP, false);
2289677Slinton     psigtrace(p, SIGCONT, false);
2299677Slinton     psigtrace(p, SIGCHLD, false);
2309677Slinton }
2319677Slinton 
2329677Slinton /*
2339677Slinton  * Initialize the argument list.
2349677Slinton  */
2359677Slinton 
2369677Slinton public arginit()
2379677Slinton {
2389677Slinton     infile = nil;
2399677Slinton     outfile = nil;
2409677Slinton     argv[0] = objname;
2419677Slinton     argc = 1;
2429677Slinton }
2439677Slinton 
2449677Slinton /*
2459677Slinton  * Add an argument to the list for the debuggee.
2469677Slinton  */
2479677Slinton 
2489677Slinton public newarg(arg)
2499677Slinton String arg;
2509677Slinton {
2519677Slinton     if (argc >= MAXNCMDARGS) {
2529677Slinton 	error("too many arguments");
2539677Slinton     }
2549677Slinton     argv[argc++] = arg;
2559677Slinton }
2569677Slinton 
2579677Slinton /*
2589677Slinton  * Set the standard input for the debuggee.
2599677Slinton  */
2609677Slinton 
2619677Slinton public inarg(filename)
2629677Slinton String filename;
2639677Slinton {
2649677Slinton     if (infile != nil) {
2659677Slinton 	error("multiple input redirects");
2669677Slinton     }
2679677Slinton     infile = filename;
2689677Slinton }
2699677Slinton 
2709677Slinton /*
2719677Slinton  * Set the standard output for the debuggee.
2729677Slinton  * Probably should check to avoid overwriting an existing file.
2739677Slinton  */
2749677Slinton 
2759677Slinton public outarg(filename)
2769677Slinton String filename;
2779677Slinton {
2789677Slinton     if (outfile != nil) {
2799677Slinton 	error("multiple output redirect");
2809677Slinton     }
2819677Slinton     outfile = filename;
2829677Slinton }
2839677Slinton 
2849677Slinton /*
2859677Slinton  * Start debuggee executing.
2869677Slinton  */
2879677Slinton 
2889677Slinton public run()
2899677Slinton {
2909677Slinton     process->status = STOPPED;
2919677Slinton     fixbps();
2929677Slinton     curline = 0;
2939677Slinton     start(argv, infile, outfile);
2949677Slinton     just_started = true;
2959677Slinton     isstopped = false;
29614757Slinton     cont(0);
2979677Slinton }
2989677Slinton 
2999677Slinton /*
3009677Slinton  * Continue execution wherever we left off.
3019677Slinton  *
3029677Slinton  * Note that this routine never returns.  Eventually bpact() will fail
3039677Slinton  * and we'll call printstatus or step will call it.
3049677Slinton  */
3059677Slinton 
3069677Slinton typedef int Intfunc();
3079677Slinton 
3089677Slinton private Intfunc *dbintr;
3099677Slinton private intr();
3109677Slinton 
3119677Slinton #define succeeds    == true
3129677Slinton #define fails       == false
3139677Slinton 
31411867Slinton public cont(signo)
31516617Ssam integer signo;
3169677Slinton {
31716617Ssam     integer s;
31816617Ssam 
3199677Slinton     dbintr = signal(SIGINT, intr);
3209677Slinton     if (just_started) {
3219677Slinton 	just_started = false;
3229677Slinton     } else {
3239677Slinton 	if (not isstopped) {
3249677Slinton 	    error("can't continue execution");
3259677Slinton 	}
3269677Slinton 	isstopped = false;
32711867Slinton 	stepover();
3289677Slinton     }
32916617Ssam     s = signo;
3309677Slinton     for (;;) {
3319677Slinton 	if (single_stepping) {
3329677Slinton 	    printnews();
3339677Slinton 	} else {
3349677Slinton 	    setallbps();
33516617Ssam 	    resume(s);
3369677Slinton 	    unsetallbps();
33716617Ssam 	    s = DEFSIG;
3389677Slinton 	    if (bpact() fails) {
3399677Slinton 		printstatus();
3409677Slinton 	    }
3419677Slinton 	}
34211867Slinton 	stepover();
3439677Slinton     }
3449677Slinton     /* NOTREACHED */
3459677Slinton }
3469677Slinton 
3479677Slinton /*
3489677Slinton  * This routine is called if we get an interrupt while "running" px
3499677Slinton  * but actually in the debugger.  Could happen, for example, while
3509677Slinton  * processing breakpoints.
3519677Slinton  *
3529677Slinton  * We basically just want to keep going; the assumption is
3539677Slinton  * that when the process resumes it will get the interrupt
3549677Slinton  * which will then be handled.
3559677Slinton  */
3569677Slinton 
3579677Slinton private intr()
3589677Slinton {
3599677Slinton     signal(SIGINT, intr);
3609677Slinton }
3619677Slinton 
3629677Slinton public fixintr()
3639677Slinton {
3649677Slinton     signal(SIGINT, dbintr);
3659677Slinton }
3669677Slinton 
3679677Slinton /*
3689677Slinton  * Resume execution.
3699677Slinton  */
3709677Slinton 
37111867Slinton public resume(signo)
37211867Slinton int signo;
3739677Slinton {
3749677Slinton     register Process p;
3759677Slinton 
3769677Slinton     p = process;
37711867Slinton     pcont(p, signo);
3789677Slinton     pc = process->reg[PROGCTR];
37911832Slinton     if (p->status != STOPPED) {
38011867Slinton 	if (p->signo != 0) {
38111867Slinton 	    error("program terminated by signal %d", p->signo);
38214757Slinton 	} else if (not runfirst) {
38311867Slinton 	    error("program unexpectedly exited with %d", p->exitval);
38411867Slinton 	}
38511832Slinton     }
3869677Slinton }
3879677Slinton 
3889677Slinton /*
3899677Slinton  * Continue execution up to the next source line.
3909677Slinton  *
3919677Slinton  * There are two ways to define the next source line depending on what
3929677Slinton  * is desired when a procedure or function call is encountered.  Step
3939677Slinton  * stops at the beginning of the procedure or call; next skips over it.
3949677Slinton  */
3959677Slinton 
3969677Slinton /*
3979677Slinton  * Stepc is what is called when the step command is given.
3989677Slinton  * It has to play with the "isstopped" information.
3999677Slinton  */
4009677Slinton 
4019677Slinton public stepc()
4029677Slinton {
4039677Slinton     if (not isstopped) {
4049677Slinton 	error("can't continue execution");
4059677Slinton     }
4069677Slinton     isstopped = false;
4079677Slinton     dostep(false);
4089677Slinton     isstopped = true;
4099677Slinton }
4109677Slinton 
4119677Slinton public next()
4129677Slinton {
41316617Ssam     Address oldfrp, newfrp;
41416617Ssam 
4159677Slinton     if (not isstopped) {
4169677Slinton 	error("can't continue execution");
4179677Slinton     }
4189677Slinton     isstopped = false;
41916617Ssam     oldfrp = reg(FRP);
42016617Ssam     do {
42116617Ssam 	dostep(true);
42216617Ssam 	pc = reg(PROGCTR);
42316617Ssam 	newfrp = reg(FRP);
42416617Ssam     } while (newfrp < oldfrp and newfrp != 0);
4259677Slinton     isstopped = true;
4269677Slinton }
4279677Slinton 
42811867Slinton /*
42916617Ssam  * Continue execution until the current function returns, or,
43016617Ssam  * if the given argument is non-nil, until execution returns to
43116617Ssam  * somewhere within the given function.
43216617Ssam  */
43316617Ssam 
43416617Ssam public rtnfunc (f)
43516617Ssam Symbol f;
43616617Ssam {
43716617Ssam     Address addr;
43816617Ssam     Symbol t;
43916617Ssam 
44016617Ssam     if (not isstopped) {
44116617Ssam 	error("can't continue execution");
44216617Ssam     } else if (f != nil and not isactive(f)) {
44316617Ssam 	error("%s is not active", symname(f));
44416617Ssam     } else {
44516617Ssam 	addr = return_addr();
44616617Ssam 	if (addr == nil) {
44716617Ssam 	    error("no place to return to");
44816617Ssam 	} else {
44916617Ssam 	    isstopped = false;
45016617Ssam 	    contto(addr);
45116617Ssam 	    if (f != nil) {
45216617Ssam 		for (;;) {
45316617Ssam 		    t = whatblock(pc);
45416617Ssam 		    addr = return_addr();
45516617Ssam 		if (t == f or addr == nil) break;
45616617Ssam 		    contto(addr);
45716617Ssam 		}
45816617Ssam 	    }
45916617Ssam 	    if (bpact() fails) {
46016617Ssam 		isstopped = true;
46116617Ssam 		printstatus();
46216617Ssam 	    }
46316617Ssam 	}
46416617Ssam     }
46516617Ssam }
46616617Ssam 
46716617Ssam /*
46811867Slinton  * Single-step over the current machine instruction.
46911867Slinton  *
47011867Slinton  * If we're single-stepping by source line we want to step to the
47111867Slinton  * next source line.  Otherwise we're going to continue so there's
47211867Slinton  * no reason to do all the work necessary to single-step to the next
47311867Slinton  * source line.
47411867Slinton  */
47511867Slinton 
47616617Ssam public stepover()
4779677Slinton {
47811867Slinton     Boolean b;
47911867Slinton 
48016617Ssam     if (traceexec) {
48116617Ssam 	printf("!! stepping over 0x%x\n", process->reg[PROGCTR]);
48216617Ssam     }
48311867Slinton     if (single_stepping) {
48411867Slinton 	dostep(false);
48511867Slinton     } else {
48611867Slinton 	b = inst_tracing;
48711867Slinton 	inst_tracing = true;
48811867Slinton 	dostep(false);
48911867Slinton 	inst_tracing = b;
49011867Slinton     }
49116617Ssam     if (traceexec) {
49216617Ssam 	printf("!! stepped over to 0x%x\n", process->reg[PROGCTR]);
49316617Ssam     }
4949677Slinton }
4959677Slinton 
4969677Slinton /*
4979677Slinton  * Resume execution up to the given address.  It is assumed that
4989677Slinton  * no breakpoints exist between the current address and the one
4999677Slinton  * we're stepping to.  This saves us from setting all the breakpoints.
5009677Slinton  */
5019677Slinton 
5029677Slinton public stepto(addr)
5039677Slinton Address addr;
5049677Slinton {
50516617Ssam     xto(addr, false);
50616617Ssam }
50716617Ssam 
50816617Ssam private contto (addr)
50916617Ssam Address addr;
51016617Ssam {
51116617Ssam     xto(addr, true);
51216617Ssam }
51316617Ssam 
51416617Ssam private xto (addr, catchbps)
51516617Ssam Address addr;
51616617Ssam boolean catchbps;
51716617Ssam {
51816617Ssam     Address curpc;
51916617Ssam 
52016617Ssam     if (catchbps) {
52116617Ssam 	stepover();
5229677Slinton     }
52316617Ssam     curpc = process->reg[PROGCTR];
52416617Ssam     if (addr != curpc) {
52516617Ssam 	if (traceexec) {
52616617Ssam 	    printf("!! stepping from 0x%x to 0x%x\n", curpc, addr);
52716617Ssam 	}
52816617Ssam 	if (catchbps) {
52916617Ssam 	    setallbps();
53016617Ssam 	}
53116617Ssam 	setbp(addr);
53216617Ssam 	resume(DEFSIG);
53316617Ssam 	unsetbp(addr);
53416617Ssam 	if (catchbps) {
53516617Ssam 	    unsetallbps();
53616617Ssam 	}
53716617Ssam 	if (not isbperr()) {
53816617Ssam 	    printstatus();
53916617Ssam 	}
54016617Ssam     }
5419677Slinton }
5429677Slinton 
5439677Slinton /*
5449677Slinton  * Print the status of the process.
5459677Slinton  * This routine does not return.
5469677Slinton  */
5479677Slinton 
5489677Slinton public printstatus()
5499677Slinton {
55014395Slinton     int status;
55114395Slinton 
5529843Slinton     if (process->status == FINISHED) {
5539843Slinton 	exit(0);
5549843Slinton     } else {
55516617Ssam 	setcurfunc(whatblock(pc));
5569677Slinton 	getsrcpos();
5579843Slinton 	if (process->signo == SIGINT) {
5589843Slinton 	    isstopped = true;
5599843Slinton 	    printerror();
5609843Slinton 	} else if (isbperr() and isstopped) {
5619843Slinton 	    printf("stopped ");
56211172Slinton 	    printloc();
56311172Slinton 	    putchar('\n');
5649843Slinton 	    if (curline > 0) {
5659843Slinton 		printlines(curline, curline);
5669843Slinton 	    } else {
5679843Slinton 		printinst(pc, pc);
5689843Slinton 	    }
5699843Slinton 	    erecover();
5709677Slinton 	} else {
5719843Slinton 	    fixintr();
5729677Slinton 	    isstopped = true;
5739677Slinton 	    printerror();
5749677Slinton 	}
5759677Slinton     }
5769677Slinton }
5779677Slinton 
5789677Slinton /*
57911172Slinton  * Print out the current location in the debuggee.
58011172Slinton  */
58111172Slinton 
58211172Slinton public printloc()
58311172Slinton {
58411172Slinton     printf("in ");
58511172Slinton     printname(stdout, curfunc);
58611172Slinton     putchar(' ');
58714757Slinton     if (curline > 0 and not useInstLoc) {
58811172Slinton 	printsrcpos();
58911172Slinton     } else {
59014757Slinton 	useInstLoc = false;
59114757Slinton 	curline = 0;
59211172Slinton 	printf("at 0x%x", pc);
59311172Slinton     }
59411172Slinton }
59511172Slinton 
59611172Slinton /*
5979677Slinton  * Some functions for testing the state of the process.
5989677Slinton  */
5999677Slinton 
6009677Slinton public Boolean notstarted(p)
6019677Slinton Process p;
6029677Slinton {
6039677Slinton     return (Boolean) (p->status == NOTSTARTED);
6049677Slinton }
6059677Slinton 
6069677Slinton public Boolean isfinished(p)
6079677Slinton Process p;
6089677Slinton {
6099677Slinton     return (Boolean) (p->status == FINISHED);
6109677Slinton }
6119677Slinton 
6129677Slinton /*
6139677Slinton  * Return the signal number which stopped the process.
6149677Slinton  */
6159677Slinton 
6169677Slinton public Integer errnum(p)
6179677Slinton Process p;
6189677Slinton {
6199677Slinton     return p->signo;
6209677Slinton }
6219677Slinton 
622*16931Ssam public Integer errcode(p)
623*16931Ssam Process p;
624*16931Ssam {
625*16931Ssam     return p->sigcode;
626*16931Ssam }
627*16931Ssam 
6289677Slinton /*
6299677Slinton  * Return the termination code of the process.
6309677Slinton  */
6319677Slinton 
6329677Slinton public Integer exitcode(p)
6339677Slinton Process p;
6349677Slinton {
6359677Slinton     return p->exitval;
6369677Slinton }
6379677Slinton 
6389677Slinton /*
6399677Slinton  * These routines are used to access the debuggee process from
6409677Slinton  * outside this module.
6419677Slinton  *
6429677Slinton  * They invoke "pio" which eventually leads to a call to "ptrace".
64314757Slinton  * The system generates an I/O error when a ptrace fails.  During reads
64414757Slinton  * these are ignored, during writes they are reported as an error, and
64514757Slinton  * for anything else they cause a fatal error.
6469677Slinton  */
6479677Slinton 
6489677Slinton extern Intfunc *onsyserr();
6499677Slinton 
6509677Slinton private badaddr;
65114757Slinton private read_err(), write_err();
6529677Slinton 
6539677Slinton /*
6549677Slinton  * Read from the process' instruction area.
6559677Slinton  */
6569677Slinton 
6579677Slinton public iread(buff, addr, nbytes)
6589677Slinton char *buff;
6599677Slinton Address addr;
6609677Slinton int nbytes;
6619677Slinton {
6629677Slinton     Intfunc *f;
6639677Slinton 
66414757Slinton     f = onsyserr(EIO, read_err);
6659677Slinton     badaddr = addr;
6669677Slinton     if (coredump) {
6679677Slinton 	coredump_readtext(buff, addr, nbytes);
6689677Slinton     } else {
6699677Slinton 	pio(process, PREAD, TEXTSEG, buff, addr, nbytes);
6709677Slinton     }
6719677Slinton     onsyserr(EIO, f);
6729677Slinton }
6739677Slinton 
6749677Slinton /*
6759677Slinton  * Write to the process' instruction area, usually in order to set
6769677Slinton  * or unset a breakpoint.
6779677Slinton  */
6789677Slinton 
6799677Slinton public iwrite(buff, addr, nbytes)
6809677Slinton char *buff;
6819677Slinton Address addr;
6829677Slinton int nbytes;
6839677Slinton {
6849677Slinton     Intfunc *f;
6859677Slinton 
6869677Slinton     if (coredump) {
6879677Slinton 	error("no process to write to");
6889677Slinton     }
68914757Slinton     f = onsyserr(EIO, write_err);
6909677Slinton     badaddr = addr;
6919677Slinton     pio(process, PWRITE, TEXTSEG, buff, addr, nbytes);
6929677Slinton     onsyserr(EIO, f);
6939677Slinton }
6949677Slinton 
6959677Slinton /*
6969677Slinton  * Read for the process' data area.
6979677Slinton  */
6989677Slinton 
6999677Slinton public dread(buff, addr, nbytes)
7009677Slinton char *buff;
7019677Slinton Address addr;
7029677Slinton int nbytes;
7039677Slinton {
7049677Slinton     Intfunc *f;
7059677Slinton 
70614757Slinton     f = onsyserr(EIO, read_err);
7079677Slinton     badaddr = addr;
7089677Slinton     if (coredump) {
7099677Slinton 	coredump_readdata(buff, addr, nbytes);
7109677Slinton     } else {
7119677Slinton 	pio(process, PREAD, DATASEG, buff, addr, nbytes);
7129677Slinton     }
7139677Slinton     onsyserr(EIO, f);
7149677Slinton }
7159677Slinton 
7169677Slinton /*
7179677Slinton  * Write to the process' data area.
7189677Slinton  */
7199677Slinton 
7209677Slinton public dwrite(buff, addr, nbytes)
7219677Slinton char *buff;
7229677Slinton Address addr;
7239677Slinton int nbytes;
7249677Slinton {
7259677Slinton     Intfunc *f;
7269677Slinton 
7279677Slinton     if (coredump) {
7289677Slinton 	error("no process to write to");
7299677Slinton     }
73014757Slinton     f = onsyserr(EIO, write_err);
7319677Slinton     badaddr = addr;
7329677Slinton     pio(process, PWRITE, DATASEG, buff, addr, nbytes);
7339677Slinton     onsyserr(EIO, f);
7349677Slinton }
7359677Slinton 
7369677Slinton /*
73714757Slinton  * Trap for errors in reading or writing to a process.
73814757Slinton  * The current approach is to "ignore" read errors and complain
73914757Slinton  * bitterly about write errors.
7409677Slinton  */
7419677Slinton 
74214757Slinton private read_err()
7439677Slinton {
74411560Slinton     /*
74514757Slinton      * Ignore.
74611560Slinton      */
7479677Slinton }
7489677Slinton 
74914757Slinton private write_err()
75014757Slinton {
75114757Slinton     error("can't write to process (address 0x%x)", badaddr);
75214757Slinton }
75314757Slinton 
7549677Slinton /*
7559677Slinton  * Ptrace interface.
7569677Slinton  */
7579677Slinton 
7589677Slinton /*
7599677Slinton  * This magic macro enables us to look at the process' registers
76014757Slinton  * in its user structure.
7619677Slinton  */
7629677Slinton 
7639677Slinton #define regloc(reg)     (ctob(UPAGES) + ( sizeof(int) * (reg) ))
7649677Slinton 
7659677Slinton #define WMASK           (~(sizeof(Word) - 1))
7669677Slinton #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE))
7679677Slinton 
7689677Slinton #define FIRSTSIG        SIGINT
7699677Slinton #define LASTSIG         SIGQUIT
7709677Slinton #define ischild(pid)    ((pid) == 0)
7719677Slinton #define traceme()       ptrace(0, 0, 0, 0)
7729677Slinton #define setrep(n)       (1 << ((n)-1))
7739677Slinton #define istraced(p)     (p->sigset&setrep(p->signo))
7749677Slinton 
7759677Slinton /*
7769677Slinton  * Ptrace options (specified in first argument).
7779677Slinton  */
7789677Slinton 
7799677Slinton #define UREAD   3       /* read from process's user structure */
7809677Slinton #define UWRITE  6       /* write to process's user structure */
7819677Slinton #define IREAD   1       /* read from process's instruction space */
7829677Slinton #define IWRITE  4       /* write to process's instruction space */
7839677Slinton #define DREAD   2       /* read from process's data space */
7849677Slinton #define DWRITE  5       /* write to process's data space */
7859677Slinton #define CONT    7       /* continue stopped process */
7869677Slinton #define SSTEP   9       /* continue for approximately one instruction */
7879677Slinton #define PKILL   8       /* terminate the process */
7889677Slinton 
7899677Slinton /*
7909677Slinton  * Start up a new process by forking and exec-ing the
7919677Slinton  * given argument list, returning when the process is loaded
7929677Slinton  * and ready to execute.  The PROCESS information (pointed to
7939677Slinton  * by the first argument) is appropriately filled.
7949677Slinton  *
7959677Slinton  * If the given PROCESS structure is associated with an already running
7969677Slinton  * process, we terminate it.
7979677Slinton  */
7989677Slinton 
7999677Slinton /* VARARGS2 */
8009677Slinton private pstart(p, argv, infile, outfile)
8019677Slinton Process p;
8029677Slinton String argv[];
8039677Slinton String infile;
8049677Slinton String outfile;
8059677Slinton {
8069677Slinton     int status;
8079677Slinton 
80816617Ssam     if (p->pid != 0) {
80916617Ssam 	pterm(p);
8109677Slinton     }
8119677Slinton     psigtrace(p, SIGTRAP, true);
81214395Slinton     p->pid = vfork();
81314395Slinton     if (p->pid == -1) {
8149677Slinton 	panic("can't fork");
8159677Slinton     }
8169677Slinton     if (ischild(p->pid)) {
8179677Slinton 	traceme();
8189677Slinton 	if (infile != nil) {
81916617Ssam 	    infrom(infile);
8209677Slinton 	}
8219677Slinton 	if (outfile != nil) {
82216617Ssam 	    outto(outfile);
8239677Slinton 	}
82411832Slinton 	execv(argv[0], argv);
82511172Slinton 	write(2, "can't exec ", 11);
82611172Slinton 	write(2, argv[0], strlen(argv[0]));
82711172Slinton 	write(2, "\n", 1);
82811172Slinton 	_exit(1);
8299677Slinton     }
8309677Slinton     pwait(p->pid, &status);
8319677Slinton     getinfo(p, status);
8329677Slinton     if (p->status != STOPPED) {
8339677Slinton 	error("program could not begin execution");
8349677Slinton     }
83514395Slinton     ptraced(p->pid);
8369677Slinton }
8379677Slinton 
8389677Slinton /*
83916617Ssam  * Terminate a ptrace'd process.
84016617Ssam  */
84116617Ssam 
84216617Ssam public pterm (p)
84316617Ssam Process p;
84416617Ssam {
84516617Ssam     integer status;
84616617Ssam 
84716617Ssam     if (p != nil and p->pid != 0) {
84816617Ssam 	ptrace(PKILL, p->pid, 0, 0);
84916617Ssam 	pwait(p->pid, &status);
85016617Ssam 	unptraced(p->pid);
85116617Ssam     }
85216617Ssam }
85316617Ssam 
85416617Ssam /*
85511867Slinton  * Continue a stopped process.  The first argument points to a Process
85611867Slinton  * structure.  Before the process is restarted it's user area is modified
85711867Slinton  * according to the values in the structure.  When this routine finishes,
8589677Slinton  * the structure has the new values from the process's user area.
8599677Slinton  *
8609677Slinton  * Pcont terminates when the process stops with a signal pending that
8619677Slinton  * is being traced (via psigtrace), or when the process terminates.
8629677Slinton  */
8639677Slinton 
86411867Slinton private pcont(p, signo)
8659677Slinton Process p;
86611867Slinton int signo;
8679677Slinton {
86816617Ssam     int s, status;
8699677Slinton 
8709677Slinton     if (p->pid == 0) {
8719677Slinton 	error("program not active");
8729677Slinton     }
87316617Ssam     s = signo;
8749677Slinton     do {
87516617Ssam 	setinfo(p, s);
87616617Ssam 	if (traceexec) {
87716617Ssam 	    printf("!! pcont from 0x%x with signal %d (%d)\n",
87816617Ssam 		p->reg[PROGCTR], s, p->signo);
87916617Ssam 	    fflush(stdout);
88016617Ssam 	}
8819677Slinton 	sigs_off();
8829677Slinton 	if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) {
88314395Slinton 	    panic("error %d trying to continue process", errno);
8849677Slinton 	}
8859677Slinton 	pwait(p->pid, &status);
8869677Slinton 	sigs_on();
8879677Slinton 	getinfo(p, status);
88816617Ssam 	if (traceexec and not istraced(p)) {
88916617Ssam 	    printf("!! ignored signal %d at 0x%x\n", p->signo, p->reg[PROGCTR]);
89016617Ssam 	    fflush(stdout);
89116617Ssam 	}
89216617Ssam 	s = p->signo;
8939677Slinton     } while (p->status == STOPPED and not istraced(p));
89416617Ssam     if (traceexec) {
89516617Ssam 	printf("!! pcont to 0x%x on signal %d\n", p->reg[PROGCTR], p->signo);
89616617Ssam 	fflush(stdout);
89716617Ssam     }
8989677Slinton }
8999677Slinton 
9009677Slinton /*
9019677Slinton  * Single step as best ptrace can.
9029677Slinton  */
9039677Slinton 
90416617Ssam public pstep(p, signo)
9059677Slinton Process p;
90616617Ssam integer signo;
9079677Slinton {
9089677Slinton     int status;
9099677Slinton 
91016617Ssam     setinfo(p, signo);
91116617Ssam     if (traceexec) {
91216617Ssam 	printf("!! pstep from pc 0x%x with signal %d (%d)\n",
91316617Ssam 	    p->reg[PROGCTR], signo, p->signo);
91416617Ssam 	fflush(stdout);
91516617Ssam     }
9169677Slinton     sigs_off();
91716617Ssam     if (ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo) < 0) {
91816617Ssam 	panic("error %d trying to step process", errno);
91916617Ssam     }
9209677Slinton     pwait(p->pid, &status);
9219677Slinton     sigs_on();
9229677Slinton     getinfo(p, status);
92316617Ssam     if (traceexec) {
92416617Ssam 	printf("!! pstep to pc 0x%x on signal %d\n", p->reg[PROGCTR], p->signo);
92516617Ssam 	fflush(stdout);
92616617Ssam     }
92716617Ssam     if (p->status != STOPPED) {
92816617Ssam 	error("program unexpectedly exited with %d\n", p->exitval);
92916617Ssam     }
9309677Slinton }
9319677Slinton 
9329677Slinton /*
9339677Slinton  * Return from execution when the given signal is pending.
9349677Slinton  */
9359677Slinton 
9369677Slinton public psigtrace(p, sig, sw)
9379677Slinton Process p;
9389677Slinton int sig;
9399677Slinton Boolean sw;
9409677Slinton {
9419677Slinton     if (sw) {
9429677Slinton 	p->sigset |= setrep(sig);
9439677Slinton     } else {
9449677Slinton 	p->sigset &= ~setrep(sig);
9459677Slinton     }
9469677Slinton }
9479677Slinton 
9489677Slinton /*
9499677Slinton  * Don't catch any signals.
9509677Slinton  * Particularly useful when letting a process finish uninhibited.
9519677Slinton  */
9529677Slinton 
9539677Slinton public unsetsigtraces(p)
9549677Slinton Process p;
9559677Slinton {
9569677Slinton     p->sigset = 0;
9579677Slinton }
9589677Slinton 
9599677Slinton /*
9609677Slinton  * Turn off attention to signals not being caught.
9619677Slinton  */
9629677Slinton 
9639677Slinton private Intfunc *sigfunc[NSIG];
9649677Slinton 
9659677Slinton private sigs_off()
9669677Slinton {
9679677Slinton     register int i;
9689677Slinton 
9699677Slinton     for (i = FIRSTSIG; i < LASTSIG; i++) {
9709677Slinton 	if (i != SIGKILL) {
9719677Slinton 	    sigfunc[i] = signal(i, SIG_IGN);
9729677Slinton 	}
9739677Slinton     }
9749677Slinton }
9759677Slinton 
9769677Slinton /*
9779677Slinton  * Turn back on attention to signals.
9789677Slinton  */
9799677Slinton 
9809677Slinton private sigs_on()
9819677Slinton {
9829677Slinton     register int i;
9839677Slinton 
9849677Slinton     for (i = FIRSTSIG; i < LASTSIG; i++) {
9859677Slinton 	if (i != SIGKILL) {
9869677Slinton 	    signal(i, sigfunc[i]);
9879677Slinton 	}
9889677Slinton     }
9899677Slinton }
9909677Slinton 
9919677Slinton /*
9929677Slinton  * Get process information from user area.
9939677Slinton  */
9949677Slinton 
9959677Slinton private int rloc[] ={
9969677Slinton     R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, AP, FP, SP, PC
9979677Slinton };
9989677Slinton 
9999677Slinton private getinfo(p, status)
10009677Slinton register Process p;
10019677Slinton register int status;
10029677Slinton {
10039677Slinton     register int i;
100416617Ssam     Address addr;
10059677Slinton 
10069677Slinton     p->signo = (status&0177);
10079677Slinton     p->exitval = ((status >> 8)&0377);
10089677Slinton     if (p->signo != STOPPED) {
10099677Slinton 	p->status = FINISHED;
101014757Slinton 	p->pid = 0;
101116617Ssam 	p->reg[PROGCTR] = 0;
10129677Slinton     } else {
10139677Slinton 	p->status = p->signo;
10149677Slinton 	p->signo = p->exitval;
1015*16931Ssam 	p->sigcode = ptrace(UREAD, p->pid, &((struct user *)0)->u_code, 0);
10169677Slinton 	p->exitval = 0;
10179677Slinton 	p->mask = ptrace(UREAD, p->pid, regloc(PS), 0);
10189677Slinton 	for (i = 0; i < NREG; i++) {
10199677Slinton 	    p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0);
10209677Slinton 	    p->oreg[i] = p->reg[i];
10219677Slinton 	}
102211768Slinton 	savetty(stdout, &(p->ttyinfo));
102316617Ssam 	addr = (Address) &(((struct user *) 0)->u_signal[p->signo]);
102416617Ssam 	p->sigstatus = (Address) ptrace(UREAD, p->pid, addr, 0);
10259677Slinton     }
10269677Slinton }
10279677Slinton 
10289677Slinton /*
10299677Slinton  * Set process's user area information from given process structure.
10309677Slinton  */
10319677Slinton 
103211867Slinton private setinfo(p, signo)
10339677Slinton register Process p;
103411867Slinton int signo;
10359677Slinton {
10369677Slinton     register int i;
10379677Slinton     register int r;
10389677Slinton 
103914757Slinton     if (signo == DEFSIG) {
104016617Ssam 	if (istraced(p) and (p->sigstatus == 0 or p->sigstatus == 1)) {
104114757Slinton 	    p->signo = 0;
104214757Slinton 	}
104314757Slinton     } else {
104411867Slinton 	p->signo = signo;
10459677Slinton     }
10469677Slinton     for (i = 0; i < NREG; i++) {
10479677Slinton 	if ((r = p->reg[i]) != p->oreg[i]) {
10489677Slinton 	    ptrace(UWRITE, p->pid, regloc(rloc[i]), r);
10499677Slinton 	}
10509677Slinton     }
105111768Slinton     restoretty(stdout, &(p->ttyinfo));
10529677Slinton }
10539677Slinton 
10549677Slinton /*
105516617Ssam  * Return the address associated with the current signal.
105616617Ssam  * (Plus two since the address points to the beginning of a procedure).
105716617Ssam  */
105816617Ssam 
105916617Ssam public Address usignal (p)
106016617Ssam Process p;
106116617Ssam {
106216617Ssam     Address r;
106316617Ssam 
106416617Ssam     r = p->sigstatus;
106516617Ssam     if (r != 0 and r != 1) {
106616617Ssam 	r += 2;
106716617Ssam     }
106816617Ssam     return r;
106916617Ssam }
107016617Ssam 
107116617Ssam /*
10729677Slinton  * Structure for reading and writing by words, but dealing with bytes.
10739677Slinton  */
10749677Slinton 
10759677Slinton typedef union {
10769677Slinton     Word pword;
10779677Slinton     Byte pbyte[sizeof(Word)];
10789677Slinton } Pword;
10799677Slinton 
10809677Slinton /*
10819677Slinton  * Read (write) from (to) the process' address space.
10829677Slinton  * We must deal with ptrace's inability to look anywhere other
10839677Slinton  * than at a word boundary.
10849677Slinton  */
10859677Slinton 
10869677Slinton private Word fetch();
10879677Slinton private store();
10889677Slinton 
10899677Slinton private pio(p, op, seg, buff, addr, nbytes)
10909677Slinton Process p;
10919677Slinton PioOp op;
10929677Slinton PioSeg seg;
10939677Slinton char *buff;
10949677Slinton Address addr;
10959677Slinton int nbytes;
10969677Slinton {
10979677Slinton     register int i;
10989677Slinton     register Address newaddr;
10999677Slinton     register char *cp;
11009677Slinton     char *bufend;
11019677Slinton     Pword w;
11029677Slinton     Address wordaddr;
11039677Slinton     int byteoff;
11049677Slinton 
11059677Slinton     if (p->status != STOPPED) {
11069677Slinton 	error("program is not active");
11079677Slinton     }
11089677Slinton     cp = buff;
11099677Slinton     newaddr = addr;
11109677Slinton     wordaddr = (newaddr&WMASK);
11119677Slinton     if (wordaddr != newaddr) {
11129677Slinton 	w.pword = fetch(p, seg, wordaddr);
11139677Slinton 	for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) {
11149677Slinton 	    if (op == PREAD) {
11159677Slinton 		*cp++ = w.pbyte[i];
11169677Slinton 	    } else {
11179677Slinton 		w.pbyte[i] = *cp++;
11189677Slinton 	    }
11199677Slinton 	    nbytes--;
11209677Slinton 	}
11219677Slinton 	if (op == PWRITE) {
11229677Slinton 	    store(p, seg, wordaddr, w.pword);
11239677Slinton 	}
11249677Slinton 	newaddr = wordaddr + sizeof(Word);
11259677Slinton     }
11269677Slinton     byteoff = (nbytes&(~WMASK));
11279677Slinton     nbytes -= byteoff;
11289677Slinton     bufend = cp + nbytes;
11299677Slinton     while (cp < bufend) {
11309677Slinton 	if (op == PREAD) {
11319677Slinton 	    *((Word *) cp) = fetch(p, seg, newaddr);
11329677Slinton 	} else {
11339677Slinton 	    store(p, seg, newaddr, *((Word *) cp));
11349677Slinton 	}
11359677Slinton 	cp += sizeof(Word);
11369677Slinton 	newaddr += sizeof(Word);
11379677Slinton     }
11389677Slinton     if (byteoff > 0) {
11399677Slinton 	w.pword = fetch(p, seg, newaddr);
11409677Slinton 	for (i = 0; i < byteoff; i++) {
11419677Slinton 	    if (op == PREAD) {
11429677Slinton 		*cp++ = w.pbyte[i];
11439677Slinton 	    } else {
11449677Slinton 		w.pbyte[i] = *cp++;
11459677Slinton 	    }
11469677Slinton 	}
11479677Slinton 	if (op == PWRITE) {
11489677Slinton 	    store(p, seg, newaddr, w.pword);
11499677Slinton 	}
11509677Slinton     }
11519677Slinton }
11529677Slinton 
11539677Slinton /*
11549677Slinton  * Get a word from a process at the given address.
11559677Slinton  * The address is assumed to be on a word boundary.
11569677Slinton  *
11579677Slinton  * A simple cache scheme is used to avoid redundant ptrace calls
11589677Slinton  * to the instruction space since it is assumed to be pure.
11599677Slinton  *
11609677Slinton  * It is necessary to use a write-through scheme so that
11619677Slinton  * breakpoints right next to each other don't interfere.
11629677Slinton  */
11639677Slinton 
11649677Slinton private Integer nfetchs, nreads, nwrites;
11659677Slinton 
11669677Slinton private Word fetch(p, seg, addr)
11679677Slinton Process p;
11689677Slinton PioSeg seg;
11699677Slinton register int addr;
11709677Slinton {
11719677Slinton     register CacheWord *wp;
11729677Slinton     register Word w;
11739677Slinton 
11749677Slinton     switch (seg) {
11759677Slinton 	case TEXTSEG:
11769677Slinton 	    ++nfetchs;
11779677Slinton 	    wp = &p->word[cachehash(addr)];
11789677Slinton 	    if (addr == 0 or wp->addr != addr) {
11799677Slinton 		++nreads;
11809677Slinton 		w = ptrace(IREAD, p->pid, addr, 0);
11819677Slinton 		wp->addr = addr;
11829677Slinton 		wp->val = w;
11839677Slinton 	    } else {
11849677Slinton 		w = wp->val;
11859677Slinton 	    }
11869677Slinton 	    break;
11879677Slinton 
11889677Slinton 	case DATASEG:
11899677Slinton 	    w = ptrace(DREAD, p->pid, addr, 0);
11909677Slinton 	    break;
11919677Slinton 
11929677Slinton 	default:
11939677Slinton 	    panic("fetch: bad seg %d", seg);
11949677Slinton 	    /* NOTREACHED */
11959677Slinton     }
11969677Slinton     return w;
11979677Slinton }
11989677Slinton 
11999677Slinton /*
12009677Slinton  * Put a word into the process' address space at the given address.
12019677Slinton  * The address is assumed to be on a word boundary.
12029677Slinton  */
12039677Slinton 
12049677Slinton private store(p, seg, addr, data)
12059677Slinton Process p;
12069677Slinton PioSeg seg;
12079677Slinton int addr;
12089677Slinton Word data;
12099677Slinton {
12109677Slinton     register CacheWord *wp;
12119677Slinton 
12129677Slinton     switch (seg) {
12139677Slinton 	case TEXTSEG:
12149677Slinton 	    ++nwrites;
12159677Slinton 	    wp = &p->word[cachehash(addr)];
12169677Slinton 	    wp->addr = addr;
12179677Slinton 	    wp->val = data;
12189677Slinton 	    ptrace(IWRITE, p->pid, addr, data);
12199677Slinton 	    break;
12209677Slinton 
12219677Slinton 	case DATASEG:
12229677Slinton 	    ptrace(DWRITE, p->pid, addr, data);
12239677Slinton 	    break;
12249677Slinton 
12259677Slinton 	default:
12269677Slinton 	    panic("store: bad seg %d", seg);
12279677Slinton 	    /* NOTREACHED */
12289677Slinton     }
12299677Slinton }
12309677Slinton 
12319677Slinton public printptraceinfo()
12329677Slinton {
12339677Slinton     printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites);
12349677Slinton }
12359677Slinton 
12369677Slinton /*
123716617Ssam  * Redirect input.
123816617Ssam  * Assuming this is called from a child, we should be careful to avoid
123916617Ssam  * (possibly) shared standard I/O buffers.
12409677Slinton  */
12419677Slinton 
124216617Ssam private infrom (filename)
124316617Ssam String filename;
124416617Ssam {
124516617Ssam     Fileid in;
124616617Ssam 
124716617Ssam     in = open(filename, 0);
124816617Ssam     if (in == -1) {
124916617Ssam 	write(2, "can't read ", 11);
125016617Ssam 	write(2, filename, strlen(filename));
125116617Ssam 	write(2, "\n", 1);
125216617Ssam 	_exit(1);
125316617Ssam     }
125416617Ssam     fswap(0, in);
125516617Ssam }
125616617Ssam 
125716617Ssam /*
125816617Ssam  * Redirect standard output.
125916617Ssam  * Same assumptions as for "infrom" above.
126016617Ssam  */
126116617Ssam 
126216617Ssam private outto (filename)
126316617Ssam String filename;
126416617Ssam {
126516617Ssam     Fileid out;
126616617Ssam 
126716617Ssam     out = creat(filename, 0666);
126816617Ssam     if (out == -1) {
126916617Ssam 	write(2, "can't write ", 12);
127016617Ssam 	write(2, filename, strlen(filename));
127116617Ssam 	write(2, "\n", 1);
127216617Ssam 	_exit(1);
127316617Ssam     }
127416617Ssam     fswap(1, out);
127516617Ssam }
127616617Ssam 
127716617Ssam /*
127816617Ssam  * Swap file numbers, useful for redirecting standard input or output.
127916617Ssam  */
128016617Ssam 
12819677Slinton private fswap(oldfd, newfd)
128216617Ssam Fileid oldfd;
128316617Ssam Fileid newfd;
12849677Slinton {
12859677Slinton     if (oldfd != newfd) {
12869677Slinton 	close(oldfd);
12879677Slinton 	dup(newfd);
12889677Slinton 	close(newfd);
12899677Slinton     }
12909677Slinton }
129116928Ssam 
129216928Ssam #define	bit(i)		(1 << ((i)-1))
129316928Ssam /*
129416928Ssam  * Signal manipulation routines.
129516928Ssam  */
129616928Ssam static String signames[NSIG] = {
129716928Ssam 	0,
129816928Ssam 	"HUP",
129916928Ssam 	"INT",
130016928Ssam 	"QUIT",
130116928Ssam 	"ILL",
130216928Ssam 	"TRAP",
130316928Ssam 	"IOT",
130416928Ssam 	"EMT",
130516928Ssam 	"FPE",
130616928Ssam 	"KILL",
130716928Ssam 	"BUS",
130816928Ssam 	"SEGV",
130916928Ssam 	"SYS",
131016928Ssam 	"PIPE",
131116928Ssam 	"ALRM",
131216928Ssam 	"TERM",
131316928Ssam 	0,
131416928Ssam 	"STOP",
131516928Ssam 	"TSTP",
131616928Ssam 	"CONT",
131716928Ssam 	"CHLD",
131816928Ssam 	"TTIN",
131916928Ssam 	"TTOU",
132016928Ssam 	"TINT",
132116928Ssam 	"XCPU",
132216928Ssam 	"XFSZ",
132316928Ssam };
132416928Ssam 
132516928Ssam /*
132616928Ssam  * Map a signal name to a number.
132716928Ssam  */
132816928Ssam public signalname(s)
132916928Ssam String s;
133016928Ssam {
133116928Ssam 	register String *p;
133216928Ssam 
1333*16931Ssam 	if (strneq(s, "SIG", 3))
1334*16931Ssam 	    s += 3;
133516928Ssam 	for (p = signames; p < &signames[NSIG]; p++)
133616928Ssam 		if (*p && streq(*p, s))
133716928Ssam 			return (p - signames);
133816928Ssam 	error("%s: Unknown signal.", s);
133916928Ssam }
134016928Ssam 
134116928Ssam /*
134216928Ssam  * Print all signals being ignored by the
134316928Ssam  * debugger.  These signals are auotmatically
134416928Ssam  * passed on to the debugged process.
134516928Ssam  */
1346*16931Ssam public printsigsignored(p)
1347*16931Ssam Process p;
134816928Ssam {
134916928Ssam 
1350*16931Ssam     printsigs(~p->sigset);
135116928Ssam }
135216928Ssam 
135316928Ssam /*
135416928Ssam  * Print all signals being intercepted by
135516928Ssam  * the debugger for the specified process.
135616928Ssam  */
1357*16931Ssam public printsigscaught(p)
1358*16931Ssam Process p;
135916928Ssam {
136016928Ssam 
1361*16931Ssam     printsigs(p->sigset);
1362*16931Ssam }
1363*16931Ssam 
1364*16931Ssam private printsigs(vec)
1365*16931Ssam register Integer vec;
1366*16931Ssam {
1367*16931Ssam     register Integer s;
1368*16931Ssam     String sep = "";
1369*16931Ssam 
1370*16931Ssam     for (s = 1; s < NSIG; s++)
1371*16931Ssam 	if (vec & bit(s) && signames[s]) {
1372*16931Ssam 	    printf("%s%s", sep, signames[s]);
1373*16931Ssam 	    sep = " ";
137416928Ssam 	}
1375*16931Ssam     if (*sep != '\0') {
1376*16931Ssam 	putchar('\n');
1377*16931Ssam 	fflush(stdout);
1378*16931Ssam     }
137916928Ssam }
1380