xref: /csrg-svn/old/dbx/process.c (revision 42683)
121620Sdist /*
238105Sbostic  * Copyright (c) 1983 The Regents of the University of California.
338105Sbostic  * All rights reserved.
438105Sbostic  *
5*42683Sbostic  * %sccs.include.redist.c%
621620Sdist  */
79677Slinton 
821620Sdist #ifndef lint
9*42683Sbostic static char sccsid[] = "@(#)process.c	5.6 (Berkeley) 06/01/90";
1038105Sbostic #endif /* not lint */
119677Slinton 
129677Slinton /*
139677Slinton  * Process management.
149677Slinton  *
159677Slinton  * This module contains the routines to manage the execution and
169677Slinton  * tracing of the debuggee process.
179677Slinton  */
189677Slinton 
199677Slinton #include "defs.h"
209677Slinton #include "process.h"
219677Slinton #include "machine.h"
229677Slinton #include "events.h"
239677Slinton #include "tree.h"
2414757Slinton #include "eval.h"
259677Slinton #include "operators.h"
269677Slinton #include "source.h"
279677Slinton #include "object.h"
289677Slinton #include "mappings.h"
299677Slinton #include "main.h"
309677Slinton #include "coredump.h"
319677Slinton #include <signal.h>
329677Slinton #include <errno.h>
339677Slinton #include <sys/stat.h>
349677Slinton 
359677Slinton #ifndef public
369677Slinton 
379677Slinton typedef struct Process *Process;
389677Slinton 
399677Slinton Process process;
409677Slinton 
4114757Slinton #define DEFSIG -1
4214757Slinton 
439677Slinton #include "machine.h"
449677Slinton 
459677Slinton #endif
469677Slinton 
479677Slinton #define NOTSTARTED 1
489677Slinton #define STOPPED 0177
499677Slinton #define FINISHED 0
509677Slinton 
519677Slinton /*
5216617Ssam  * A cache of the instruction segment is kept to reduce the number
5316617Ssam  * of system calls.  Might be better just to read the entire
5416617Ssam  * code space into memory.
559677Slinton  */
569677Slinton 
5733331Sdonn #define CACHESIZE 1003
589677Slinton 
599677Slinton typedef struct {
609677Slinton     Word addr;
619677Slinton     Word val;
629677Slinton } CacheWord;
639677Slinton 
649677Slinton /*
659677Slinton  * This structure holds the information we need from the user structure.
669677Slinton  */
679677Slinton 
689677Slinton struct Process {
699677Slinton     int pid;			/* process being traced */
7011768Slinton     int mask;			/* process status word */
7111768Slinton     Word reg[NREG];		/* process' registers */
729677Slinton     Word oreg[NREG];		/* registers when process last stopped */
739677Slinton     short status;		/* either STOPPED or FINISHED */
749677Slinton     short signo;		/* signal that stopped process */
7518230Slinton     short sigcode;		/* extra signal information */
769677Slinton     int exitval;		/* return value from exit() */
779677Slinton     long sigset;		/* bit array of traced signals */
7833331Sdonn     CacheWord word[CACHESIZE];	/* text segment cache */
7911768Slinton     Ttyinfo ttyinfo;		/* process' terminal characteristics */
8016617Ssam     Address sigstatus;		/* process' handler for current signal */
819677Slinton };
829677Slinton 
839677Slinton /*
849677Slinton  * These definitions are for the arguments to "pio".
859677Slinton  */
869677Slinton 
879677Slinton typedef enum { PREAD, PWRITE } PioOp;
889677Slinton typedef enum { TEXTSEG, DATASEG } PioSeg;
899677Slinton 
909677Slinton private struct Process pbuf;
919677Slinton 
9218230Slinton #define MAXNCMDARGS 1000         /* maximum number of arguments to RUN */
939677Slinton 
9414395Slinton extern int errno;
9514395Slinton 
969677Slinton private Boolean just_started;
979677Slinton private int argc;
989677Slinton private String argv[MAXNCMDARGS];
999677Slinton private String infile, outfile;
1009677Slinton 
1019677Slinton /*
1029677Slinton  * Initialize process information.
1039677Slinton  */
1049677Slinton 
process_init()1059677Slinton public process_init()
1069677Slinton {
10733331Sdonn     register integer i;
10833331Sdonn     char buf[10];
1099677Slinton 
1109677Slinton     process = &pbuf;
1119677Slinton     process->status = (coredump) ? STOPPED : NOTSTARTED;
1129677Slinton     setsigtrace();
11333331Sdonn #   if vax || tahoe
11433331Sdonn 	for (i = 0; i < NREG; i++) {
11533331Sdonn 	    sprintf(buf, "$r%d", i);
11633331Sdonn 	    defregname(identname(buf, false), i);
11733331Sdonn 	}
11833331Sdonn #	ifdef vax
11933331Sdonn 	    defregname(identname("$ap", true), ARGP);
12033331Sdonn #	endif
12133331Sdonn #   else
12233331Sdonn #       ifdef mc68000
12333331Sdonn 	    for (i = 0; i < 8; i++) {
12433331Sdonn 		sprintf(buf, "$d%d", i);
12533331Sdonn 		defregname(identname(buf, false), i);
12633331Sdonn 		sprintf(buf, "$a%d", i);
12733331Sdonn 		defregname(identname(buf, false), i + 8);
12833331Sdonn 	    }
12933331Sdonn #       endif
13033331Sdonn #   endif
1319677Slinton     defregname(identname("$fp", true), FRP);
1329677Slinton     defregname(identname("$sp", true), STKP);
1339677Slinton     defregname(identname("$pc", true), PROGCTR);
1349677Slinton     if (coredump) {
1359677Slinton 	coredump_readin(process->mask, process->reg, process->signo);
13612484Slinton 	pc = process->reg[PROGCTR];
1379677Slinton     }
13812484Slinton     arginit();
1399677Slinton }
1409677Slinton 
1419677Slinton /*
1429677Slinton  * Routines to get at process information from outside this module.
1439677Slinton  */
1449677Slinton 
reg(n)1459677Slinton public Word reg(n)
1469677Slinton Integer n;
1479677Slinton {
1489677Slinton     register Word w;
1499677Slinton 
1509677Slinton     if (n == NREG) {
1519677Slinton 	w = process->mask;
1529677Slinton     } else {
1539677Slinton 	w = process->reg[n];
1549677Slinton     }
1559677Slinton     return w;
1569677Slinton }
1579677Slinton 
setreg(n,w)1589677Slinton public setreg(n, w)
1599677Slinton Integer n;
1609677Slinton Word w;
1619677Slinton {
1629677Slinton     process->reg[n] = w;
1639677Slinton }
1649677Slinton 
1659677Slinton /*
1669677Slinton  * Begin execution.
1679677Slinton  *
1689677Slinton  * We set a breakpoint at the end of the code so that the
1699677Slinton  * process data doesn't disappear after the program terminates.
1709677Slinton  */
1719677Slinton 
1729677Slinton private Boolean remade();
1739677Slinton 
start(argv,infile,outfile)1749677Slinton public start(argv, infile, outfile)
1759677Slinton String argv[];
1769677Slinton String infile, outfile;
1779677Slinton {
1789677Slinton     String pargv[4];
1799677Slinton     Node cond;
1809677Slinton 
1819677Slinton     if (coredump) {
1829677Slinton 	coredump = false;
1839677Slinton 	fclose(corefile);
1849677Slinton 	coredump_close();
1859677Slinton     }
1869677Slinton     if (argv == nil) {
1879677Slinton 	argv = pargv;
1889677Slinton 	pargv[0] = objname;
1899677Slinton 	pargv[1] = nil;
1909677Slinton     } else {
1919677Slinton 	argv[argc] = nil;
1929677Slinton     }
19318230Slinton     pstart(process, argv, infile, outfile);
1949677Slinton     if (remade(objname)) {
1959677Slinton 	reinit(argv, infile, outfile);
1969677Slinton     }
1979677Slinton     if (process->status == STOPPED) {
19833331Sdonn 	pc = CODESTART;
19916617Ssam 	setcurfunc(program);
2009677Slinton 	if (objsize != 0) {
2019677Slinton 	    cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr()));
2029677Slinton 	    event_once(cond, buildcmdlist(build(O_ENDX)));
2039677Slinton 	}
2049677Slinton     }
2059677Slinton }
2069677Slinton 
2079677Slinton /*
2089677Slinton  * Check to see if the object file has changed since the symbolic
2099677Slinton  * information last was read.
2109677Slinton  */
2119677Slinton 
2129677Slinton private time_t modtime;
2139677Slinton 
remade(filename)2149677Slinton private Boolean remade(filename)
2159677Slinton String filename;
2169677Slinton {
2179677Slinton     struct stat s;
2189677Slinton     Boolean b;
2199677Slinton 
2209677Slinton     stat(filename, &s);
2219677Slinton     b = (Boolean) (modtime != 0 and modtime < s.st_mtime);
2229677Slinton     modtime = s.st_mtime;
2239677Slinton     return b;
2249677Slinton }
2259677Slinton 
2269677Slinton /*
2279677Slinton  * Set up what signals we want to trace.
2289677Slinton  */
2299677Slinton 
setsigtrace()2309677Slinton private setsigtrace()
2319677Slinton {
2329677Slinton     register Integer i;
2339677Slinton     register Process p;
2349677Slinton 
2359677Slinton     p = process;
2369677Slinton     for (i = 1; i <= NSIG; i++) {
2379677Slinton 	psigtrace(p, i, true);
2389677Slinton     }
2399677Slinton     psigtrace(p, SIGHUP, false);
2409677Slinton     psigtrace(p, SIGKILL, false);
2419677Slinton     psigtrace(p, SIGALRM, false);
24233331Sdonn #   ifdef SIGTSTP
24333331Sdonn 	psigtrace(p, SIGTSTP, false);
24433331Sdonn 	psigtrace(p, SIGCONT, false);
24533331Sdonn #   endif
2469677Slinton     psigtrace(p, SIGCHLD, false);
24726333Ssam     psigtrace(p, SIGWINCH, false);
2489677Slinton }
2499677Slinton 
2509677Slinton /*
2519677Slinton  * Initialize the argument list.
2529677Slinton  */
2539677Slinton 
arginit()2549677Slinton public arginit()
2559677Slinton {
2569677Slinton     infile = nil;
2579677Slinton     outfile = nil;
2589677Slinton     argv[0] = objname;
2599677Slinton     argc = 1;
2609677Slinton }
2619677Slinton 
2629677Slinton /*
2639677Slinton  * Add an argument to the list for the debuggee.
2649677Slinton  */
2659677Slinton 
newarg(arg)2669677Slinton public newarg(arg)
2679677Slinton String arg;
2689677Slinton {
2699677Slinton     if (argc >= MAXNCMDARGS) {
2709677Slinton 	error("too many arguments");
2719677Slinton     }
2729677Slinton     argv[argc++] = arg;
2739677Slinton }
2749677Slinton 
2759677Slinton /*
2769677Slinton  * Set the standard input for the debuggee.
2779677Slinton  */
2789677Slinton 
inarg(filename)2799677Slinton public inarg(filename)
2809677Slinton String filename;
2819677Slinton {
2829677Slinton     if (infile != nil) {
2839677Slinton 	error("multiple input redirects");
2849677Slinton     }
2859677Slinton     infile = filename;
2869677Slinton }
2879677Slinton 
2889677Slinton /*
2899677Slinton  * Set the standard output for the debuggee.
2909677Slinton  * Probably should check to avoid overwriting an existing file.
2919677Slinton  */
2929677Slinton 
outarg(filename)2939677Slinton public outarg(filename)
2949677Slinton String filename;
2959677Slinton {
2969677Slinton     if (outfile != nil) {
2979677Slinton 	error("multiple output redirect");
2989677Slinton     }
2999677Slinton     outfile = filename;
3009677Slinton }
3019677Slinton 
3029677Slinton /*
3039677Slinton  * Start debuggee executing.
3049677Slinton  */
3059677Slinton 
run()3069677Slinton public run()
3079677Slinton {
3089677Slinton     process->status = STOPPED;
3099677Slinton     fixbps();
3109677Slinton     curline = 0;
3119677Slinton     start(argv, infile, outfile);
3129677Slinton     just_started = true;
3139677Slinton     isstopped = false;
31414757Slinton     cont(0);
3159677Slinton }
3169677Slinton 
3179677Slinton /*
3189677Slinton  * Continue execution wherever we left off.
3199677Slinton  *
3209677Slinton  * Note that this routine never returns.  Eventually bpact() will fail
3219677Slinton  * and we'll call printstatus or step will call it.
3229677Slinton  */
3239677Slinton 
3249677Slinton typedef int Intfunc();
3259677Slinton 
32639163Sbostic private sig_t dbintr;
32739163Sbostic private void intr();
3289677Slinton 
cont(signo)32911867Slinton public cont(signo)
33016617Ssam integer signo;
3319677Slinton {
33216617Ssam     integer s;
33316617Ssam 
3349677Slinton     dbintr = signal(SIGINT, intr);
3359677Slinton     if (just_started) {
3369677Slinton 	just_started = false;
3379677Slinton     } else {
3389677Slinton 	if (not isstopped) {
3399677Slinton 	    error("can't continue execution");
3409677Slinton 	}
3419677Slinton 	isstopped = false;
34211867Slinton 	stepover();
3439677Slinton     }
34416617Ssam     s = signo;
3459677Slinton     for (;;) {
3469677Slinton 	if (single_stepping) {
3479677Slinton 	    printnews();
3489677Slinton 	} else {
3499677Slinton 	    setallbps();
35016617Ssam 	    resume(s);
3519677Slinton 	    unsetallbps();
35216617Ssam 	    s = DEFSIG;
35318230Slinton 	    if (not isbperr() or not bpact()) {
3549677Slinton 		printstatus();
3559677Slinton 	    }
3569677Slinton 	}
35711867Slinton 	stepover();
3589677Slinton     }
3599677Slinton     /* NOTREACHED */
3609677Slinton }
3619677Slinton 
3629677Slinton /*
36318230Slinton  * This routine is called if we get an interrupt while "running"
3649677Slinton  * but actually in the debugger.  Could happen, for example, while
3659677Slinton  * processing breakpoints.
3669677Slinton  *
3679677Slinton  * We basically just want to keep going; the assumption is
36818230Slinton  * that when the process resumes it will get the interrupt,
3699677Slinton  * which will then be handled.
3709677Slinton  */
3719677Slinton 
intr()37239163Sbostic private void intr()
3739677Slinton {
3749677Slinton     signal(SIGINT, intr);
3759677Slinton }
3769677Slinton 
fixintr()3779677Slinton public fixintr()
3789677Slinton {
3799677Slinton     signal(SIGINT, dbintr);
3809677Slinton }
3819677Slinton 
3829677Slinton /*
3839677Slinton  * Resume execution.
3849677Slinton  */
3859677Slinton 
resume(signo)38611867Slinton public resume(signo)
38711867Slinton int signo;
3889677Slinton {
3899677Slinton     register Process p;
3909677Slinton 
3919677Slinton     p = process;
39211867Slinton     pcont(p, signo);
3939677Slinton     pc = process->reg[PROGCTR];
39411832Slinton     if (p->status != STOPPED) {
39511867Slinton 	if (p->signo != 0) {
39611867Slinton 	    error("program terminated by signal %d", p->signo);
39714757Slinton 	} else if (not runfirst) {
39818230Slinton 	    if (p->exitval == 0) {
39918230Slinton 		error("program exited");
40018230Slinton 	    } else {
40118230Slinton 		error("program exited with code %d", p->exitval);
40218230Slinton 	    }
40311867Slinton 	}
40411832Slinton     }
4059677Slinton }
4069677Slinton 
4079677Slinton /*
4089677Slinton  * Continue execution up to the next source line.
4099677Slinton  *
4109677Slinton  * There are two ways to define the next source line depending on what
4119677Slinton  * is desired when a procedure or function call is encountered.  Step
4129677Slinton  * stops at the beginning of the procedure or call; next skips over it.
4139677Slinton  */
4149677Slinton 
4159677Slinton /*
4169677Slinton  * Stepc is what is called when the step command is given.
4179677Slinton  * It has to play with the "isstopped" information.
4189677Slinton  */
4199677Slinton 
stepc()4209677Slinton public stepc()
4219677Slinton {
4229677Slinton     if (not isstopped) {
4239677Slinton 	error("can't continue execution");
4249677Slinton     }
4259677Slinton     isstopped = false;
4269677Slinton     dostep(false);
4279677Slinton     isstopped = true;
4289677Slinton }
4299677Slinton 
next()4309677Slinton public next()
4319677Slinton {
43216617Ssam     Address oldfrp, newfrp;
43316617Ssam 
4349677Slinton     if (not isstopped) {
4359677Slinton 	error("can't continue execution");
4369677Slinton     }
4379677Slinton     isstopped = false;
43816617Ssam     oldfrp = reg(FRP);
43916617Ssam     do {
44016617Ssam 	dostep(true);
44116617Ssam 	pc = reg(PROGCTR);
44216617Ssam 	newfrp = reg(FRP);
44316617Ssam     } while (newfrp < oldfrp and newfrp != 0);
4449677Slinton     isstopped = true;
4459677Slinton }
4469677Slinton 
44711867Slinton /*
44816617Ssam  * Continue execution until the current function returns, or,
44916617Ssam  * if the given argument is non-nil, until execution returns to
45016617Ssam  * somewhere within the given function.
45116617Ssam  */
45216617Ssam 
rtnfunc(f)45316617Ssam public rtnfunc (f)
45416617Ssam Symbol f;
45516617Ssam {
45616617Ssam     Address addr;
45716617Ssam     Symbol t;
45816617Ssam 
45916617Ssam     if (not isstopped) {
46016617Ssam 	error("can't continue execution");
46116617Ssam     } else if (f != nil and not isactive(f)) {
46216617Ssam 	error("%s is not active", symname(f));
46316617Ssam     } else {
46416617Ssam 	addr = return_addr();
46516617Ssam 	if (addr == nil) {
46616617Ssam 	    error("no place to return to");
46716617Ssam 	} else {
46816617Ssam 	    isstopped = false;
46916617Ssam 	    contto(addr);
47016617Ssam 	    if (f != nil) {
47116617Ssam 		for (;;) {
47216617Ssam 		    t = whatblock(pc);
47316617Ssam 		    addr = return_addr();
47416617Ssam 		if (t == f or addr == nil) break;
47516617Ssam 		    contto(addr);
47616617Ssam 		}
47716617Ssam 	    }
47818230Slinton 	    if (not bpact()) {
47916617Ssam 		isstopped = true;
48016617Ssam 		printstatus();
48116617Ssam 	    }
48216617Ssam 	}
48316617Ssam     }
48416617Ssam }
48516617Ssam 
48616617Ssam /*
48711867Slinton  * Single-step over the current machine instruction.
48811867Slinton  *
48911867Slinton  * If we're single-stepping by source line we want to step to the
49011867Slinton  * next source line.  Otherwise we're going to continue so there's
49111867Slinton  * no reason to do all the work necessary to single-step to the next
49211867Slinton  * source line.
49311867Slinton  */
49411867Slinton 
stepover()49516617Ssam public stepover()
4969677Slinton {
49711867Slinton     Boolean b;
49811867Slinton 
49916617Ssam     if (traceexec) {
50016617Ssam 	printf("!! stepping over 0x%x\n", process->reg[PROGCTR]);
50116617Ssam     }
50211867Slinton     if (single_stepping) {
50311867Slinton 	dostep(false);
50411867Slinton     } else {
50511867Slinton 	b = inst_tracing;
50611867Slinton 	inst_tracing = true;
50711867Slinton 	dostep(false);
50811867Slinton 	inst_tracing = b;
50911867Slinton     }
51016617Ssam     if (traceexec) {
51116617Ssam 	printf("!! stepped over to 0x%x\n", process->reg[PROGCTR]);
51216617Ssam     }
5139677Slinton }
5149677Slinton 
5159677Slinton /*
51618230Slinton  * Resume execution up to the given address.  We can either ignore
51718230Slinton  * breakpoints (stepto) or catch them (contto).
5189677Slinton  */
5199677Slinton 
stepto(addr)5209677Slinton public stepto(addr)
5219677Slinton Address addr;
5229677Slinton {
52316617Ssam     xto(addr, false);
52416617Ssam }
52516617Ssam 
contto(addr)52616617Ssam private contto (addr)
52716617Ssam Address addr;
52816617Ssam {
52916617Ssam     xto(addr, true);
53016617Ssam }
53116617Ssam 
xto(addr,catchbps)53216617Ssam private xto (addr, catchbps)
53316617Ssam Address addr;
53416617Ssam boolean catchbps;
53516617Ssam {
53616617Ssam     Address curpc;
53716617Ssam 
53816617Ssam     if (catchbps) {
53916617Ssam 	stepover();
5409677Slinton     }
54116617Ssam     curpc = process->reg[PROGCTR];
54216617Ssam     if (addr != curpc) {
54316617Ssam 	if (traceexec) {
54416617Ssam 	    printf("!! stepping from 0x%x to 0x%x\n", curpc, addr);
54516617Ssam 	}
54616617Ssam 	if (catchbps) {
54716617Ssam 	    setallbps();
54816617Ssam 	}
54916617Ssam 	setbp(addr);
55016617Ssam 	resume(DEFSIG);
55116617Ssam 	unsetbp(addr);
55216617Ssam 	if (catchbps) {
55316617Ssam 	    unsetallbps();
55416617Ssam 	}
55516617Ssam 	if (not isbperr()) {
55616617Ssam 	    printstatus();
55716617Ssam 	}
55816617Ssam     }
5599677Slinton }
5609677Slinton 
5619677Slinton /*
5629677Slinton  * Print the status of the process.
5639677Slinton  * This routine does not return.
5649677Slinton  */
5659677Slinton 
printstatus()56633331Sdonn public printstatus ()
5679677Slinton {
56814395Slinton     int status;
56914395Slinton 
5709843Slinton     if (process->status == FINISHED) {
5719843Slinton 	exit(0);
5729843Slinton     } else {
57333331Sdonn 	if (runfirst) {
57433331Sdonn 	    fprintf(stderr, "\nEntering debugger ...\n");
57533331Sdonn 	    printheading();
57633331Sdonn 	    init();
57733331Sdonn 	}
57816617Ssam 	setcurfunc(whatblock(pc));
5799677Slinton 	getsrcpos();
5809843Slinton 	if (process->signo == SIGINT) {
5819843Slinton 	    isstopped = true;
5829843Slinton 	    printerror();
5839843Slinton 	} else if (isbperr() and isstopped) {
5849843Slinton 	    printf("stopped ");
58511172Slinton 	    printloc();
58611172Slinton 	    putchar('\n');
5879843Slinton 	    if (curline > 0) {
5889843Slinton 		printlines(curline, curline);
5899843Slinton 	    } else {
5909843Slinton 		printinst(pc, pc);
5919843Slinton 	    }
5929843Slinton 	    erecover();
5939677Slinton 	} else {
5949843Slinton 	    fixintr();
5959677Slinton 	    isstopped = true;
5969677Slinton 	    printerror();
5979677Slinton 	}
5989677Slinton     }
5999677Slinton }
6009677Slinton 
6019677Slinton /*
60211172Slinton  * Print out the current location in the debuggee.
60311172Slinton  */
60411172Slinton 
printloc()60511172Slinton public printloc()
60611172Slinton {
60711172Slinton     printf("in ");
60811172Slinton     printname(stdout, curfunc);
60911172Slinton     putchar(' ');
61014757Slinton     if (curline > 0 and not useInstLoc) {
61111172Slinton 	printsrcpos();
61211172Slinton     } else {
61314757Slinton 	useInstLoc = false;
61414757Slinton 	curline = 0;
61511172Slinton 	printf("at 0x%x", pc);
61611172Slinton     }
61711172Slinton }
61811172Slinton 
61911172Slinton /*
6209677Slinton  * Some functions for testing the state of the process.
6219677Slinton  */
6229677Slinton 
notstarted(p)6239677Slinton public Boolean notstarted(p)
6249677Slinton Process p;
6259677Slinton {
6269677Slinton     return (Boolean) (p->status == NOTSTARTED);
6279677Slinton }
6289677Slinton 
isfinished(p)6299677Slinton public Boolean isfinished(p)
6309677Slinton Process p;
6319677Slinton {
6329677Slinton     return (Boolean) (p->status == FINISHED);
6339677Slinton }
6349677Slinton 
6359677Slinton /*
63618230Slinton  * Predicate to test if the reason the process stopped was because
63718230Slinton  * of a breakpoint.  If so, as a side effect clear the local copy of
63818230Slinton  * signal handler associated with process.  We must do this so as to
63918230Slinton  * not confuse future stepping or continuing by possibly concluding
64018230Slinton  * the process should continue with a SIGTRAP handler.
6419677Slinton  */
6429677Slinton 
isbperr()64318230Slinton public boolean isbperr()
64418230Slinton {
64518230Slinton     Process p;
64618230Slinton     boolean b;
64718230Slinton 
64818230Slinton     p = process;
64918230Slinton     if (p->status == STOPPED and p->signo == SIGTRAP) {
65018230Slinton 	b = true;
65118230Slinton 	p->sigstatus = 0;
65218230Slinton     } else {
65318230Slinton 	b = false;
65418230Slinton     }
65518230Slinton     return b;
65618230Slinton }
65718230Slinton 
65818230Slinton /*
65918230Slinton  * Return the signal number that stopped the process.
66018230Slinton  */
66118230Slinton 
errnum(p)66218230Slinton public integer errnum (p)
6639677Slinton Process p;
6649677Slinton {
6659677Slinton     return p->signo;
6669677Slinton }
6679677Slinton 
66818230Slinton /*
66918230Slinton  * Return the signal code associated with the signal.
67018230Slinton  */
67118230Slinton 
errcode(p)67218230Slinton public integer errcode (p)
67316931Ssam Process p;
67416931Ssam {
67516931Ssam     return p->sigcode;
67616931Ssam }
67716931Ssam 
6789677Slinton /*
6799677Slinton  * Return the termination code of the process.
6809677Slinton  */
6819677Slinton 
exitcode(p)68218230Slinton public integer exitcode (p)
6839677Slinton Process p;
6849677Slinton {
6859677Slinton     return p->exitval;
6869677Slinton }
6879677Slinton 
6889677Slinton /*
6899677Slinton  * These routines are used to access the debuggee process from
6909677Slinton  * outside this module.
6919677Slinton  *
6929677Slinton  * They invoke "pio" which eventually leads to a call to "ptrace".
69314757Slinton  * The system generates an I/O error when a ptrace fails.  During reads
69414757Slinton  * these are ignored, during writes they are reported as an error, and
69514757Slinton  * for anything else they cause a fatal error.
6969677Slinton  */
6979677Slinton 
6989677Slinton extern Intfunc *onsyserr();
6999677Slinton 
7009677Slinton private badaddr;
70114757Slinton private read_err(), write_err();
7029677Slinton 
7039677Slinton /*
7049677Slinton  * Read from the process' instruction area.
7059677Slinton  */
7069677Slinton 
iread(buff,addr,nbytes)7079677Slinton public iread(buff, addr, nbytes)
7089677Slinton char *buff;
7099677Slinton Address addr;
7109677Slinton int nbytes;
7119677Slinton {
7129677Slinton     Intfunc *f;
7139677Slinton 
71414757Slinton     f = onsyserr(EIO, read_err);
7159677Slinton     badaddr = addr;
7169677Slinton     if (coredump) {
7179677Slinton 	coredump_readtext(buff, addr, nbytes);
7189677Slinton     } else {
7199677Slinton 	pio(process, PREAD, TEXTSEG, buff, addr, nbytes);
7209677Slinton     }
7219677Slinton     onsyserr(EIO, f);
7229677Slinton }
7239677Slinton 
7249677Slinton /*
7259677Slinton  * Write to the process' instruction area, usually in order to set
7269677Slinton  * or unset a breakpoint.
7279677Slinton  */
7289677Slinton 
iwrite(buff,addr,nbytes)7299677Slinton public iwrite(buff, addr, nbytes)
7309677Slinton char *buff;
7319677Slinton Address addr;
7329677Slinton int nbytes;
7339677Slinton {
7349677Slinton     Intfunc *f;
7359677Slinton 
7369677Slinton     if (coredump) {
7379677Slinton 	error("no process to write to");
7389677Slinton     }
73914757Slinton     f = onsyserr(EIO, write_err);
7409677Slinton     badaddr = addr;
7419677Slinton     pio(process, PWRITE, TEXTSEG, buff, addr, nbytes);
7429677Slinton     onsyserr(EIO, f);
7439677Slinton }
7449677Slinton 
7459677Slinton /*
7469677Slinton  * Read for the process' data area.
7479677Slinton  */
7489677Slinton 
dread(buff,addr,nbytes)7499677Slinton public dread(buff, addr, nbytes)
7509677Slinton char *buff;
7519677Slinton Address addr;
7529677Slinton int nbytes;
7539677Slinton {
7549677Slinton     Intfunc *f;
7559677Slinton 
7569677Slinton     badaddr = addr;
7579677Slinton     if (coredump) {
75818230Slinton 	f = onsyserr(EFAULT, read_err);
7599677Slinton 	coredump_readdata(buff, addr, nbytes);
76018230Slinton 	onsyserr(EFAULT, f);
7619677Slinton     } else {
76218230Slinton 	f = onsyserr(EIO, read_err);
7639677Slinton 	pio(process, PREAD, DATASEG, buff, addr, nbytes);
76418230Slinton 	onsyserr(EIO, f);
7659677Slinton     }
7669677Slinton }
7679677Slinton 
7689677Slinton /*
7699677Slinton  * Write to the process' data area.
7709677Slinton  */
7719677Slinton 
dwrite(buff,addr,nbytes)7729677Slinton public dwrite(buff, addr, nbytes)
7739677Slinton char *buff;
7749677Slinton Address addr;
7759677Slinton int nbytes;
7769677Slinton {
7779677Slinton     Intfunc *f;
7789677Slinton 
7799677Slinton     if (coredump) {
7809677Slinton 	error("no process to write to");
7819677Slinton     }
78214757Slinton     f = onsyserr(EIO, write_err);
7839677Slinton     badaddr = addr;
7849677Slinton     pio(process, PWRITE, DATASEG, buff, addr, nbytes);
7859677Slinton     onsyserr(EIO, f);
7869677Slinton }
7879677Slinton 
7889677Slinton /*
78914757Slinton  * Trap for errors in reading or writing to a process.
79014757Slinton  * The current approach is to "ignore" read errors and complain
79114757Slinton  * bitterly about write errors.
7929677Slinton  */
7939677Slinton 
read_err()79414757Slinton private read_err()
7959677Slinton {
79611560Slinton     /*
79714757Slinton      * Ignore.
79811560Slinton      */
7999677Slinton }
8009677Slinton 
write_err()80114757Slinton private write_err()
80214757Slinton {
80314757Slinton     error("can't write to process (address 0x%x)", badaddr);
80414757Slinton }
80514757Slinton 
8069677Slinton /*
8079677Slinton  * Ptrace interface.
8089677Slinton  */
8099677Slinton 
8109677Slinton #define WMASK           (~(sizeof(Word) - 1))
81133331Sdonn #define cachehash(addr) ((unsigned) ((addr >> 2) % CACHESIZE))
8129677Slinton 
8139677Slinton #define FIRSTSIG        SIGINT
8149677Slinton #define LASTSIG         SIGQUIT
8159677Slinton #define ischild(pid)    ((pid) == 0)
81618230Slinton #define traceme()       ptrace(0, 0, 0, 0)
8179677Slinton #define setrep(n)       (1 << ((n)-1))
8189677Slinton #define istraced(p)     (p->sigset&setrep(p->signo))
8199677Slinton 
8209677Slinton /*
82118230Slinton  * Ptrace options (specified in first argument).
82218230Slinton  */
82318230Slinton 
82418230Slinton #define UREAD   3       /* read from process's user structure */
82518230Slinton #define UWRITE  6       /* write to process's user structure */
82618230Slinton #define IREAD   1       /* read from process's instruction space */
82718230Slinton #define IWRITE  4       /* write to process's instruction space */
82818230Slinton #define DREAD   2       /* read from process's data space */
82918230Slinton #define DWRITE  5       /* write to process's data space */
83018230Slinton #define CONT    7       /* continue stopped process */
83118230Slinton #define SSTEP   9       /* continue for approximately one instruction */
83218230Slinton #define PKILL   8       /* terminate the process */
83318230Slinton 
83433331Sdonn #ifdef IRIS
83533331Sdonn #   define readreg(p, r)	ptrace(10, p->pid, r, 0)
83633331Sdonn #   define writereg(p, r, v)	ptrace(11, p->pid, r, v)
83733331Sdonn #else
83833331Sdonn #   define readreg(p, r)	ptrace(UREAD, p->pid, regloc(r), 0);
83933331Sdonn #   define writereg(p, r, v)	ptrace(UWRITE, p->pid, regloc(r), v);
84033331Sdonn #endif
84133331Sdonn 
84218230Slinton /*
8439677Slinton  * Start up a new process by forking and exec-ing the
8449677Slinton  * given argument list, returning when the process is loaded
8459677Slinton  * and ready to execute.  The PROCESS information (pointed to
8469677Slinton  * by the first argument) is appropriately filled.
8479677Slinton  *
8489677Slinton  * If the given PROCESS structure is associated with an already running
8499677Slinton  * process, we terminate it.
8509677Slinton  */
8519677Slinton 
8529677Slinton /* VARARGS2 */
pstart(p,argv,infile,outfile)8539677Slinton private pstart(p, argv, infile, outfile)
8549677Slinton Process p;
8559677Slinton String argv[];
8569677Slinton String infile;
8579677Slinton String outfile;
8589677Slinton {
8599677Slinton     int status;
8609677Slinton 
86116617Ssam     if (p->pid != 0) {
86216617Ssam 	pterm(p);
86318230Slinton 	cacheflush(p);
8649677Slinton     }
86518230Slinton     fflush(stdout);
8669677Slinton     psigtrace(p, SIGTRAP, true);
86733331Sdonn #   ifdef IRIS
86833331Sdonn 	p->pid = fork();
86933331Sdonn #   else
87033331Sdonn 	p->pid = vfork();
87133331Sdonn #   endif
87214395Slinton     if (p->pid == -1) {
8739677Slinton 	panic("can't fork");
8749677Slinton     }
8759677Slinton     if (ischild(p->pid)) {
87618230Slinton 	nocatcherrs();
8779677Slinton 	traceme();
8789677Slinton 	if (infile != nil) {
87916617Ssam 	    infrom(infile);
8809677Slinton 	}
8819677Slinton 	if (outfile != nil) {
88216617Ssam 	    outto(outfile);
8839677Slinton 	}
88411832Slinton 	execv(argv[0], argv);
88511172Slinton 	_exit(1);
8869677Slinton     }
8879677Slinton     pwait(p->pid, &status);
8889677Slinton     getinfo(p, status);
8899677Slinton     if (p->status != STOPPED) {
89018230Slinton 	beginerrmsg();
89118230Slinton 	fprintf(stderr, "warning: cannot execute %s\n", argv[0]);
89218230Slinton     } else {
89318230Slinton 	ptraced(p->pid);
8949677Slinton     }
8959677Slinton }
8969677Slinton 
8979677Slinton /*
89816617Ssam  * Terminate a ptrace'd process.
89916617Ssam  */
90016617Ssam 
pterm(p)90116617Ssam public pterm (p)
90216617Ssam Process p;
90316617Ssam {
90416617Ssam     integer status;
90516617Ssam 
90616617Ssam     if (p != nil and p->pid != 0) {
90718230Slinton 	ptrace(PKILL, p->pid, 0, 0);
90816617Ssam 	pwait(p->pid, &status);
90916617Ssam 	unptraced(p->pid);
91016617Ssam     }
91116617Ssam }
91216617Ssam 
91316617Ssam /*
91411867Slinton  * Continue a stopped process.  The first argument points to a Process
91511867Slinton  * structure.  Before the process is restarted it's user area is modified
91611867Slinton  * according to the values in the structure.  When this routine finishes,
9179677Slinton  * the structure has the new values from the process's user area.
9189677Slinton  *
9199677Slinton  * Pcont terminates when the process stops with a signal pending that
9209677Slinton  * is being traced (via psigtrace), or when the process terminates.
9219677Slinton  */
9229677Slinton 
pcont(p,signo)92311867Slinton private pcont(p, signo)
9249677Slinton Process p;
92511867Slinton int signo;
9269677Slinton {
92716617Ssam     int s, status;
9289677Slinton 
9299677Slinton     if (p->pid == 0) {
93018230Slinton 	error("program is not active");
9319677Slinton     }
93216617Ssam     s = signo;
9339677Slinton     do {
93416617Ssam 	setinfo(p, s);
93516617Ssam 	if (traceexec) {
93616617Ssam 	    printf("!! pcont from 0x%x with signal %d (%d)\n",
93716617Ssam 		p->reg[PROGCTR], s, p->signo);
93816617Ssam 	    fflush(stdout);
93916617Ssam 	}
9409677Slinton 	sigs_off();
94118230Slinton 	if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) {
94214395Slinton 	    panic("error %d trying to continue process", errno);
9439677Slinton 	}
9449677Slinton 	pwait(p->pid, &status);
9459677Slinton 	sigs_on();
9469677Slinton 	getinfo(p, status);
94718230Slinton 	if (p->status == STOPPED and traceexec and not istraced(p)) {
94818230Slinton 	    printf("!! ignored signal %d at 0x%x\n",
94918230Slinton 		p->signo, p->reg[PROGCTR]);
95016617Ssam 	    fflush(stdout);
95116617Ssam 	}
95216617Ssam 	s = p->signo;
9539677Slinton     } while (p->status == STOPPED and not istraced(p));
95416617Ssam     if (traceexec) {
95516617Ssam 	printf("!! pcont to 0x%x on signal %d\n", p->reg[PROGCTR], p->signo);
95616617Ssam 	fflush(stdout);
95716617Ssam     }
9589677Slinton }
9599677Slinton 
9609677Slinton /*
9619677Slinton  * Single step as best ptrace can.
9629677Slinton  */
9639677Slinton 
pstep(p,signo)96416617Ssam public pstep(p, signo)
9659677Slinton Process p;
96616617Ssam integer signo;
9679677Slinton {
96818230Slinton     int s, status;
9699677Slinton 
97018230Slinton     s = signo;
97118230Slinton     do {
97218230Slinton 	setinfo(p, s);
97318230Slinton 	if (traceexec) {
97418230Slinton 	    printf("!! pstep from 0x%x with signal %d (%d)\n",
97518230Slinton 		p->reg[PROGCTR], s, p->signo);
97618230Slinton 	    fflush(stdout);
97718230Slinton 	}
97818230Slinton 	sigs_off();
97918230Slinton 	if (ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo) < 0) {
98018230Slinton 	    panic("error %d trying to step process", errno);
98118230Slinton 	}
98218230Slinton 	pwait(p->pid, &status);
98318230Slinton 	sigs_on();
98418230Slinton 	getinfo(p, status);
98533331Sdonn #	if mc68000 || m68000
98633331Sdonn 	    if (p->status == STOPPED and p->signo == SIGTRAP) {
98733331Sdonn 		p->reg[PROGCTR] += 2;
98833331Sdonn 	    }
98933331Sdonn #	endif
99018230Slinton 	if (p->status == STOPPED and traceexec and not istraced(p)) {
99118230Slinton 	    printf("!! pstep ignored signal %d at 0x%x\n",
99218230Slinton 		p->signo, p->reg[PROGCTR]);
99318230Slinton 	    fflush(stdout);
99418230Slinton 	}
99518230Slinton 	s = p->signo;
99618230Slinton     } while (p->status == STOPPED and not istraced(p));
99716617Ssam     if (traceexec) {
99818230Slinton 	printf("!! pstep to 0x%x on signal %d\n",
99918230Slinton 	    p->reg[PROGCTR], p->signo);
100016617Ssam 	fflush(stdout);
100116617Ssam     }
100216617Ssam     if (p->status != STOPPED) {
100318230Slinton 	if (p->exitval == 0) {
100418230Slinton 	    error("program exited\n");
100518230Slinton 	} else {
100618230Slinton 	    error("program exited with code %d\n", p->exitval);
100718230Slinton 	}
100816617Ssam     }
10099677Slinton }
10109677Slinton 
10119677Slinton /*
10129677Slinton  * Return from execution when the given signal is pending.
10139677Slinton  */
10149677Slinton 
psigtrace(p,sig,sw)10159677Slinton public psigtrace(p, sig, sw)
10169677Slinton Process p;
10179677Slinton int sig;
10189677Slinton Boolean sw;
10199677Slinton {
10209677Slinton     if (sw) {
10219677Slinton 	p->sigset |= setrep(sig);
10229677Slinton     } else {
10239677Slinton 	p->sigset &= ~setrep(sig);
10249677Slinton     }
10259677Slinton }
10269677Slinton 
10279677Slinton /*
10289677Slinton  * Don't catch any signals.
10299677Slinton  * Particularly useful when letting a process finish uninhibited.
10309677Slinton  */
10319677Slinton 
unsetsigtraces(p)10329677Slinton public unsetsigtraces(p)
10339677Slinton Process p;
10349677Slinton {
10359677Slinton     p->sigset = 0;
10369677Slinton }
10379677Slinton 
10389677Slinton /*
10399677Slinton  * Turn off attention to signals not being caught.
10409677Slinton  */
10419677Slinton 
104239163Sbostic private sig_t sigfunc[NSIG];
10439677Slinton 
sigs_off()10449677Slinton private sigs_off()
10459677Slinton {
10469677Slinton     register int i;
10479677Slinton 
10489677Slinton     for (i = FIRSTSIG; i < LASTSIG; i++) {
10499677Slinton 	if (i != SIGKILL) {
10509677Slinton 	    sigfunc[i] = signal(i, SIG_IGN);
10519677Slinton 	}
10529677Slinton     }
10539677Slinton }
10549677Slinton 
10559677Slinton /*
10569677Slinton  * Turn back on attention to signals.
10579677Slinton  */
10589677Slinton 
sigs_on()10599677Slinton private sigs_on()
10609677Slinton {
10619677Slinton     register int i;
10629677Slinton 
10639677Slinton     for (i = FIRSTSIG; i < LASTSIG; i++) {
10649677Slinton 	if (i != SIGKILL) {
10659677Slinton 	    signal(i, sigfunc[i]);
10669677Slinton 	}
10679677Slinton     }
10689677Slinton }
10699677Slinton 
10709677Slinton /*
10719677Slinton  * Get process information from user area.
10729677Slinton  */
10739677Slinton 
getinfo(p,status)107433331Sdonn private getinfo (p, status)
10759677Slinton register Process p;
10769677Slinton register int status;
10779677Slinton {
10789677Slinton     register int i;
107916617Ssam     Address addr;
10809677Slinton 
10819677Slinton     p->signo = (status&0177);
10829677Slinton     p->exitval = ((status >> 8)&0377);
10839677Slinton     if (p->signo != STOPPED) {
10849677Slinton 	p->status = FINISHED;
108514757Slinton 	p->pid = 0;
108616617Ssam 	p->reg[PROGCTR] = 0;
10879677Slinton     } else {
10889677Slinton 	p->status = p->signo;
10899677Slinton 	p->signo = p->exitval;
10909677Slinton 	p->exitval = 0;
109133331Sdonn #       ifdef IRIS
109233331Sdonn 	    p->mask = readreg(p, RPS);
109333331Sdonn #       else
109433331Sdonn 	    p->sigcode = ptrace(UREAD, p->pid, &((struct user *)0)->u_code, 0);
109533331Sdonn 	    p->mask = readreg(p, PS);
109633331Sdonn #       endif
10979677Slinton 	for (i = 0; i < NREG; i++) {
109833331Sdonn 	    p->reg[i] = readreg(p, rloc[i]);
10999677Slinton 	    p->oreg[i] = p->reg[i];
11009677Slinton 	}
110133331Sdonn #       ifdef mc68000
110233331Sdonn 	    if (p->status == STOPPED and p->signo == SIGTRAP and
110333331Sdonn 		p->reg[PROGCTR] > CODESTART
110433331Sdonn 	    ) {
110533331Sdonn 		p->reg[PROGCTR] -= 2;
110633331Sdonn 	    }
110733331Sdonn #       endif
110811768Slinton 	savetty(stdout, &(p->ttyinfo));
110916617Ssam 	addr = (Address) &(((struct user *) 0)->u_signal[p->signo]);
111018230Slinton 	p->sigstatus = (Address) ptrace(UREAD, p->pid, addr, 0);
11119677Slinton     }
11129677Slinton }
11139677Slinton 
11149677Slinton /*
11159677Slinton  * Set process's user area information from given process structure.
11169677Slinton  */
11179677Slinton 
setinfo(p,signo)111833331Sdonn private setinfo (p, signo)
11199677Slinton register Process p;
112011867Slinton int signo;
11219677Slinton {
11229677Slinton     register int i;
11239677Slinton     register int r;
11249677Slinton 
112514757Slinton     if (signo == DEFSIG) {
112616617Ssam 	if (istraced(p) and (p->sigstatus == 0 or p->sigstatus == 1)) {
112714757Slinton 	    p->signo = 0;
112814757Slinton 	}
112914757Slinton     } else {
113011867Slinton 	p->signo = signo;
11319677Slinton     }
11329677Slinton     for (i = 0; i < NREG; i++) {
11339677Slinton 	if ((r = p->reg[i]) != p->oreg[i]) {
113433331Sdonn 	    writereg(p, rloc[i], r);
11359677Slinton 	}
11369677Slinton     }
113711768Slinton     restoretty(stdout, &(p->ttyinfo));
11389677Slinton }
11399677Slinton 
11409677Slinton /*
114116617Ssam  * Return the address associated with the current signal.
114216617Ssam  * (Plus two since the address points to the beginning of a procedure).
114316617Ssam  */
114416617Ssam 
usignal(p)114516617Ssam public Address usignal (p)
114616617Ssam Process p;
114716617Ssam {
114816617Ssam     Address r;
114916617Ssam 
115016617Ssam     r = p->sigstatus;
115116617Ssam     if (r != 0 and r != 1) {
115233331Sdonn 	r += FUNCOFFSET;
115316617Ssam     }
115416617Ssam     return r;
115516617Ssam }
115616617Ssam 
115716617Ssam /*
11589677Slinton  * Structure for reading and writing by words, but dealing with bytes.
11599677Slinton  */
11609677Slinton 
11619677Slinton typedef union {
11629677Slinton     Word pword;
11639677Slinton     Byte pbyte[sizeof(Word)];
11649677Slinton } Pword;
11659677Slinton 
11669677Slinton /*
11679677Slinton  * Read (write) from (to) the process' address space.
11689677Slinton  * We must deal with ptrace's inability to look anywhere other
11699677Slinton  * than at a word boundary.
11709677Slinton  */
11719677Slinton 
11729677Slinton private Word fetch();
11739677Slinton private store();
11749677Slinton 
pio(p,op,seg,buff,addr,nbytes)11759677Slinton private pio(p, op, seg, buff, addr, nbytes)
11769677Slinton Process p;
11779677Slinton PioOp op;
11789677Slinton PioSeg seg;
11799677Slinton char *buff;
11809677Slinton Address addr;
11819677Slinton int nbytes;
11829677Slinton {
11839677Slinton     register int i;
11849677Slinton     register Address newaddr;
11859677Slinton     register char *cp;
11869677Slinton     char *bufend;
11879677Slinton     Pword w;
11889677Slinton     Address wordaddr;
11899677Slinton     int byteoff;
11909677Slinton 
11919677Slinton     if (p->status != STOPPED) {
11929677Slinton 	error("program is not active");
11939677Slinton     }
11949677Slinton     cp = buff;
11959677Slinton     newaddr = addr;
11969677Slinton     wordaddr = (newaddr&WMASK);
11979677Slinton     if (wordaddr != newaddr) {
11989677Slinton 	w.pword = fetch(p, seg, wordaddr);
11999677Slinton 	for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) {
12009677Slinton 	    if (op == PREAD) {
12019677Slinton 		*cp++ = w.pbyte[i];
12029677Slinton 	    } else {
12039677Slinton 		w.pbyte[i] = *cp++;
12049677Slinton 	    }
12059677Slinton 	    nbytes--;
12069677Slinton 	}
12079677Slinton 	if (op == PWRITE) {
12089677Slinton 	    store(p, seg, wordaddr, w.pword);
12099677Slinton 	}
12109677Slinton 	newaddr = wordaddr + sizeof(Word);
12119677Slinton     }
12129677Slinton     byteoff = (nbytes&(~WMASK));
12139677Slinton     nbytes -= byteoff;
12149677Slinton     bufend = cp + nbytes;
121526333Ssam #ifdef tahoe
121626333Ssam     if (((int)cp)&WMASK) {
121726333Ssam 	/*
121826333Ssam 	 * Must copy a byte at a time, buffer not word addressable.
121926333Ssam 	 */
122026333Ssam 	while (cp < bufend) {
122126333Ssam 	    if (op == PREAD) {
122226333Ssam 		w.pword = fetch(p, seg, newaddr);
122326333Ssam 		for (i = 0; i < sizeof(Word); i++)
122426333Ssam 		    *cp++ = w.pbyte[i];
122526333Ssam 	    } else {
122626333Ssam 		for (i = 0; i < sizeof(Word); i++)
122726333Ssam 		    w.pbyte[i] = *cp++;
122826333Ssam 		store(p, seg, newaddr, w.pword);
122926333Ssam 	    }
123026333Ssam 	    newaddr += sizeof(Word);
123126333Ssam 	}
123226333Ssam     } else {
123326333Ssam     /*
123426333Ssam      * Buffer, word aligned, act normally...
123526333Ssam      */
123626333Ssam #endif
12379677Slinton     while (cp < bufend) {
12389677Slinton 	if (op == PREAD) {
12399677Slinton 	    *((Word *) cp) = fetch(p, seg, newaddr);
12409677Slinton 	} else {
12419677Slinton 	    store(p, seg, newaddr, *((Word *) cp));
12429677Slinton 	}
12439677Slinton 	cp += sizeof(Word);
12449677Slinton 	newaddr += sizeof(Word);
12459677Slinton     }
124626333Ssam #ifdef tahoe
124726333Ssam     }
124826333Ssam #endif
12499677Slinton     if (byteoff > 0) {
12509677Slinton 	w.pword = fetch(p, seg, newaddr);
12519677Slinton 	for (i = 0; i < byteoff; i++) {
12529677Slinton 	    if (op == PREAD) {
12539677Slinton 		*cp++ = w.pbyte[i];
12549677Slinton 	    } else {
12559677Slinton 		w.pbyte[i] = *cp++;
12569677Slinton 	    }
12579677Slinton 	}
12589677Slinton 	if (op == PWRITE) {
12599677Slinton 	    store(p, seg, newaddr, w.pword);
12609677Slinton 	}
12619677Slinton     }
12629677Slinton }
12639677Slinton 
12649677Slinton /*
12659677Slinton  * Get a word from a process at the given address.
12669677Slinton  * The address is assumed to be on a word boundary.
12679677Slinton  *
12689677Slinton  * A simple cache scheme is used to avoid redundant ptrace calls
12699677Slinton  * to the instruction space since it is assumed to be pure.
12709677Slinton  *
12719677Slinton  * It is necessary to use a write-through scheme so that
12729677Slinton  * breakpoints right next to each other don't interfere.
12739677Slinton  */
12749677Slinton 
12759677Slinton private Integer nfetchs, nreads, nwrites;
12769677Slinton 
fetch(p,seg,addr)12779677Slinton private Word fetch(p, seg, addr)
12789677Slinton Process p;
12799677Slinton PioSeg seg;
12809677Slinton register int addr;
12819677Slinton {
12829677Slinton     register CacheWord *wp;
12839677Slinton     register Word w;
12849677Slinton 
12859677Slinton     switch (seg) {
12869677Slinton 	case TEXTSEG:
12879677Slinton 	    ++nfetchs;
12889677Slinton 	    wp = &p->word[cachehash(addr)];
12899677Slinton 	    if (addr == 0 or wp->addr != addr) {
12909677Slinton 		++nreads;
129118230Slinton 		w = ptrace(IREAD, p->pid, addr, 0);
12929677Slinton 		wp->addr = addr;
12939677Slinton 		wp->val = w;
12949677Slinton 	    } else {
12959677Slinton 		w = wp->val;
12969677Slinton 	    }
12979677Slinton 	    break;
12989677Slinton 
12999677Slinton 	case DATASEG:
130018230Slinton 	    w = ptrace(DREAD, p->pid, addr, 0);
13019677Slinton 	    break;
13029677Slinton 
13039677Slinton 	default:
13049677Slinton 	    panic("fetch: bad seg %d", seg);
13059677Slinton 	    /* NOTREACHED */
13069677Slinton     }
13079677Slinton     return w;
13089677Slinton }
13099677Slinton 
13109677Slinton /*
13119677Slinton  * Put a word into the process' address space at the given address.
13129677Slinton  * The address is assumed to be on a word boundary.
13139677Slinton  */
13149677Slinton 
store(p,seg,addr,data)13159677Slinton private store(p, seg, addr, data)
13169677Slinton Process p;
13179677Slinton PioSeg seg;
13189677Slinton int addr;
13199677Slinton Word data;
13209677Slinton {
13219677Slinton     register CacheWord *wp;
13229677Slinton 
13239677Slinton     switch (seg) {
13249677Slinton 	case TEXTSEG:
13259677Slinton 	    ++nwrites;
13269677Slinton 	    wp = &p->word[cachehash(addr)];
13279677Slinton 	    wp->addr = addr;
13289677Slinton 	    wp->val = data;
132918230Slinton 	    ptrace(IWRITE, p->pid, addr, data);
13309677Slinton 	    break;
13319677Slinton 
13329677Slinton 	case DATASEG:
133318230Slinton 	    ptrace(DWRITE, p->pid, addr, data);
13349677Slinton 	    break;
13359677Slinton 
13369677Slinton 	default:
13379677Slinton 	    panic("store: bad seg %d", seg);
13389677Slinton 	    /* NOTREACHED */
13399677Slinton     }
13409677Slinton }
13419677Slinton 
134218230Slinton /*
134318230Slinton  * Flush the instruction cache associated with a process.
134418230Slinton  */
134518230Slinton 
cacheflush(p)134618230Slinton private cacheflush (p)
134718230Slinton Process p;
134818230Slinton {
134918230Slinton     bzero(p->word, sizeof(p->word));
135018230Slinton }
135118230Slinton 
printptraceinfo()13529677Slinton public printptraceinfo()
13539677Slinton {
13549677Slinton     printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites);
13559677Slinton }
13569677Slinton 
13579677Slinton /*
135816617Ssam  * Redirect input.
135916617Ssam  * Assuming this is called from a child, we should be careful to avoid
136016617Ssam  * (possibly) shared standard I/O buffers.
13619677Slinton  */
13629677Slinton 
infrom(filename)136316617Ssam private infrom (filename)
136416617Ssam String filename;
136516617Ssam {
136616617Ssam     Fileid in;
136716617Ssam 
136816617Ssam     in = open(filename, 0);
136916617Ssam     if (in == -1) {
137016617Ssam 	write(2, "can't read ", 11);
137116617Ssam 	write(2, filename, strlen(filename));
137216617Ssam 	write(2, "\n", 1);
137316617Ssam 	_exit(1);
137416617Ssam     }
137516617Ssam     fswap(0, in);
137616617Ssam }
137716617Ssam 
137816617Ssam /*
137916617Ssam  * Redirect standard output.
138016617Ssam  * Same assumptions as for "infrom" above.
138116617Ssam  */
138216617Ssam 
outto(filename)138316617Ssam private outto (filename)
138416617Ssam String filename;
138516617Ssam {
138616617Ssam     Fileid out;
138716617Ssam 
138816617Ssam     out = creat(filename, 0666);
138916617Ssam     if (out == -1) {
139016617Ssam 	write(2, "can't write ", 12);
139116617Ssam 	write(2, filename, strlen(filename));
139216617Ssam 	write(2, "\n", 1);
139316617Ssam 	_exit(1);
139416617Ssam     }
139516617Ssam     fswap(1, out);
139616617Ssam }
139716617Ssam 
139816617Ssam /*
139916617Ssam  * Swap file numbers, useful for redirecting standard input or output.
140016617Ssam  */
140116617Ssam 
fswap(oldfd,newfd)14029677Slinton private fswap(oldfd, newfd)
140316617Ssam Fileid oldfd;
140416617Ssam Fileid newfd;
14059677Slinton {
14069677Slinton     if (oldfd != newfd) {
14079677Slinton 	close(oldfd);
14089677Slinton 	dup(newfd);
14099677Slinton 	close(newfd);
14109677Slinton     }
14119677Slinton }
141216928Ssam 
141316928Ssam /*
141418230Slinton  * Signal name manipulation.
141516928Ssam  */
141618230Slinton 
141718230Slinton private String signames[NSIG] = {
141818230Slinton     0,
141918230Slinton     "HUP", "INT", "QUIT", "ILL", "TRAP",
142018230Slinton     "IOT", "EMT", "FPE", "KILL", "BUS",
142118230Slinton     "SEGV", "SYS", "PIPE", "ALRM", "TERM",
142218230Slinton     0, "STOP", "TSTP", "CONT", "CHLD",
142318230Slinton     "TTIN", "TTOU", "TINT", "XCPU", "XFSZ",
142426333Ssam     "VTALRM", "PROF", "WINCH", "USR1", "USR2"
142516928Ssam };
142616928Ssam 
142716928Ssam /*
142818230Slinton  * Get the signal number associated with a given name.
142918230Slinton  * The name is first translated to upper case if necessary.
143016928Ssam  */
143118230Slinton 
siglookup(s)143218230Slinton public integer siglookup (s)
143316928Ssam String s;
143416928Ssam {
143518230Slinton     register char *p, *q;
143618230Slinton     char buf[100];
143718230Slinton     integer i;
143816928Ssam 
143918230Slinton     p = s;
144018230Slinton     q = buf;
144118230Slinton     while (*p != '\0') {
144218230Slinton 	if (*p >= 'a' and *p <= 'z') {
144318230Slinton 	    *q = (*p - 'a') + 'A';
144418230Slinton 	} else {
144518230Slinton 	    *q = *p;
144618230Slinton 	}
144718230Slinton 	++p;
144818230Slinton 	++q;
144918230Slinton     }
145018230Slinton     *q = '\0';
145118230Slinton     p = buf;
145218230Slinton     if (buf[0] == 'S' and buf[1] == 'I' and buf[2] == 'G') {
145318230Slinton 	p += 3;
145418230Slinton     }
145518230Slinton     i = 1;
145618230Slinton     for (;;) {
145718230Slinton 	if (i >= sizeof(signames) div sizeof(signames[0])) {
145818230Slinton 	    error("signal \"%s\" unknown", s);
145918230Slinton 	    i = 0;
146018230Slinton 	    break;
146118230Slinton 	}
146218230Slinton 	if (signames[i] != nil and streq(signames[i], p)) {
146318230Slinton 	    break;
146418230Slinton 	}
146518230Slinton 	++i;
146618230Slinton     }
146718230Slinton     return i;
146816928Ssam }
146916928Ssam 
147016928Ssam /*
147118230Slinton  * Print all signals being ignored by the debugger.
147218230Slinton  * These signals are auotmatically
147316928Ssam  * passed on to the debugged process.
147416928Ssam  */
147518230Slinton 
printsigsignored(p)147618230Slinton public printsigsignored (p)
147716931Ssam Process p;
147816928Ssam {
147916931Ssam     printsigs(~p->sigset);
148016928Ssam }
148116928Ssam 
148216928Ssam /*
148316928Ssam  * Print all signals being intercepted by
148416928Ssam  * the debugger for the specified process.
148516928Ssam  */
148618230Slinton 
printsigscaught(p)148716931Ssam public printsigscaught(p)
148816931Ssam Process p;
148916928Ssam {
149016931Ssam     printsigs(p->sigset);
149116931Ssam }
149216931Ssam 
printsigs(set)149318230Slinton private printsigs (set)
149418230Slinton integer set;
149516931Ssam {
149618230Slinton     integer s;
149718230Slinton     char separator[2];
149816931Ssam 
149918230Slinton     separator[0] = '\0';
150018230Slinton     for (s = 1; s < sizeof(signames) div sizeof(signames[0]); s++) {
150118230Slinton 	if (set & setrep(s)) {
150218230Slinton 	    if (signames[s] != nil) {
150318230Slinton 		printf("%s%s", separator, signames[s]);
150418230Slinton 		separator[0] = ' ';
150518230Slinton 		separator[1] = '\0';
150618230Slinton 	    }
150716928Ssam 	}
150818230Slinton     }
150918230Slinton     if (separator[0] == ' ') {
151016931Ssam 	putchar('\n');
151116931Ssam     }
151216928Ssam }
1513