xref: /csrg-svn/old/dbx/process.c (revision 11867)
1 /* Copyright (c) 1982 Regents of the University of California */
2 
3 static char sccsid[] = "@(#)process.c 1.8 04/08/83";
4 
5 /*
6  * Process management.
7  *
8  * This module contains the routines to manage the execution and
9  * tracing of the debuggee process.
10  */
11 
12 #include "defs.h"
13 #include "process.h"
14 #include "machine.h"
15 #include "events.h"
16 #include "tree.h"
17 #include "operators.h"
18 #include "source.h"
19 #include "object.h"
20 #include "mappings.h"
21 #include "main.h"
22 #include "coredump.h"
23 #include <signal.h>
24 #include <errno.h>
25 #include <sys/param.h>
26 #include <machine/reg.h>
27 #include <sys/stat.h>
28 
29 #ifndef public
30 
31 typedef struct Process *Process;
32 
33 Process process;
34 
35 #include "machine.h"
36 
37 #endif
38 
39 #define NOTSTARTED 1
40 #define STOPPED 0177
41 #define FINISHED 0
42 
43 /*
44  * Cache-ing of instruction segment is done to reduce the number
45  * of system calls.
46  */
47 
48 #define CSIZE 1003       /* size of instruction cache */
49 
50 typedef struct {
51     Word addr;
52     Word val;
53 } CacheWord;
54 
55 /*
56  * This structure holds the information we need from the user structure.
57  */
58 
59 struct Process {
60     int pid;			/* process being traced */
61     int mask;			/* process status word */
62     Word reg[NREG];		/* process' registers */
63     Word oreg[NREG];		/* registers when process last stopped */
64     short status;		/* either STOPPED or FINISHED */
65     short signo;		/* signal that stopped process */
66     int exitval;		/* return value from exit() */
67     long sigset;		/* bit array of traced signals */
68     CacheWord word[CSIZE];	/* text segment cache */
69     Ttyinfo ttyinfo;		/* process' terminal characteristics */
70 };
71 
72 /*
73  * These definitions are for the arguments to "pio".
74  */
75 
76 typedef enum { PREAD, PWRITE } PioOp;
77 typedef enum { TEXTSEG, DATASEG } PioSeg;
78 
79 private struct Process pbuf;
80 
81 #define MAXNCMDARGS 10         /* maximum number of arguments to RUN */
82 
83 private Boolean just_started;
84 private int argc;
85 private String argv[MAXNCMDARGS];
86 private String infile, outfile;
87 
88 /*
89  * Initialize process information.
90  */
91 
92 public process_init()
93 {
94     register Integer i;
95     Char buf[10];
96 
97     process = &pbuf;
98     process->status = (coredump) ? STOPPED : NOTSTARTED;
99     setsigtrace();
100     for (i = 0; i < NREG; i++) {
101 	sprintf(buf, "$r%d", i);
102 	defregname(identname(buf, false), i);
103     }
104     defregname(identname("$ap", true), ARGP);
105     defregname(identname("$fp", true), FRP);
106     defregname(identname("$sp", true), STKP);
107     defregname(identname("$pc", true), PROGCTR);
108     if (coredump) {
109 	coredump_readin(process->mask, process->reg, process->signo);
110     }
111 }
112 
113 /*
114  * Routines to get at process information from outside this module.
115  */
116 
117 public Word reg(n)
118 Integer n;
119 {
120     register Word w;
121 
122     if (n == NREG) {
123 	w = process->mask;
124     } else {
125 	w = process->reg[n];
126     }
127     return w;
128 }
129 
130 public setreg(n, w)
131 Integer n;
132 Word w;
133 {
134     process->reg[n] = w;
135 }
136 
137 /*
138  * Begin execution.
139  *
140  * We set a breakpoint at the end of the code so that the
141  * process data doesn't disappear after the program terminates.
142  */
143 
144 private Boolean remade();
145 
146 public start(argv, infile, outfile)
147 String argv[];
148 String infile, outfile;
149 {
150     String pargv[4];
151     Node cond;
152 
153     if (coredump) {
154 	coredump = false;
155 	fclose(corefile);
156 	coredump_close();
157     }
158     if (argv == nil) {
159 	argv = pargv;
160 	pargv[0] = objname;
161 	pargv[1] = nil;
162     } else {
163 	argv[argc] = nil;
164     }
165     if (remade(objname)) {
166 	reinit(argv, infile, outfile);
167     }
168     pstart(process, argv, infile, outfile);
169     if (process->status == STOPPED) {
170 	pc = 0;
171 	curfunc = program;
172 	if (objsize != 0) {
173 	    cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr()));
174 	    event_once(cond, buildcmdlist(build(O_ENDX)));
175 	}
176     }
177 }
178 
179 /*
180  * Check to see if the object file has changed since the symbolic
181  * information last was read.
182  */
183 
184 private time_t modtime;
185 
186 private Boolean remade(filename)
187 String filename;
188 {
189     struct stat s;
190     Boolean b;
191 
192     stat(filename, &s);
193     b = (Boolean) (modtime != 0 and modtime < s.st_mtime);
194     modtime = s.st_mtime;
195     return b;
196 }
197 
198 /*
199  * Set up what signals we want to trace.
200  */
201 
202 private setsigtrace()
203 {
204     register Integer i;
205     register Process p;
206 
207     p = process;
208     for (i = 1; i <= NSIG; i++) {
209 	psigtrace(p, i, true);
210     }
211     psigtrace(p, SIGHUP, false);
212     psigtrace(p, SIGKILL, false);
213     psigtrace(p, SIGALRM, false);
214     psigtrace(p, SIGTSTP, false);
215     psigtrace(p, SIGCONT, false);
216     psigtrace(p, SIGCHLD, false);
217 }
218 
219 /*
220  * Initialize the argument list.
221  */
222 
223 public arginit()
224 {
225     infile = nil;
226     outfile = nil;
227     argv[0] = objname;
228     argc = 1;
229 }
230 
231 /*
232  * Add an argument to the list for the debuggee.
233  */
234 
235 public newarg(arg)
236 String arg;
237 {
238     if (argc >= MAXNCMDARGS) {
239 	error("too many arguments");
240     }
241     argv[argc++] = arg;
242 }
243 
244 /*
245  * Set the standard input for the debuggee.
246  */
247 
248 public inarg(filename)
249 String filename;
250 {
251     if (infile != nil) {
252 	error("multiple input redirects");
253     }
254     infile = filename;
255 }
256 
257 /*
258  * Set the standard output for the debuggee.
259  * Probably should check to avoid overwriting an existing file.
260  */
261 
262 public outarg(filename)
263 String filename;
264 {
265     if (outfile != nil) {
266 	error("multiple output redirect");
267     }
268     outfile = filename;
269 }
270 
271 /*
272  * Start debuggee executing.
273  */
274 
275 public run()
276 {
277     process->status = STOPPED;
278     fixbps();
279     curline = 0;
280     start(argv, infile, outfile);
281     just_started = true;
282     isstopped = false;
283     cont();
284 }
285 
286 /*
287  * Continue execution wherever we left off.
288  *
289  * Note that this routine never returns.  Eventually bpact() will fail
290  * and we'll call printstatus or step will call it.
291  */
292 
293 typedef int Intfunc();
294 
295 private Intfunc *dbintr;
296 private intr();
297 
298 #define succeeds    == true
299 #define fails       == false
300 
301 public cont(signo)
302 int signo;
303 {
304     dbintr = signal(SIGINT, intr);
305     if (just_started) {
306 	just_started = false;
307     } else {
308 	if (not isstopped) {
309 	    error("can't continue execution");
310 	}
311 	isstopped = false;
312 	stepover();
313     }
314     for (;;) {
315 	if (single_stepping) {
316 	    printnews();
317 	} else {
318 	    setallbps();
319 	    resume(signo);
320 	    unsetallbps();
321 	    if (bpact() fails) {
322 		printstatus();
323 	    }
324 	}
325 	stepover();
326     }
327     /* NOTREACHED */
328 }
329 
330 /*
331  * This routine is called if we get an interrupt while "running" px
332  * but actually in the debugger.  Could happen, for example, while
333  * processing breakpoints.
334  *
335  * We basically just want to keep going; the assumption is
336  * that when the process resumes it will get the interrupt
337  * which will then be handled.
338  */
339 
340 private intr()
341 {
342     signal(SIGINT, intr);
343 }
344 
345 public fixintr()
346 {
347     signal(SIGINT, dbintr);
348 }
349 
350 /*
351  * Resume execution.
352  */
353 
354 public resume(signo)
355 int signo;
356 {
357     register Process p;
358 
359     p = process;
360     if (traceexec) {
361 	printf("execution resumes at pc 0x%x\n", process->reg[PROGCTR]);
362 	fflush(stdout);
363     }
364     pcont(p, signo);
365     pc = process->reg[PROGCTR];
366     if (traceexec) {
367 	printf("execution stops at pc 0x%x on sig %d\n",
368 	    process->reg[PROGCTR], p->signo);
369 	fflush(stdout);
370     }
371     if (p->status != STOPPED) {
372 	if (p->signo != 0) {
373 	    error("program terminated by signal %d", p->signo);
374 	} else {
375 	    error("program unexpectedly exited with %d", p->exitval);
376 	}
377     }
378 }
379 
380 /*
381  * Continue execution up to the next source line.
382  *
383  * There are two ways to define the next source line depending on what
384  * is desired when a procedure or function call is encountered.  Step
385  * stops at the beginning of the procedure or call; next skips over it.
386  */
387 
388 /*
389  * Stepc is what is called when the step command is given.
390  * It has to play with the "isstopped" information.
391  */
392 
393 public stepc()
394 {
395     if (not isstopped) {
396 	error("can't continue execution");
397     }
398     isstopped = false;
399     dostep(false);
400     isstopped = true;
401 }
402 
403 public next()
404 {
405     if (not isstopped) {
406 	error("can't continue execution");
407     }
408     isstopped = false;
409     dostep(true);
410     isstopped = true;
411 }
412 
413 /*
414  * Single-step over the current machine instruction.
415  *
416  * If we're single-stepping by source line we want to step to the
417  * next source line.  Otherwise we're going to continue so there's
418  * no reason to do all the work necessary to single-step to the next
419  * source line.
420  */
421 
422 private stepover()
423 {
424     Boolean b;
425 
426     if (single_stepping) {
427 	dostep(false);
428     } else {
429 	b = inst_tracing;
430 	inst_tracing = true;
431 	dostep(false);
432 	inst_tracing = b;
433     }
434 }
435 
436 /*
437  * Resume execution up to the given address.  It is assumed that
438  * no breakpoints exist between the current address and the one
439  * we're stepping to.  This saves us from setting all the breakpoints.
440  */
441 
442 public stepto(addr)
443 Address addr;
444 {
445     setbp(addr);
446     resume(0);
447     unsetbp(addr);
448     if (not isbperr()) {
449 	printstatus();
450     }
451 }
452 
453 /*
454  * Print the status of the process.
455  * This routine does not return.
456  */
457 
458 public printstatus()
459 {
460     if (process->status == FINISHED) {
461 	exit(0);
462     } else {
463 	curfunc = whatblock(pc);
464 	getsrcpos();
465 	if (process->signo == SIGINT) {
466 	    isstopped = true;
467 	    printerror();
468 	} else if (isbperr() and isstopped) {
469 	    printf("stopped ");
470 	    printloc();
471 	    putchar('\n');
472 	    if (curline > 0) {
473 		printlines(curline, curline);
474 	    } else {
475 		printinst(pc, pc);
476 	    }
477 	    erecover();
478 	} else {
479 	    fixbps();
480 	    fixintr();
481 	    isstopped = true;
482 	    printerror();
483 	}
484     }
485 }
486 
487 /*
488  * Print out the current location in the debuggee.
489  */
490 
491 public printloc()
492 {
493     printf("in ");
494     printname(stdout, curfunc);
495     putchar(' ');
496     if (curline > 0) {
497 	printsrcpos();
498     } else {
499 	printf("at 0x%x", pc);
500     }
501 }
502 
503 /*
504  * Some functions for testing the state of the process.
505  */
506 
507 public Boolean notstarted(p)
508 Process p;
509 {
510     return (Boolean) (p->status == NOTSTARTED);
511 }
512 
513 public Boolean isfinished(p)
514 Process p;
515 {
516     return (Boolean) (p->status == FINISHED);
517 }
518 
519 /*
520  * Return the signal number which stopped the process.
521  */
522 
523 public Integer errnum(p)
524 Process p;
525 {
526     return p->signo;
527 }
528 
529 /*
530  * Return the termination code of the process.
531  */
532 
533 public Integer exitcode(p)
534 Process p;
535 {
536     return p->exitval;
537 }
538 
539 /*
540  * These routines are used to access the debuggee process from
541  * outside this module.
542  *
543  * They invoke "pio" which eventually leads to a call to "ptrace".
544  * The system generates an I/O error when a ptrace fails, we assume
545  * during a read/write to the process that such an error is due to
546  * a misguided address and ignore it.
547  */
548 
549 extern Intfunc *onsyserr();
550 
551 private badaddr;
552 private rwerr();
553 
554 /*
555  * Read from the process' instruction area.
556  */
557 
558 public iread(buff, addr, nbytes)
559 char *buff;
560 Address addr;
561 int nbytes;
562 {
563     Intfunc *f;
564 
565     f = onsyserr(EIO, rwerr);
566     badaddr = addr;
567     if (coredump) {
568 	coredump_readtext(buff, addr, nbytes);
569     } else {
570 	pio(process, PREAD, TEXTSEG, buff, addr, nbytes);
571     }
572     onsyserr(EIO, f);
573 }
574 
575 /*
576  * Write to the process' instruction area, usually in order to set
577  * or unset a breakpoint.
578  */
579 
580 public iwrite(buff, addr, nbytes)
581 char *buff;
582 Address addr;
583 int nbytes;
584 {
585     Intfunc *f;
586 
587     if (coredump) {
588 	error("no process to write to");
589     }
590     f = onsyserr(EIO, rwerr);
591     badaddr = addr;
592     pio(process, PWRITE, TEXTSEG, buff, addr, nbytes);
593     onsyserr(EIO, f);
594 }
595 
596 /*
597  * Read for the process' data area.
598  */
599 
600 public dread(buff, addr, nbytes)
601 char *buff;
602 Address addr;
603 int nbytes;
604 {
605     Intfunc *f;
606 
607     f = onsyserr(EIO, rwerr);
608     badaddr = addr;
609     if (coredump) {
610 	coredump_readdata(buff, addr, nbytes);
611     } else {
612 	pio(process, PREAD, DATASEG, buff, addr, nbytes);
613     }
614     onsyserr(EIO, f);
615 }
616 
617 /*
618  * Write to the process' data area.
619  */
620 
621 public dwrite(buff, addr, nbytes)
622 char *buff;
623 Address addr;
624 int nbytes;
625 {
626     Intfunc *f;
627 
628     if (coredump) {
629 	error("no process to write to");
630     }
631     f = onsyserr(EIO, rwerr);
632     badaddr = addr;
633     pio(process, PWRITE, DATASEG, buff, addr, nbytes);
634     onsyserr(EIO, f);
635 }
636 
637 /*
638  * Error handler.
639  */
640 
641 private rwerr()
642 {
643     /*
644      * Current response is to ignore the error and let the result
645      * (-1) ripple back up to the process.
646      *
647     error("bad read/write process address 0x%x", badaddr);
648      */
649 }
650 
651 /*
652  * Ptrace interface.
653  */
654 
655 /*
656  * This magic macro enables us to look at the process' registers
657  * in its user structure.  Very gross.
658  */
659 
660 #define regloc(reg)     (ctob(UPAGES) + ( sizeof(int) * (reg) ))
661 
662 #define WMASK           (~(sizeof(Word) - 1))
663 #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE))
664 
665 #define FIRSTSIG        SIGINT
666 #define LASTSIG         SIGQUIT
667 #define ischild(pid)    ((pid) == 0)
668 #define traceme()       ptrace(0, 0, 0, 0)
669 #define setrep(n)       (1 << ((n)-1))
670 #define istraced(p)     (p->sigset&setrep(p->signo))
671 
672 /*
673  * Ptrace options (specified in first argument).
674  */
675 
676 #define UREAD   3       /* read from process's user structure */
677 #define UWRITE  6       /* write to process's user structure */
678 #define IREAD   1       /* read from process's instruction space */
679 #define IWRITE  4       /* write to process's instruction space */
680 #define DREAD   2       /* read from process's data space */
681 #define DWRITE  5       /* write to process's data space */
682 #define CONT    7       /* continue stopped process */
683 #define SSTEP   9       /* continue for approximately one instruction */
684 #define PKILL   8       /* terminate the process */
685 
686 /*
687  * Start up a new process by forking and exec-ing the
688  * given argument list, returning when the process is loaded
689  * and ready to execute.  The PROCESS information (pointed to
690  * by the first argument) is appropriately filled.
691  *
692  * If the given PROCESS structure is associated with an already running
693  * process, we terminate it.
694  */
695 
696 /* VARARGS2 */
697 private pstart(p, argv, infile, outfile)
698 Process p;
699 String argv[];
700 String infile;
701 String outfile;
702 {
703     int status;
704 
705     if (p->pid != 0) {          	/* child already running? */
706 	ptrace(PKILL, p->pid, 0, 0);    /* ... kill it! */
707     }
708     psigtrace(p, SIGTRAP, true);
709     if ((p->pid = vfork()) == -1) {
710 	panic("can't fork");
711     }
712     if (ischild(p->pid)) {
713 	Fileid in, out;
714 
715 	traceme();
716 	if (infile != nil) {
717 	    in = open(infile, 0);
718 	    if (in == -1) {
719 		write(2, "can't read ", 11);
720 		write(2, infile, strlen(infile));
721 		write(2, "\n", 1);
722 		_exit(1);
723 	    }
724 	    fswap(0, in);
725 	}
726 	if (outfile != nil) {
727 	    out = creat(outfile, 0666);
728 	    if (out == -1) {
729 		write(2, "can't write ", 12);
730 		write(2, outfile, strlen(outfile));
731 		write(2, "\n", 1);
732 		_exit(1);
733 	    }
734 	    fswap(1, out);
735 	}
736 	execv(argv[0], argv);
737 	write(2, "can't exec ", 11);
738 	write(2, argv[0], strlen(argv[0]));
739 	write(2, "\n", 1);
740 	_exit(1);
741     }
742     pwait(p->pid, &status);
743     getinfo(p, status);
744     if (p->status != STOPPED) {
745 	error("program could not begin execution");
746     }
747 }
748 
749 /*
750  * Continue a stopped process.  The first argument points to a Process
751  * structure.  Before the process is restarted it's user area is modified
752  * according to the values in the structure.  When this routine finishes,
753  * the structure has the new values from the process's user area.
754  *
755  * Pcont terminates when the process stops with a signal pending that
756  * is being traced (via psigtrace), or when the process terminates.
757  */
758 
759 private pcont(p, signo)
760 Process p;
761 int signo;
762 {
763     int status;
764 
765     if (p->pid == 0) {
766 	error("program not active");
767     }
768     do {
769 	setinfo(p, signo);
770 	sigs_off();
771 	if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) {
772 	    panic("can't continue process");
773 	}
774 	pwait(p->pid, &status);
775 	sigs_on();
776 	getinfo(p, status);
777     } while (p->status == STOPPED and not istraced(p));
778 }
779 
780 /*
781  * Single step as best ptrace can.
782  */
783 
784 public pstep(p)
785 Process p;
786 {
787     int status;
788 
789     setinfo(p, 0);
790     sigs_off();
791     ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo);
792     pwait(p->pid, &status);
793     sigs_on();
794     getinfo(p, status);
795 }
796 
797 /*
798  * Return from execution when the given signal is pending.
799  */
800 
801 public psigtrace(p, sig, sw)
802 Process p;
803 int sig;
804 Boolean sw;
805 {
806     if (sw) {
807 	p->sigset |= setrep(sig);
808     } else {
809 	p->sigset &= ~setrep(sig);
810     }
811 }
812 
813 /*
814  * Don't catch any signals.
815  * Particularly useful when letting a process finish uninhibited.
816  */
817 
818 public unsetsigtraces(p)
819 Process p;
820 {
821     p->sigset = 0;
822 }
823 
824 /*
825  * Turn off attention to signals not being caught.
826  */
827 
828 private Intfunc *sigfunc[NSIG];
829 
830 private sigs_off()
831 {
832     register int i;
833 
834     for (i = FIRSTSIG; i < LASTSIG; i++) {
835 	if (i != SIGKILL) {
836 	    sigfunc[i] = signal(i, SIG_IGN);
837 	}
838     }
839 }
840 
841 /*
842  * Turn back on attention to signals.
843  */
844 
845 private sigs_on()
846 {
847     register int i;
848 
849     for (i = FIRSTSIG; i < LASTSIG; i++) {
850 	if (i != SIGKILL) {
851 	    signal(i, sigfunc[i]);
852 	}
853     }
854 }
855 
856 /*
857  * Get process information from user area.
858  */
859 
860 private int rloc[] ={
861     R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, AP, FP, SP, PC
862 };
863 
864 private getinfo(p, status)
865 register Process p;
866 register int status;
867 {
868     register int i;
869 
870     p->signo = (status&0177);
871     p->exitval = ((status >> 8)&0377);
872     if (p->signo != STOPPED) {
873 	p->status = FINISHED;
874     } else {
875 	p->status = p->signo;
876 	p->signo = p->exitval;
877 	p->exitval = 0;
878 	p->mask = ptrace(UREAD, p->pid, regloc(PS), 0);
879 	for (i = 0; i < NREG; i++) {
880 	    p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0);
881 	    p->oreg[i] = p->reg[i];
882 	}
883 	savetty(stdout, &(p->ttyinfo));
884     }
885 }
886 
887 /*
888  * Set process's user area information from given process structure.
889  */
890 
891 private setinfo(p, signo)
892 register Process p;
893 int signo;
894 {
895     register int i;
896     register int r;
897 
898     if (istraced(p)) {
899 	p->signo = signo;
900     }
901     for (i = 0; i < NREG; i++) {
902 	if ((r = p->reg[i]) != p->oreg[i]) {
903 	    ptrace(UWRITE, p->pid, regloc(rloc[i]), r);
904 	}
905     }
906     restoretty(stdout, &(p->ttyinfo));
907 }
908 
909 /*
910  * Structure for reading and writing by words, but dealing with bytes.
911  */
912 
913 typedef union {
914     Word pword;
915     Byte pbyte[sizeof(Word)];
916 } Pword;
917 
918 /*
919  * Read (write) from (to) the process' address space.
920  * We must deal with ptrace's inability to look anywhere other
921  * than at a word boundary.
922  */
923 
924 private Word fetch();
925 private store();
926 
927 private pio(p, op, seg, buff, addr, nbytes)
928 Process p;
929 PioOp op;
930 PioSeg seg;
931 char *buff;
932 Address addr;
933 int nbytes;
934 {
935     register int i;
936     register Address newaddr;
937     register char *cp;
938     char *bufend;
939     Pword w;
940     Address wordaddr;
941     int byteoff;
942 
943     if (p->status != STOPPED) {
944 	error("program is not active");
945     }
946     cp = buff;
947     newaddr = addr;
948     wordaddr = (newaddr&WMASK);
949     if (wordaddr != newaddr) {
950 	w.pword = fetch(p, seg, wordaddr);
951 	for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) {
952 	    if (op == PREAD) {
953 		*cp++ = w.pbyte[i];
954 	    } else {
955 		w.pbyte[i] = *cp++;
956 	    }
957 	    nbytes--;
958 	}
959 	if (op == PWRITE) {
960 	    store(p, seg, wordaddr, w.pword);
961 	}
962 	newaddr = wordaddr + sizeof(Word);
963     }
964     byteoff = (nbytes&(~WMASK));
965     nbytes -= byteoff;
966     bufend = cp + nbytes;
967     while (cp < bufend) {
968 	if (op == PREAD) {
969 	    *((Word *) cp) = fetch(p, seg, newaddr);
970 	} else {
971 	    store(p, seg, newaddr, *((Word *) cp));
972 	}
973 	cp += sizeof(Word);
974 	newaddr += sizeof(Word);
975     }
976     if (byteoff > 0) {
977 	w.pword = fetch(p, seg, newaddr);
978 	for (i = 0; i < byteoff; i++) {
979 	    if (op == PREAD) {
980 		*cp++ = w.pbyte[i];
981 	    } else {
982 		w.pbyte[i] = *cp++;
983 	    }
984 	}
985 	if (op == PWRITE) {
986 	    store(p, seg, newaddr, w.pword);
987 	}
988     }
989 }
990 
991 /*
992  * Get a word from a process at the given address.
993  * The address is assumed to be on a word boundary.
994  *
995  * A simple cache scheme is used to avoid redundant ptrace calls
996  * to the instruction space since it is assumed to be pure.
997  *
998  * It is necessary to use a write-through scheme so that
999  * breakpoints right next to each other don't interfere.
1000  */
1001 
1002 private Integer nfetchs, nreads, nwrites;
1003 
1004 private Word fetch(p, seg, addr)
1005 Process p;
1006 PioSeg seg;
1007 register int addr;
1008 {
1009     register CacheWord *wp;
1010     register Word w;
1011 
1012     switch (seg) {
1013 	case TEXTSEG:
1014 	    ++nfetchs;
1015 	    wp = &p->word[cachehash(addr)];
1016 	    if (addr == 0 or wp->addr != addr) {
1017 		++nreads;
1018 		w = ptrace(IREAD, p->pid, addr, 0);
1019 		wp->addr = addr;
1020 		wp->val = w;
1021 	    } else {
1022 		w = wp->val;
1023 	    }
1024 	    break;
1025 
1026 	case DATASEG:
1027 	    w = ptrace(DREAD, p->pid, addr, 0);
1028 	    break;
1029 
1030 	default:
1031 	    panic("fetch: bad seg %d", seg);
1032 	    /* NOTREACHED */
1033     }
1034     return w;
1035 }
1036 
1037 /*
1038  * Put a word into the process' address space at the given address.
1039  * The address is assumed to be on a word boundary.
1040  */
1041 
1042 private store(p, seg, addr, data)
1043 Process p;
1044 PioSeg seg;
1045 int addr;
1046 Word data;
1047 {
1048     register CacheWord *wp;
1049 
1050     switch (seg) {
1051 	case TEXTSEG:
1052 	    ++nwrites;
1053 	    wp = &p->word[cachehash(addr)];
1054 	    wp->addr = addr;
1055 	    wp->val = data;
1056 	    ptrace(IWRITE, p->pid, addr, data);
1057 	    break;
1058 
1059 	case DATASEG:
1060 	    ptrace(DWRITE, p->pid, addr, data);
1061 	    break;
1062 
1063 	default:
1064 	    panic("store: bad seg %d", seg);
1065 	    /* NOTREACHED */
1066     }
1067 }
1068 
1069 public printptraceinfo()
1070 {
1071     printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites);
1072 }
1073 
1074 /*
1075  * Swap file numbers so as to redirect standard input and output.
1076  */
1077 
1078 private fswap(oldfd, newfd)
1079 int oldfd;
1080 int newfd;
1081 {
1082     if (oldfd != newfd) {
1083 	close(oldfd);
1084 	dup(newfd);
1085 	close(newfd);
1086     }
1087 }
1088