xref: /csrg-svn/old/dbx/process.c (revision 16928)
19677Slinton /* Copyright (c) 1982 Regents of the University of California */
29677Slinton 
3*16928Ssam static	char sccsid[] = "@(#)process.c	1.14 (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 */
729677Slinton     int exitval;		/* return value from exit() */
739677Slinton     long sigset;		/* bit array of traced signals */
749677Slinton     CacheWord word[CSIZE];	/* text segment cache */
7511768Slinton     Ttyinfo ttyinfo;		/* process' terminal characteristics */
7616617Ssam     Address sigstatus;		/* process' handler for current signal */
779677Slinton };
789677Slinton 
799677Slinton /*
809677Slinton  * These definitions are for the arguments to "pio".
819677Slinton  */
829677Slinton 
839677Slinton typedef enum { PREAD, PWRITE } PioOp;
849677Slinton typedef enum { TEXTSEG, DATASEG } PioSeg;
859677Slinton 
869677Slinton private struct Process pbuf;
879677Slinton 
8813841Slinton #define MAXNCMDARGS 100         /* maximum number of arguments to RUN */
899677Slinton 
9014395Slinton extern int errno;
9114395Slinton 
929677Slinton private Boolean just_started;
939677Slinton private int argc;
949677Slinton private String argv[MAXNCMDARGS];
959677Slinton private String infile, outfile;
969677Slinton 
979677Slinton /*
989677Slinton  * Initialize process information.
999677Slinton  */
1009677Slinton 
1019677Slinton public process_init()
1029677Slinton {
1039677Slinton     register Integer i;
1049677Slinton     Char buf[10];
1059677Slinton 
1069677Slinton     process = &pbuf;
1079677Slinton     process->status = (coredump) ? STOPPED : NOTSTARTED;
1089677Slinton     setsigtrace();
1099677Slinton     for (i = 0; i < NREG; i++) {
1109677Slinton 	sprintf(buf, "$r%d", i);
1119677Slinton 	defregname(identname(buf, false), i);
1129677Slinton     }
1139677Slinton     defregname(identname("$ap", true), ARGP);
1149677Slinton     defregname(identname("$fp", true), FRP);
1159677Slinton     defregname(identname("$sp", true), STKP);
1169677Slinton     defregname(identname("$pc", true), PROGCTR);
1179677Slinton     if (coredump) {
1189677Slinton 	coredump_readin(process->mask, process->reg, process->signo);
11912484Slinton 	pc = process->reg[PROGCTR];
12012484Slinton 	getsrcpos();
1219677Slinton     }
12212484Slinton     arginit();
1239677Slinton }
1249677Slinton 
1259677Slinton /*
1269677Slinton  * Routines to get at process information from outside this module.
1279677Slinton  */
1289677Slinton 
1299677Slinton public Word reg(n)
1309677Slinton Integer n;
1319677Slinton {
1329677Slinton     register Word w;
1339677Slinton 
1349677Slinton     if (n == NREG) {
1359677Slinton 	w = process->mask;
1369677Slinton     } else {
1379677Slinton 	w = process->reg[n];
1389677Slinton     }
1399677Slinton     return w;
1409677Slinton }
1419677Slinton 
1429677Slinton public setreg(n, w)
1439677Slinton Integer n;
1449677Slinton Word w;
1459677Slinton {
1469677Slinton     process->reg[n] = w;
1479677Slinton }
1489677Slinton 
1499677Slinton /*
1509677Slinton  * Begin execution.
1519677Slinton  *
1529677Slinton  * We set a breakpoint at the end of the code so that the
1539677Slinton  * process data doesn't disappear after the program terminates.
1549677Slinton  */
1559677Slinton 
1569677Slinton private Boolean remade();
1579677Slinton 
1589677Slinton public start(argv, infile, outfile)
1599677Slinton String argv[];
1609677Slinton String infile, outfile;
1619677Slinton {
1629677Slinton     String pargv[4];
1639677Slinton     Node cond;
1649677Slinton 
1659677Slinton     if (coredump) {
1669677Slinton 	coredump = false;
1679677Slinton 	fclose(corefile);
1689677Slinton 	coredump_close();
1699677Slinton     }
1709677Slinton     if (argv == nil) {
1719677Slinton 	argv = pargv;
1729677Slinton 	pargv[0] = objname;
1739677Slinton 	pargv[1] = nil;
1749677Slinton     } else {
1759677Slinton 	argv[argc] = nil;
1769677Slinton     }
1779677Slinton     if (remade(objname)) {
1789677Slinton 	reinit(argv, infile, outfile);
1799677Slinton     }
1809677Slinton     pstart(process, argv, infile, outfile);
1819677Slinton     if (process->status == STOPPED) {
1829677Slinton 	pc = 0;
18316617Ssam 	setcurfunc(program);
1849677Slinton 	if (objsize != 0) {
1859677Slinton 	    cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr()));
1869677Slinton 	    event_once(cond, buildcmdlist(build(O_ENDX)));
1879677Slinton 	}
1889677Slinton     }
1899677Slinton }
1909677Slinton 
1919677Slinton /*
1929677Slinton  * Check to see if the object file has changed since the symbolic
1939677Slinton  * information last was read.
1949677Slinton  */
1959677Slinton 
1969677Slinton private time_t modtime;
1979677Slinton 
1989677Slinton private Boolean remade(filename)
1999677Slinton String filename;
2009677Slinton {
2019677Slinton     struct stat s;
2029677Slinton     Boolean b;
2039677Slinton 
2049677Slinton     stat(filename, &s);
2059677Slinton     b = (Boolean) (modtime != 0 and modtime < s.st_mtime);
2069677Slinton     modtime = s.st_mtime;
2079677Slinton     return b;
2089677Slinton }
2099677Slinton 
2109677Slinton /*
2119677Slinton  * Set up what signals we want to trace.
2129677Slinton  */
2139677Slinton 
2149677Slinton private setsigtrace()
2159677Slinton {
2169677Slinton     register Integer i;
2179677Slinton     register Process p;
2189677Slinton 
2199677Slinton     p = process;
2209677Slinton     for (i = 1; i <= NSIG; i++) {
2219677Slinton 	psigtrace(p, i, true);
2229677Slinton     }
2239677Slinton     psigtrace(p, SIGHUP, false);
2249677Slinton     psigtrace(p, SIGKILL, false);
2259677Slinton     psigtrace(p, SIGALRM, false);
2269677Slinton     psigtrace(p, SIGTSTP, false);
2279677Slinton     psigtrace(p, SIGCONT, false);
2289677Slinton     psigtrace(p, SIGCHLD, false);
2299677Slinton }
2309677Slinton 
2319677Slinton /*
2329677Slinton  * Initialize the argument list.
2339677Slinton  */
2349677Slinton 
2359677Slinton public arginit()
2369677Slinton {
2379677Slinton     infile = nil;
2389677Slinton     outfile = nil;
2399677Slinton     argv[0] = objname;
2409677Slinton     argc = 1;
2419677Slinton }
2429677Slinton 
2439677Slinton /*
2449677Slinton  * Add an argument to the list for the debuggee.
2459677Slinton  */
2469677Slinton 
2479677Slinton public newarg(arg)
2489677Slinton String arg;
2499677Slinton {
2509677Slinton     if (argc >= MAXNCMDARGS) {
2519677Slinton 	error("too many arguments");
2529677Slinton     }
2539677Slinton     argv[argc++] = arg;
2549677Slinton }
2559677Slinton 
2569677Slinton /*
2579677Slinton  * Set the standard input for the debuggee.
2589677Slinton  */
2599677Slinton 
2609677Slinton public inarg(filename)
2619677Slinton String filename;
2629677Slinton {
2639677Slinton     if (infile != nil) {
2649677Slinton 	error("multiple input redirects");
2659677Slinton     }
2669677Slinton     infile = filename;
2679677Slinton }
2689677Slinton 
2699677Slinton /*
2709677Slinton  * Set the standard output for the debuggee.
2719677Slinton  * Probably should check to avoid overwriting an existing file.
2729677Slinton  */
2739677Slinton 
2749677Slinton public outarg(filename)
2759677Slinton String filename;
2769677Slinton {
2779677Slinton     if (outfile != nil) {
2789677Slinton 	error("multiple output redirect");
2799677Slinton     }
2809677Slinton     outfile = filename;
2819677Slinton }
2829677Slinton 
2839677Slinton /*
2849677Slinton  * Start debuggee executing.
2859677Slinton  */
2869677Slinton 
2879677Slinton public run()
2889677Slinton {
2899677Slinton     process->status = STOPPED;
2909677Slinton     fixbps();
2919677Slinton     curline = 0;
2929677Slinton     start(argv, infile, outfile);
2939677Slinton     just_started = true;
2949677Slinton     isstopped = false;
29514757Slinton     cont(0);
2969677Slinton }
2979677Slinton 
2989677Slinton /*
2999677Slinton  * Continue execution wherever we left off.
3009677Slinton  *
3019677Slinton  * Note that this routine never returns.  Eventually bpact() will fail
3029677Slinton  * and we'll call printstatus or step will call it.
3039677Slinton  */
3049677Slinton 
3059677Slinton typedef int Intfunc();
3069677Slinton 
3079677Slinton private Intfunc *dbintr;
3089677Slinton private intr();
3099677Slinton 
3109677Slinton #define succeeds    == true
3119677Slinton #define fails       == false
3129677Slinton 
31311867Slinton public cont(signo)
31416617Ssam integer signo;
3159677Slinton {
31616617Ssam     integer s;
31716617Ssam 
3189677Slinton     dbintr = signal(SIGINT, intr);
3199677Slinton     if (just_started) {
3209677Slinton 	just_started = false;
3219677Slinton     } else {
3229677Slinton 	if (not isstopped) {
3239677Slinton 	    error("can't continue execution");
3249677Slinton 	}
3259677Slinton 	isstopped = false;
32611867Slinton 	stepover();
3279677Slinton     }
32816617Ssam     s = signo;
3299677Slinton     for (;;) {
3309677Slinton 	if (single_stepping) {
3319677Slinton 	    printnews();
3329677Slinton 	} else {
3339677Slinton 	    setallbps();
33416617Ssam 	    resume(s);
3359677Slinton 	    unsetallbps();
33616617Ssam 	    s = DEFSIG;
3379677Slinton 	    if (bpact() fails) {
3389677Slinton 		printstatus();
3399677Slinton 	    }
3409677Slinton 	}
34111867Slinton 	stepover();
3429677Slinton     }
3439677Slinton     /* NOTREACHED */
3449677Slinton }
3459677Slinton 
3469677Slinton /*
3479677Slinton  * This routine is called if we get an interrupt while "running" px
3489677Slinton  * but actually in the debugger.  Could happen, for example, while
3499677Slinton  * processing breakpoints.
3509677Slinton  *
3519677Slinton  * We basically just want to keep going; the assumption is
3529677Slinton  * that when the process resumes it will get the interrupt
3539677Slinton  * which will then be handled.
3549677Slinton  */
3559677Slinton 
3569677Slinton private intr()
3579677Slinton {
3589677Slinton     signal(SIGINT, intr);
3599677Slinton }
3609677Slinton 
3619677Slinton public fixintr()
3629677Slinton {
3639677Slinton     signal(SIGINT, dbintr);
3649677Slinton }
3659677Slinton 
3669677Slinton /*
3679677Slinton  * Resume execution.
3689677Slinton  */
3699677Slinton 
37011867Slinton public resume(signo)
37111867Slinton int signo;
3729677Slinton {
3739677Slinton     register Process p;
3749677Slinton 
3759677Slinton     p = process;
37611867Slinton     pcont(p, signo);
3779677Slinton     pc = process->reg[PROGCTR];
37811832Slinton     if (p->status != STOPPED) {
37911867Slinton 	if (p->signo != 0) {
38011867Slinton 	    error("program terminated by signal %d", p->signo);
38114757Slinton 	} else if (not runfirst) {
38211867Slinton 	    error("program unexpectedly exited with %d", p->exitval);
38311867Slinton 	}
38411832Slinton     }
3859677Slinton }
3869677Slinton 
3879677Slinton /*
3889677Slinton  * Continue execution up to the next source line.
3899677Slinton  *
3909677Slinton  * There are two ways to define the next source line depending on what
3919677Slinton  * is desired when a procedure or function call is encountered.  Step
3929677Slinton  * stops at the beginning of the procedure or call; next skips over it.
3939677Slinton  */
3949677Slinton 
3959677Slinton /*
3969677Slinton  * Stepc is what is called when the step command is given.
3979677Slinton  * It has to play with the "isstopped" information.
3989677Slinton  */
3999677Slinton 
4009677Slinton public stepc()
4019677Slinton {
4029677Slinton     if (not isstopped) {
4039677Slinton 	error("can't continue execution");
4049677Slinton     }
4059677Slinton     isstopped = false;
4069677Slinton     dostep(false);
4079677Slinton     isstopped = true;
4089677Slinton }
4099677Slinton 
4109677Slinton public next()
4119677Slinton {
41216617Ssam     Address oldfrp, newfrp;
41316617Ssam 
4149677Slinton     if (not isstopped) {
4159677Slinton 	error("can't continue execution");
4169677Slinton     }
4179677Slinton     isstopped = false;
41816617Ssam     oldfrp = reg(FRP);
41916617Ssam     do {
42016617Ssam 	dostep(true);
42116617Ssam 	pc = reg(PROGCTR);
42216617Ssam 	newfrp = reg(FRP);
42316617Ssam     } while (newfrp < oldfrp and newfrp != 0);
4249677Slinton     isstopped = true;
4259677Slinton }
4269677Slinton 
42711867Slinton /*
42816617Ssam  * Continue execution until the current function returns, or,
42916617Ssam  * if the given argument is non-nil, until execution returns to
43016617Ssam  * somewhere within the given function.
43116617Ssam  */
43216617Ssam 
43316617Ssam public rtnfunc (f)
43416617Ssam Symbol f;
43516617Ssam {
43616617Ssam     Address addr;
43716617Ssam     Symbol t;
43816617Ssam 
43916617Ssam     if (not isstopped) {
44016617Ssam 	error("can't continue execution");
44116617Ssam     } else if (f != nil and not isactive(f)) {
44216617Ssam 	error("%s is not active", symname(f));
44316617Ssam     } else {
44416617Ssam 	addr = return_addr();
44516617Ssam 	if (addr == nil) {
44616617Ssam 	    error("no place to return to");
44716617Ssam 	} else {
44816617Ssam 	    isstopped = false;
44916617Ssam 	    contto(addr);
45016617Ssam 	    if (f != nil) {
45116617Ssam 		for (;;) {
45216617Ssam 		    t = whatblock(pc);
45316617Ssam 		    addr = return_addr();
45416617Ssam 		if (t == f or addr == nil) break;
45516617Ssam 		    contto(addr);
45616617Ssam 		}
45716617Ssam 	    }
45816617Ssam 	    if (bpact() fails) {
45916617Ssam 		isstopped = true;
46016617Ssam 		printstatus();
46116617Ssam 	    }
46216617Ssam 	}
46316617Ssam     }
46416617Ssam }
46516617Ssam 
46616617Ssam /*
46711867Slinton  * Single-step over the current machine instruction.
46811867Slinton  *
46911867Slinton  * If we're single-stepping by source line we want to step to the
47011867Slinton  * next source line.  Otherwise we're going to continue so there's
47111867Slinton  * no reason to do all the work necessary to single-step to the next
47211867Slinton  * source line.
47311867Slinton  */
47411867Slinton 
47516617Ssam public stepover()
4769677Slinton {
47711867Slinton     Boolean b;
47811867Slinton 
47916617Ssam     if (traceexec) {
48016617Ssam 	printf("!! stepping over 0x%x\n", process->reg[PROGCTR]);
48116617Ssam     }
48211867Slinton     if (single_stepping) {
48311867Slinton 	dostep(false);
48411867Slinton     } else {
48511867Slinton 	b = inst_tracing;
48611867Slinton 	inst_tracing = true;
48711867Slinton 	dostep(false);
48811867Slinton 	inst_tracing = b;
48911867Slinton     }
49016617Ssam     if (traceexec) {
49116617Ssam 	printf("!! stepped over to 0x%x\n", process->reg[PROGCTR]);
49216617Ssam     }
4939677Slinton }
4949677Slinton 
4959677Slinton /*
4969677Slinton  * Resume execution up to the given address.  It is assumed that
4979677Slinton  * no breakpoints exist between the current address and the one
4989677Slinton  * we're stepping to.  This saves us from setting all the breakpoints.
4999677Slinton  */
5009677Slinton 
5019677Slinton public stepto(addr)
5029677Slinton Address addr;
5039677Slinton {
50416617Ssam     xto(addr, false);
50516617Ssam }
50616617Ssam 
50716617Ssam private contto (addr)
50816617Ssam Address addr;
50916617Ssam {
51016617Ssam     xto(addr, true);
51116617Ssam }
51216617Ssam 
51316617Ssam private xto (addr, catchbps)
51416617Ssam Address addr;
51516617Ssam boolean catchbps;
51616617Ssam {
51716617Ssam     Address curpc;
51816617Ssam 
51916617Ssam     if (catchbps) {
52016617Ssam 	stepover();
5219677Slinton     }
52216617Ssam     curpc = process->reg[PROGCTR];
52316617Ssam     if (addr != curpc) {
52416617Ssam 	if (traceexec) {
52516617Ssam 	    printf("!! stepping from 0x%x to 0x%x\n", curpc, addr);
52616617Ssam 	}
52716617Ssam 	if (catchbps) {
52816617Ssam 	    setallbps();
52916617Ssam 	}
53016617Ssam 	setbp(addr);
53116617Ssam 	resume(DEFSIG);
53216617Ssam 	unsetbp(addr);
53316617Ssam 	if (catchbps) {
53416617Ssam 	    unsetallbps();
53516617Ssam 	}
53616617Ssam 	if (not isbperr()) {
53716617Ssam 	    printstatus();
53816617Ssam 	}
53916617Ssam     }
5409677Slinton }
5419677Slinton 
5429677Slinton /*
5439677Slinton  * Print the status of the process.
5449677Slinton  * This routine does not return.
5459677Slinton  */
5469677Slinton 
5479677Slinton public printstatus()
5489677Slinton {
54914395Slinton     int status;
55014395Slinton 
5519843Slinton     if (process->status == FINISHED) {
5529843Slinton 	exit(0);
5539843Slinton     } else {
55416617Ssam 	setcurfunc(whatblock(pc));
5559677Slinton 	getsrcpos();
5569843Slinton 	if (process->signo == SIGINT) {
5579843Slinton 	    isstopped = true;
5589843Slinton 	    printerror();
5599843Slinton 	} else if (isbperr() and isstopped) {
5609843Slinton 	    printf("stopped ");
56111172Slinton 	    printloc();
56211172Slinton 	    putchar('\n');
5639843Slinton 	    if (curline > 0) {
5649843Slinton 		printlines(curline, curline);
5659843Slinton 	    } else {
5669843Slinton 		printinst(pc, pc);
5679843Slinton 	    }
5689843Slinton 	    erecover();
5699677Slinton 	} else {
5709843Slinton 	    fixintr();
5719677Slinton 	    isstopped = true;
5729677Slinton 	    printerror();
5739677Slinton 	}
5749677Slinton     }
5759677Slinton }
5769677Slinton 
5779677Slinton /*
57811172Slinton  * Print out the current location in the debuggee.
57911172Slinton  */
58011172Slinton 
58111172Slinton public printloc()
58211172Slinton {
58311172Slinton     printf("in ");
58411172Slinton     printname(stdout, curfunc);
58511172Slinton     putchar(' ');
58614757Slinton     if (curline > 0 and not useInstLoc) {
58711172Slinton 	printsrcpos();
58811172Slinton     } else {
58914757Slinton 	useInstLoc = false;
59014757Slinton 	curline = 0;
59111172Slinton 	printf("at 0x%x", pc);
59211172Slinton     }
59311172Slinton }
59411172Slinton 
59511172Slinton /*
5969677Slinton  * Some functions for testing the state of the process.
5979677Slinton  */
5989677Slinton 
5999677Slinton public Boolean notstarted(p)
6009677Slinton Process p;
6019677Slinton {
6029677Slinton     return (Boolean) (p->status == NOTSTARTED);
6039677Slinton }
6049677Slinton 
6059677Slinton public Boolean isfinished(p)
6069677Slinton Process p;
6079677Slinton {
6089677Slinton     return (Boolean) (p->status == FINISHED);
6099677Slinton }
6109677Slinton 
6119677Slinton /*
6129677Slinton  * Return the signal number which stopped the process.
6139677Slinton  */
6149677Slinton 
6159677Slinton public Integer errnum(p)
6169677Slinton Process p;
6179677Slinton {
6189677Slinton     return p->signo;
6199677Slinton }
6209677Slinton 
6219677Slinton /*
6229677Slinton  * Return the termination code of the process.
6239677Slinton  */
6249677Slinton 
6259677Slinton public Integer exitcode(p)
6269677Slinton Process p;
6279677Slinton {
6289677Slinton     return p->exitval;
6299677Slinton }
6309677Slinton 
6319677Slinton /*
6329677Slinton  * These routines are used to access the debuggee process from
6339677Slinton  * outside this module.
6349677Slinton  *
6359677Slinton  * They invoke "pio" which eventually leads to a call to "ptrace".
63614757Slinton  * The system generates an I/O error when a ptrace fails.  During reads
63714757Slinton  * these are ignored, during writes they are reported as an error, and
63814757Slinton  * for anything else they cause a fatal error.
6399677Slinton  */
6409677Slinton 
6419677Slinton extern Intfunc *onsyserr();
6429677Slinton 
6439677Slinton private badaddr;
64414757Slinton private read_err(), write_err();
6459677Slinton 
6469677Slinton /*
6479677Slinton  * Read from the process' instruction area.
6489677Slinton  */
6499677Slinton 
6509677Slinton public iread(buff, addr, nbytes)
6519677Slinton char *buff;
6529677Slinton Address addr;
6539677Slinton int nbytes;
6549677Slinton {
6559677Slinton     Intfunc *f;
6569677Slinton 
65714757Slinton     f = onsyserr(EIO, read_err);
6589677Slinton     badaddr = addr;
6599677Slinton     if (coredump) {
6609677Slinton 	coredump_readtext(buff, addr, nbytes);
6619677Slinton     } else {
6629677Slinton 	pio(process, PREAD, TEXTSEG, buff, addr, nbytes);
6639677Slinton     }
6649677Slinton     onsyserr(EIO, f);
6659677Slinton }
6669677Slinton 
6679677Slinton /*
6689677Slinton  * Write to the process' instruction area, usually in order to set
6699677Slinton  * or unset a breakpoint.
6709677Slinton  */
6719677Slinton 
6729677Slinton public iwrite(buff, addr, nbytes)
6739677Slinton char *buff;
6749677Slinton Address addr;
6759677Slinton int nbytes;
6769677Slinton {
6779677Slinton     Intfunc *f;
6789677Slinton 
6799677Slinton     if (coredump) {
6809677Slinton 	error("no process to write to");
6819677Slinton     }
68214757Slinton     f = onsyserr(EIO, write_err);
6839677Slinton     badaddr = addr;
6849677Slinton     pio(process, PWRITE, TEXTSEG, buff, addr, nbytes);
6859677Slinton     onsyserr(EIO, f);
6869677Slinton }
6879677Slinton 
6889677Slinton /*
6899677Slinton  * Read for the process' data area.
6909677Slinton  */
6919677Slinton 
6929677Slinton public dread(buff, addr, nbytes)
6939677Slinton char *buff;
6949677Slinton Address addr;
6959677Slinton int nbytes;
6969677Slinton {
6979677Slinton     Intfunc *f;
6989677Slinton 
69914757Slinton     f = onsyserr(EIO, read_err);
7009677Slinton     badaddr = addr;
7019677Slinton     if (coredump) {
7029677Slinton 	coredump_readdata(buff, addr, nbytes);
7039677Slinton     } else {
7049677Slinton 	pio(process, PREAD, DATASEG, buff, addr, nbytes);
7059677Slinton     }
7069677Slinton     onsyserr(EIO, f);
7079677Slinton }
7089677Slinton 
7099677Slinton /*
7109677Slinton  * Write to the process' data area.
7119677Slinton  */
7129677Slinton 
7139677Slinton public dwrite(buff, addr, nbytes)
7149677Slinton char *buff;
7159677Slinton Address addr;
7169677Slinton int nbytes;
7179677Slinton {
7189677Slinton     Intfunc *f;
7199677Slinton 
7209677Slinton     if (coredump) {
7219677Slinton 	error("no process to write to");
7229677Slinton     }
72314757Slinton     f = onsyserr(EIO, write_err);
7249677Slinton     badaddr = addr;
7259677Slinton     pio(process, PWRITE, DATASEG, buff, addr, nbytes);
7269677Slinton     onsyserr(EIO, f);
7279677Slinton }
7289677Slinton 
7299677Slinton /*
73014757Slinton  * Trap for errors in reading or writing to a process.
73114757Slinton  * The current approach is to "ignore" read errors and complain
73214757Slinton  * bitterly about write errors.
7339677Slinton  */
7349677Slinton 
73514757Slinton private read_err()
7369677Slinton {
73711560Slinton     /*
73814757Slinton      * Ignore.
73911560Slinton      */
7409677Slinton }
7419677Slinton 
74214757Slinton private write_err()
74314757Slinton {
74414757Slinton     error("can't write to process (address 0x%x)", badaddr);
74514757Slinton }
74614757Slinton 
7479677Slinton /*
7489677Slinton  * Ptrace interface.
7499677Slinton  */
7509677Slinton 
7519677Slinton /*
7529677Slinton  * This magic macro enables us to look at the process' registers
75314757Slinton  * in its user structure.
7549677Slinton  */
7559677Slinton 
7569677Slinton #define regloc(reg)     (ctob(UPAGES) + ( sizeof(int) * (reg) ))
7579677Slinton 
7589677Slinton #define WMASK           (~(sizeof(Word) - 1))
7599677Slinton #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE))
7609677Slinton 
7619677Slinton #define FIRSTSIG        SIGINT
7629677Slinton #define LASTSIG         SIGQUIT
7639677Slinton #define ischild(pid)    ((pid) == 0)
7649677Slinton #define traceme()       ptrace(0, 0, 0, 0)
7659677Slinton #define setrep(n)       (1 << ((n)-1))
7669677Slinton #define istraced(p)     (p->sigset&setrep(p->signo))
7679677Slinton 
7689677Slinton /*
7699677Slinton  * Ptrace options (specified in first argument).
7709677Slinton  */
7719677Slinton 
7729677Slinton #define UREAD   3       /* read from process's user structure */
7739677Slinton #define UWRITE  6       /* write to process's user structure */
7749677Slinton #define IREAD   1       /* read from process's instruction space */
7759677Slinton #define IWRITE  4       /* write to process's instruction space */
7769677Slinton #define DREAD   2       /* read from process's data space */
7779677Slinton #define DWRITE  5       /* write to process's data space */
7789677Slinton #define CONT    7       /* continue stopped process */
7799677Slinton #define SSTEP   9       /* continue for approximately one instruction */
7809677Slinton #define PKILL   8       /* terminate the process */
7819677Slinton 
7829677Slinton /*
7839677Slinton  * Start up a new process by forking and exec-ing the
7849677Slinton  * given argument list, returning when the process is loaded
7859677Slinton  * and ready to execute.  The PROCESS information (pointed to
7869677Slinton  * by the first argument) is appropriately filled.
7879677Slinton  *
7889677Slinton  * If the given PROCESS structure is associated with an already running
7899677Slinton  * process, we terminate it.
7909677Slinton  */
7919677Slinton 
7929677Slinton /* VARARGS2 */
7939677Slinton private pstart(p, argv, infile, outfile)
7949677Slinton Process p;
7959677Slinton String argv[];
7969677Slinton String infile;
7979677Slinton String outfile;
7989677Slinton {
7999677Slinton     int status;
8009677Slinton 
80116617Ssam     if (p->pid != 0) {
80216617Ssam 	pterm(p);
8039677Slinton     }
8049677Slinton     psigtrace(p, SIGTRAP, true);
80514395Slinton     p->pid = vfork();
80614395Slinton     if (p->pid == -1) {
8079677Slinton 	panic("can't fork");
8089677Slinton     }
8099677Slinton     if (ischild(p->pid)) {
8109677Slinton 	traceme();
8119677Slinton 	if (infile != nil) {
81216617Ssam 	    infrom(infile);
8139677Slinton 	}
8149677Slinton 	if (outfile != nil) {
81516617Ssam 	    outto(outfile);
8169677Slinton 	}
81711832Slinton 	execv(argv[0], argv);
81811172Slinton 	write(2, "can't exec ", 11);
81911172Slinton 	write(2, argv[0], strlen(argv[0]));
82011172Slinton 	write(2, "\n", 1);
82111172Slinton 	_exit(1);
8229677Slinton     }
8239677Slinton     pwait(p->pid, &status);
8249677Slinton     getinfo(p, status);
8259677Slinton     if (p->status != STOPPED) {
8269677Slinton 	error("program could not begin execution");
8279677Slinton     }
82814395Slinton     ptraced(p->pid);
8299677Slinton }
8309677Slinton 
8319677Slinton /*
83216617Ssam  * Terminate a ptrace'd process.
83316617Ssam  */
83416617Ssam 
83516617Ssam public pterm (p)
83616617Ssam Process p;
83716617Ssam {
83816617Ssam     integer status;
83916617Ssam 
84016617Ssam     if (p != nil and p->pid != 0) {
84116617Ssam 	ptrace(PKILL, p->pid, 0, 0);
84216617Ssam 	pwait(p->pid, &status);
84316617Ssam 	unptraced(p->pid);
84416617Ssam     }
84516617Ssam }
84616617Ssam 
84716617Ssam /*
84811867Slinton  * Continue a stopped process.  The first argument points to a Process
84911867Slinton  * structure.  Before the process is restarted it's user area is modified
85011867Slinton  * according to the values in the structure.  When this routine finishes,
8519677Slinton  * the structure has the new values from the process's user area.
8529677Slinton  *
8539677Slinton  * Pcont terminates when the process stops with a signal pending that
8549677Slinton  * is being traced (via psigtrace), or when the process terminates.
8559677Slinton  */
8569677Slinton 
85711867Slinton private pcont(p, signo)
8589677Slinton Process p;
85911867Slinton int signo;
8609677Slinton {
86116617Ssam     int s, status;
8629677Slinton 
8639677Slinton     if (p->pid == 0) {
8649677Slinton 	error("program not active");
8659677Slinton     }
86616617Ssam     s = signo;
8679677Slinton     do {
86816617Ssam 	setinfo(p, s);
86916617Ssam 	if (traceexec) {
87016617Ssam 	    printf("!! pcont from 0x%x with signal %d (%d)\n",
87116617Ssam 		p->reg[PROGCTR], s, p->signo);
87216617Ssam 	    fflush(stdout);
87316617Ssam 	}
8749677Slinton 	sigs_off();
8759677Slinton 	if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) {
87614395Slinton 	    panic("error %d trying to continue process", errno);
8779677Slinton 	}
8789677Slinton 	pwait(p->pid, &status);
8799677Slinton 	sigs_on();
8809677Slinton 	getinfo(p, status);
88116617Ssam 	if (traceexec and not istraced(p)) {
88216617Ssam 	    printf("!! ignored signal %d at 0x%x\n", p->signo, p->reg[PROGCTR]);
88316617Ssam 	    fflush(stdout);
88416617Ssam 	}
88516617Ssam 	s = p->signo;
8869677Slinton     } while (p->status == STOPPED and not istraced(p));
88716617Ssam     if (traceexec) {
88816617Ssam 	printf("!! pcont to 0x%x on signal %d\n", p->reg[PROGCTR], p->signo);
88916617Ssam 	fflush(stdout);
89016617Ssam     }
8919677Slinton }
8929677Slinton 
8939677Slinton /*
8949677Slinton  * Single step as best ptrace can.
8959677Slinton  */
8969677Slinton 
89716617Ssam public pstep(p, signo)
8989677Slinton Process p;
89916617Ssam integer signo;
9009677Slinton {
9019677Slinton     int status;
9029677Slinton 
90316617Ssam     setinfo(p, signo);
90416617Ssam     if (traceexec) {
90516617Ssam 	printf("!! pstep from pc 0x%x with signal %d (%d)\n",
90616617Ssam 	    p->reg[PROGCTR], signo, p->signo);
90716617Ssam 	fflush(stdout);
90816617Ssam     }
9099677Slinton     sigs_off();
91016617Ssam     if (ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo) < 0) {
91116617Ssam 	panic("error %d trying to step process", errno);
91216617Ssam     }
9139677Slinton     pwait(p->pid, &status);
9149677Slinton     sigs_on();
9159677Slinton     getinfo(p, status);
91616617Ssam     if (traceexec) {
91716617Ssam 	printf("!! pstep to pc 0x%x on signal %d\n", p->reg[PROGCTR], p->signo);
91816617Ssam 	fflush(stdout);
91916617Ssam     }
92016617Ssam     if (p->status != STOPPED) {
92116617Ssam 	error("program unexpectedly exited with %d\n", p->exitval);
92216617Ssam     }
9239677Slinton }
9249677Slinton 
9259677Slinton /*
9269677Slinton  * Return from execution when the given signal is pending.
9279677Slinton  */
9289677Slinton 
9299677Slinton public psigtrace(p, sig, sw)
9309677Slinton Process p;
9319677Slinton int sig;
9329677Slinton Boolean sw;
9339677Slinton {
9349677Slinton     if (sw) {
9359677Slinton 	p->sigset |= setrep(sig);
9369677Slinton     } else {
9379677Slinton 	p->sigset &= ~setrep(sig);
9389677Slinton     }
9399677Slinton }
9409677Slinton 
9419677Slinton /*
9429677Slinton  * Don't catch any signals.
9439677Slinton  * Particularly useful when letting a process finish uninhibited.
9449677Slinton  */
9459677Slinton 
9469677Slinton public unsetsigtraces(p)
9479677Slinton Process p;
9489677Slinton {
9499677Slinton     p->sigset = 0;
9509677Slinton }
9519677Slinton 
9529677Slinton /*
9539677Slinton  * Turn off attention to signals not being caught.
9549677Slinton  */
9559677Slinton 
9569677Slinton private Intfunc *sigfunc[NSIG];
9579677Slinton 
9589677Slinton private sigs_off()
9599677Slinton {
9609677Slinton     register int i;
9619677Slinton 
9629677Slinton     for (i = FIRSTSIG; i < LASTSIG; i++) {
9639677Slinton 	if (i != SIGKILL) {
9649677Slinton 	    sigfunc[i] = signal(i, SIG_IGN);
9659677Slinton 	}
9669677Slinton     }
9679677Slinton }
9689677Slinton 
9699677Slinton /*
9709677Slinton  * Turn back on attention to signals.
9719677Slinton  */
9729677Slinton 
9739677Slinton private sigs_on()
9749677Slinton {
9759677Slinton     register int i;
9769677Slinton 
9779677Slinton     for (i = FIRSTSIG; i < LASTSIG; i++) {
9789677Slinton 	if (i != SIGKILL) {
9799677Slinton 	    signal(i, sigfunc[i]);
9809677Slinton 	}
9819677Slinton     }
9829677Slinton }
9839677Slinton 
9849677Slinton /*
9859677Slinton  * Get process information from user area.
9869677Slinton  */
9879677Slinton 
9889677Slinton private int rloc[] ={
9899677Slinton     R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, AP, FP, SP, PC
9909677Slinton };
9919677Slinton 
9929677Slinton private getinfo(p, status)
9939677Slinton register Process p;
9949677Slinton register int status;
9959677Slinton {
9969677Slinton     register int i;
99716617Ssam     Address addr;
9989677Slinton 
9999677Slinton     p->signo = (status&0177);
10009677Slinton     p->exitval = ((status >> 8)&0377);
10019677Slinton     if (p->signo != STOPPED) {
10029677Slinton 	p->status = FINISHED;
100314757Slinton 	p->pid = 0;
100416617Ssam 	p->reg[PROGCTR] = 0;
10059677Slinton     } else {
10069677Slinton 	p->status = p->signo;
10079677Slinton 	p->signo = p->exitval;
10089677Slinton 	p->exitval = 0;
10099677Slinton 	p->mask = ptrace(UREAD, p->pid, regloc(PS), 0);
10109677Slinton 	for (i = 0; i < NREG; i++) {
10119677Slinton 	    p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0);
10129677Slinton 	    p->oreg[i] = p->reg[i];
10139677Slinton 	}
101411768Slinton 	savetty(stdout, &(p->ttyinfo));
101516617Ssam 	addr = (Address) &(((struct user *) 0)->u_signal[p->signo]);
101616617Ssam 	p->sigstatus = (Address) ptrace(UREAD, p->pid, addr, 0);
10179677Slinton     }
10189677Slinton }
10199677Slinton 
10209677Slinton /*
10219677Slinton  * Set process's user area information from given process structure.
10229677Slinton  */
10239677Slinton 
102411867Slinton private setinfo(p, signo)
10259677Slinton register Process p;
102611867Slinton int signo;
10279677Slinton {
10289677Slinton     register int i;
10299677Slinton     register int r;
10309677Slinton 
103114757Slinton     if (signo == DEFSIG) {
103216617Ssam 	if (istraced(p) and (p->sigstatus == 0 or p->sigstatus == 1)) {
103314757Slinton 	    p->signo = 0;
103414757Slinton 	}
103514757Slinton     } else {
103611867Slinton 	p->signo = signo;
10379677Slinton     }
10389677Slinton     for (i = 0; i < NREG; i++) {
10399677Slinton 	if ((r = p->reg[i]) != p->oreg[i]) {
10409677Slinton 	    ptrace(UWRITE, p->pid, regloc(rloc[i]), r);
10419677Slinton 	}
10429677Slinton     }
104311768Slinton     restoretty(stdout, &(p->ttyinfo));
10449677Slinton }
10459677Slinton 
10469677Slinton /*
104716617Ssam  * Return the address associated with the current signal.
104816617Ssam  * (Plus two since the address points to the beginning of a procedure).
104916617Ssam  */
105016617Ssam 
105116617Ssam public Address usignal (p)
105216617Ssam Process p;
105316617Ssam {
105416617Ssam     Address r;
105516617Ssam 
105616617Ssam     r = p->sigstatus;
105716617Ssam     if (r != 0 and r != 1) {
105816617Ssam 	r += 2;
105916617Ssam     }
106016617Ssam     return r;
106116617Ssam }
106216617Ssam 
106316617Ssam /*
10649677Slinton  * Structure for reading and writing by words, but dealing with bytes.
10659677Slinton  */
10669677Slinton 
10679677Slinton typedef union {
10689677Slinton     Word pword;
10699677Slinton     Byte pbyte[sizeof(Word)];
10709677Slinton } Pword;
10719677Slinton 
10729677Slinton /*
10739677Slinton  * Read (write) from (to) the process' address space.
10749677Slinton  * We must deal with ptrace's inability to look anywhere other
10759677Slinton  * than at a word boundary.
10769677Slinton  */
10779677Slinton 
10789677Slinton private Word fetch();
10799677Slinton private store();
10809677Slinton 
10819677Slinton private pio(p, op, seg, buff, addr, nbytes)
10829677Slinton Process p;
10839677Slinton PioOp op;
10849677Slinton PioSeg seg;
10859677Slinton char *buff;
10869677Slinton Address addr;
10879677Slinton int nbytes;
10889677Slinton {
10899677Slinton     register int i;
10909677Slinton     register Address newaddr;
10919677Slinton     register char *cp;
10929677Slinton     char *bufend;
10939677Slinton     Pword w;
10949677Slinton     Address wordaddr;
10959677Slinton     int byteoff;
10969677Slinton 
10979677Slinton     if (p->status != STOPPED) {
10989677Slinton 	error("program is not active");
10999677Slinton     }
11009677Slinton     cp = buff;
11019677Slinton     newaddr = addr;
11029677Slinton     wordaddr = (newaddr&WMASK);
11039677Slinton     if (wordaddr != newaddr) {
11049677Slinton 	w.pword = fetch(p, seg, wordaddr);
11059677Slinton 	for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) {
11069677Slinton 	    if (op == PREAD) {
11079677Slinton 		*cp++ = w.pbyte[i];
11089677Slinton 	    } else {
11099677Slinton 		w.pbyte[i] = *cp++;
11109677Slinton 	    }
11119677Slinton 	    nbytes--;
11129677Slinton 	}
11139677Slinton 	if (op == PWRITE) {
11149677Slinton 	    store(p, seg, wordaddr, w.pword);
11159677Slinton 	}
11169677Slinton 	newaddr = wordaddr + sizeof(Word);
11179677Slinton     }
11189677Slinton     byteoff = (nbytes&(~WMASK));
11199677Slinton     nbytes -= byteoff;
11209677Slinton     bufend = cp + nbytes;
11219677Slinton     while (cp < bufend) {
11229677Slinton 	if (op == PREAD) {
11239677Slinton 	    *((Word *) cp) = fetch(p, seg, newaddr);
11249677Slinton 	} else {
11259677Slinton 	    store(p, seg, newaddr, *((Word *) cp));
11269677Slinton 	}
11279677Slinton 	cp += sizeof(Word);
11289677Slinton 	newaddr += sizeof(Word);
11299677Slinton     }
11309677Slinton     if (byteoff > 0) {
11319677Slinton 	w.pword = fetch(p, seg, newaddr);
11329677Slinton 	for (i = 0; i < byteoff; i++) {
11339677Slinton 	    if (op == PREAD) {
11349677Slinton 		*cp++ = w.pbyte[i];
11359677Slinton 	    } else {
11369677Slinton 		w.pbyte[i] = *cp++;
11379677Slinton 	    }
11389677Slinton 	}
11399677Slinton 	if (op == PWRITE) {
11409677Slinton 	    store(p, seg, newaddr, w.pword);
11419677Slinton 	}
11429677Slinton     }
11439677Slinton }
11449677Slinton 
11459677Slinton /*
11469677Slinton  * Get a word from a process at the given address.
11479677Slinton  * The address is assumed to be on a word boundary.
11489677Slinton  *
11499677Slinton  * A simple cache scheme is used to avoid redundant ptrace calls
11509677Slinton  * to the instruction space since it is assumed to be pure.
11519677Slinton  *
11529677Slinton  * It is necessary to use a write-through scheme so that
11539677Slinton  * breakpoints right next to each other don't interfere.
11549677Slinton  */
11559677Slinton 
11569677Slinton private Integer nfetchs, nreads, nwrites;
11579677Slinton 
11589677Slinton private Word fetch(p, seg, addr)
11599677Slinton Process p;
11609677Slinton PioSeg seg;
11619677Slinton register int addr;
11629677Slinton {
11639677Slinton     register CacheWord *wp;
11649677Slinton     register Word w;
11659677Slinton 
11669677Slinton     switch (seg) {
11679677Slinton 	case TEXTSEG:
11689677Slinton 	    ++nfetchs;
11699677Slinton 	    wp = &p->word[cachehash(addr)];
11709677Slinton 	    if (addr == 0 or wp->addr != addr) {
11719677Slinton 		++nreads;
11729677Slinton 		w = ptrace(IREAD, p->pid, addr, 0);
11739677Slinton 		wp->addr = addr;
11749677Slinton 		wp->val = w;
11759677Slinton 	    } else {
11769677Slinton 		w = wp->val;
11779677Slinton 	    }
11789677Slinton 	    break;
11799677Slinton 
11809677Slinton 	case DATASEG:
11819677Slinton 	    w = ptrace(DREAD, p->pid, addr, 0);
11829677Slinton 	    break;
11839677Slinton 
11849677Slinton 	default:
11859677Slinton 	    panic("fetch: bad seg %d", seg);
11869677Slinton 	    /* NOTREACHED */
11879677Slinton     }
11889677Slinton     return w;
11899677Slinton }
11909677Slinton 
11919677Slinton /*
11929677Slinton  * Put a word into the process' address space at the given address.
11939677Slinton  * The address is assumed to be on a word boundary.
11949677Slinton  */
11959677Slinton 
11969677Slinton private store(p, seg, addr, data)
11979677Slinton Process p;
11989677Slinton PioSeg seg;
11999677Slinton int addr;
12009677Slinton Word data;
12019677Slinton {
12029677Slinton     register CacheWord *wp;
12039677Slinton 
12049677Slinton     switch (seg) {
12059677Slinton 	case TEXTSEG:
12069677Slinton 	    ++nwrites;
12079677Slinton 	    wp = &p->word[cachehash(addr)];
12089677Slinton 	    wp->addr = addr;
12099677Slinton 	    wp->val = data;
12109677Slinton 	    ptrace(IWRITE, p->pid, addr, data);
12119677Slinton 	    break;
12129677Slinton 
12139677Slinton 	case DATASEG:
12149677Slinton 	    ptrace(DWRITE, p->pid, addr, data);
12159677Slinton 	    break;
12169677Slinton 
12179677Slinton 	default:
12189677Slinton 	    panic("store: bad seg %d", seg);
12199677Slinton 	    /* NOTREACHED */
12209677Slinton     }
12219677Slinton }
12229677Slinton 
12239677Slinton public printptraceinfo()
12249677Slinton {
12259677Slinton     printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites);
12269677Slinton }
12279677Slinton 
12289677Slinton /*
122916617Ssam  * Redirect input.
123016617Ssam  * Assuming this is called from a child, we should be careful to avoid
123116617Ssam  * (possibly) shared standard I/O buffers.
12329677Slinton  */
12339677Slinton 
123416617Ssam private infrom (filename)
123516617Ssam String filename;
123616617Ssam {
123716617Ssam     Fileid in;
123816617Ssam 
123916617Ssam     in = open(filename, 0);
124016617Ssam     if (in == -1) {
124116617Ssam 	write(2, "can't read ", 11);
124216617Ssam 	write(2, filename, strlen(filename));
124316617Ssam 	write(2, "\n", 1);
124416617Ssam 	_exit(1);
124516617Ssam     }
124616617Ssam     fswap(0, in);
124716617Ssam }
124816617Ssam 
124916617Ssam /*
125016617Ssam  * Redirect standard output.
125116617Ssam  * Same assumptions as for "infrom" above.
125216617Ssam  */
125316617Ssam 
125416617Ssam private outto (filename)
125516617Ssam String filename;
125616617Ssam {
125716617Ssam     Fileid out;
125816617Ssam 
125916617Ssam     out = creat(filename, 0666);
126016617Ssam     if (out == -1) {
126116617Ssam 	write(2, "can't write ", 12);
126216617Ssam 	write(2, filename, strlen(filename));
126316617Ssam 	write(2, "\n", 1);
126416617Ssam 	_exit(1);
126516617Ssam     }
126616617Ssam     fswap(1, out);
126716617Ssam }
126816617Ssam 
126916617Ssam /*
127016617Ssam  * Swap file numbers, useful for redirecting standard input or output.
127116617Ssam  */
127216617Ssam 
12739677Slinton private fswap(oldfd, newfd)
127416617Ssam Fileid oldfd;
127516617Ssam Fileid newfd;
12769677Slinton {
12779677Slinton     if (oldfd != newfd) {
12789677Slinton 	close(oldfd);
12799677Slinton 	dup(newfd);
12809677Slinton 	close(newfd);
12819677Slinton     }
12829677Slinton }
1283*16928Ssam 
1284*16928Ssam #define	bit(i)		(1 << ((i)-1))
1285*16928Ssam /*
1286*16928Ssam  * Signal manipulation routines.
1287*16928Ssam  */
1288*16928Ssam static String signames[NSIG] = {
1289*16928Ssam 	0,
1290*16928Ssam 	"HUP",
1291*16928Ssam 	"INT",
1292*16928Ssam 	"QUIT",
1293*16928Ssam 	"ILL",
1294*16928Ssam 	"TRAP",
1295*16928Ssam 	"IOT",
1296*16928Ssam 	"EMT",
1297*16928Ssam 	"FPE",
1298*16928Ssam 	"KILL",
1299*16928Ssam 	"BUS",
1300*16928Ssam 	"SEGV",
1301*16928Ssam 	"SYS",
1302*16928Ssam 	"PIPE",
1303*16928Ssam 	"ALRM",
1304*16928Ssam 	"TERM",
1305*16928Ssam 	0,
1306*16928Ssam 	"STOP",
1307*16928Ssam 	"TSTP",
1308*16928Ssam 	"CONT",
1309*16928Ssam 	"CHLD",
1310*16928Ssam 	"TTIN",
1311*16928Ssam 	"TTOU",
1312*16928Ssam 	"TINT",
1313*16928Ssam 	"XCPU",
1314*16928Ssam 	"XFSZ",
1315*16928Ssam };
1316*16928Ssam 
1317*16928Ssam /*
1318*16928Ssam  * Map a signal name to a number.
1319*16928Ssam  */
1320*16928Ssam public signalname(s)
1321*16928Ssam String s;
1322*16928Ssam {
1323*16928Ssam 	register String *p;
1324*16928Ssam 
1325*16928Ssam 	for (p = signames; p < &signames[NSIG]; p++)
1326*16928Ssam 		if (*p && streq(*p, s))
1327*16928Ssam 			return (p - signames);
1328*16928Ssam 	error("%s: Unknown signal.", s);
1329*16928Ssam }
1330*16928Ssam 
1331*16928Ssam /*
1332*16928Ssam  * Print all signals being ignored by the
1333*16928Ssam  * debugger.  These signals are auotmatically
1334*16928Ssam  * passed on to the debugged process.
1335*16928Ssam  */
1336*16928Ssam public printsigsignored(vec)
1337*16928Ssam long vec;
1338*16928Ssam {
1339*16928Ssam 	register Integer s;
1340*16928Ssam 	String sep = "";
1341*16928Ssam 
1342*16928Ssam 	for (s = 1; s < NSIG; s++)
1343*16928Ssam 		if ((vec & bit(s)) && signames[s]) {
1344*16928Ssam 			printf("%s%s", sep, signames[s]);
1345*16928Ssam 			sep = " ";
1346*16928Ssam 		}
1347*16928Ssam 	if (*sep != '\0') {
1348*16928Ssam 		putchar('\n');
1349*16928Ssam 		fflush(stdout);
1350*16928Ssam 	}
1351*16928Ssam }
1352*16928Ssam 
1353*16928Ssam /*
1354*16928Ssam  * Print all signals being intercepted by
1355*16928Ssam  * the debugger for the specified process.
1356*16928Ssam  */
1357*16928Ssam public printsigscaught(vec)
1358*16928Ssam long vec;
1359*16928Ssam {
1360*16928Ssam 	register Integer s;
1361*16928Ssam 	String sep = "";
1362*16928Ssam 
1363*16928Ssam 	for (s = 1; s < NSIG; s++)
1364*16928Ssam 		if ((vec & bit(s)) == 0 && signames[s]) {
1365*16928Ssam 			printf("%s%s", sep, signames[s]);
1366*16928Ssam 			sep = " ";
1367*16928Ssam 		}
1368*16928Ssam 	if (*sep != '\0') {
1369*16928Ssam 		putchar('\n');
1370*16928Ssam 		fflush(stdout);
1371*16928Ssam 	}
1372*16928Ssam }
1373*16928Ssam 
1374