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