xref: /csrg-svn/old/dbx/process.c (revision 11832)
1 /* Copyright (c) 1982 Regents of the University of California */
2 
3 static char sccsid[] = "@(#)process.c 1.7 04/03/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()
302 {
303     dbintr = signal(SIGINT, intr);
304     if (just_started) {
305 	just_started = false;
306     } else {
307 	if (not isstopped) {
308 	    error("can't continue execution");
309 	}
310 	isstopped = false;
311 	step();
312     }
313     for (;;) {
314 	if (single_stepping) {
315 	    printnews();
316 	} else {
317 	    setallbps();
318 	    resume();
319 	    unsetallbps();
320 	    if (bpact() fails) {
321 		printstatus();
322 	    }
323 	}
324 	step();
325     }
326     /* NOTREACHED */
327 }
328 
329 /*
330  * This routine is called if we get an interrupt while "running" px
331  * but actually in the debugger.  Could happen, for example, while
332  * processing breakpoints.
333  *
334  * We basically just want to keep going; the assumption is
335  * that when the process resumes it will get the interrupt
336  * which will then be handled.
337  */
338 
339 private intr()
340 {
341     signal(SIGINT, intr);
342 }
343 
344 public fixintr()
345 {
346     signal(SIGINT, dbintr);
347 }
348 
349 /*
350  * Resume execution.
351  */
352 
353 public resume()
354 {
355     register Process p;
356 
357     p = process;
358     if (traceexec) {
359 	printf("execution resumes at pc 0x%x\n", process->reg[PROGCTR]);
360 	fflush(stdout);
361     }
362     pcont(p);
363     pc = process->reg[PROGCTR];
364     if (traceexec) {
365 	printf("execution stops at pc 0x%x on sig %d\n",
366 	    process->reg[PROGCTR], p->signo);
367 	fflush(stdout);
368     }
369     if (p->status != STOPPED) {
370 	error("program unexpectedly exited with %d", p->exitval);
371     }
372 }
373 
374 /*
375  * Continue execution up to the next source line.
376  *
377  * There are two ways to define the next source line depending on what
378  * is desired when a procedure or function call is encountered.  Step
379  * stops at the beginning of the procedure or call; next skips over it.
380  */
381 
382 /*
383  * Stepc is what is called when the step command is given.
384  * It has to play with the "isstopped" information.
385  */
386 
387 public stepc()
388 {
389     if (not isstopped) {
390 	error("can't continue execution");
391     }
392     isstopped = false;
393     dostep(false);
394     isstopped = true;
395 }
396 
397 public next()
398 {
399     if (not isstopped) {
400 	error("can't continue execution");
401     }
402     isstopped = false;
403     dostep(true);
404     isstopped = true;
405 }
406 
407 public step()
408 {
409     dostep(false);
410 }
411 
412 /*
413  * Resume execution up to the given address.  It is assumed that
414  * no breakpoints exist between the current address and the one
415  * we're stepping to.  This saves us from setting all the breakpoints.
416  */
417 
418 public stepto(addr)
419 Address addr;
420 {
421     setbp(addr);
422     resume();
423     unsetbp(addr);
424     if (not isbperr()) {
425 	printstatus();
426     }
427 }
428 
429 /*
430  * Print the status of the process.
431  * This routine does not return.
432  */
433 
434 public printstatus()
435 {
436     if (process->status == FINISHED) {
437 	exit(0);
438     } else {
439 	curfunc = whatblock(pc);
440 	getsrcpos();
441 	if (process->signo == SIGINT) {
442 	    isstopped = true;
443 	    printerror();
444 	} else if (isbperr() and isstopped) {
445 	    printf("stopped ");
446 	    printloc();
447 	    putchar('\n');
448 	    if (curline > 0) {
449 		printlines(curline, curline);
450 	    } else {
451 		printinst(pc, pc);
452 	    }
453 	    erecover();
454 	} else {
455 	    fixbps();
456 	    fixintr();
457 	    isstopped = true;
458 	    printerror();
459 	}
460     }
461 }
462 
463 /*
464  * Print out the current location in the debuggee.
465  */
466 
467 public printloc()
468 {
469     printf("in ");
470     printname(stdout, curfunc);
471     putchar(' ');
472     if (curline > 0) {
473 	printsrcpos();
474     } else {
475 	printf("at 0x%x", pc);
476     }
477 }
478 
479 /*
480  * Some functions for testing the state of the process.
481  */
482 
483 public Boolean notstarted(p)
484 Process p;
485 {
486     return (Boolean) (p->status == NOTSTARTED);
487 }
488 
489 public Boolean isfinished(p)
490 Process p;
491 {
492     return (Boolean) (p->status == FINISHED);
493 }
494 
495 /*
496  * Return the signal number which stopped the process.
497  */
498 
499 public Integer errnum(p)
500 Process p;
501 {
502     return p->signo;
503 }
504 
505 /*
506  * Return the termination code of the process.
507  */
508 
509 public Integer exitcode(p)
510 Process p;
511 {
512     return p->exitval;
513 }
514 
515 /*
516  * These routines are used to access the debuggee process from
517  * outside this module.
518  *
519  * They invoke "pio" which eventually leads to a call to "ptrace".
520  * The system generates an I/O error when a ptrace fails, we assume
521  * during a read/write to the process that such an error is due to
522  * a misguided address and ignore it.
523  */
524 
525 extern Intfunc *onsyserr();
526 
527 private badaddr;
528 private rwerr();
529 
530 /*
531  * Read from the process' instruction area.
532  */
533 
534 public iread(buff, addr, nbytes)
535 char *buff;
536 Address addr;
537 int nbytes;
538 {
539     Intfunc *f;
540 
541     f = onsyserr(EIO, rwerr);
542     badaddr = addr;
543     if (coredump) {
544 	coredump_readtext(buff, addr, nbytes);
545     } else {
546 	pio(process, PREAD, TEXTSEG, buff, addr, nbytes);
547     }
548     onsyserr(EIO, f);
549 }
550 
551 /*
552  * Write to the process' instruction area, usually in order to set
553  * or unset a breakpoint.
554  */
555 
556 public iwrite(buff, addr, nbytes)
557 char *buff;
558 Address addr;
559 int nbytes;
560 {
561     Intfunc *f;
562 
563     if (coredump) {
564 	error("no process to write to");
565     }
566     f = onsyserr(EIO, rwerr);
567     badaddr = addr;
568     pio(process, PWRITE, TEXTSEG, buff, addr, nbytes);
569     onsyserr(EIO, f);
570 }
571 
572 /*
573  * Read for the process' data area.
574  */
575 
576 public dread(buff, addr, nbytes)
577 char *buff;
578 Address addr;
579 int nbytes;
580 {
581     Intfunc *f;
582 
583     f = onsyserr(EIO, rwerr);
584     badaddr = addr;
585     if (coredump) {
586 	coredump_readdata(buff, addr, nbytes);
587     } else {
588 	pio(process, PREAD, DATASEG, buff, addr, nbytes);
589     }
590     onsyserr(EIO, f);
591 }
592 
593 /*
594  * Write to the process' data area.
595  */
596 
597 public dwrite(buff, addr, nbytes)
598 char *buff;
599 Address addr;
600 int nbytes;
601 {
602     Intfunc *f;
603 
604     if (coredump) {
605 	error("no process to write to");
606     }
607     f = onsyserr(EIO, rwerr);
608     badaddr = addr;
609     pio(process, PWRITE, DATASEG, buff, addr, nbytes);
610     onsyserr(EIO, f);
611 }
612 
613 /*
614  * Error handler.
615  */
616 
617 private rwerr()
618 {
619     /*
620      * Current response is to ignore the error and let the result
621      * (-1) ripple back up to the process.
622      *
623     error("bad read/write process address 0x%x", badaddr);
624      */
625 }
626 
627 /*
628  * Ptrace interface.
629  */
630 
631 /*
632  * This magic macro enables us to look at the process' registers
633  * in its user structure.  Very gross.
634  */
635 
636 #define regloc(reg)     (ctob(UPAGES) + ( sizeof(int) * (reg) ))
637 
638 #define WMASK           (~(sizeof(Word) - 1))
639 #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE))
640 
641 #define FIRSTSIG        SIGINT
642 #define LASTSIG         SIGQUIT
643 #define ischild(pid)    ((pid) == 0)
644 #define traceme()       ptrace(0, 0, 0, 0)
645 #define setrep(n)       (1 << ((n)-1))
646 #define istraced(p)     (p->sigset&setrep(p->signo))
647 
648 /*
649  * Ptrace options (specified in first argument).
650  */
651 
652 #define UREAD   3       /* read from process's user structure */
653 #define UWRITE  6       /* write to process's user structure */
654 #define IREAD   1       /* read from process's instruction space */
655 #define IWRITE  4       /* write to process's instruction space */
656 #define DREAD   2       /* read from process's data space */
657 #define DWRITE  5       /* write to process's data space */
658 #define CONT    7       /* continue stopped process */
659 #define SSTEP   9       /* continue for approximately one instruction */
660 #define PKILL   8       /* terminate the process */
661 
662 /*
663  * Start up a new process by forking and exec-ing the
664  * given argument list, returning when the process is loaded
665  * and ready to execute.  The PROCESS information (pointed to
666  * by the first argument) is appropriately filled.
667  *
668  * If the given PROCESS structure is associated with an already running
669  * process, we terminate it.
670  */
671 
672 /* VARARGS2 */
673 private pstart(p, argv, infile, outfile)
674 Process p;
675 String argv[];
676 String infile;
677 String outfile;
678 {
679     int status;
680 
681     if (p->pid != 0) {          	/* child already running? */
682 	ptrace(PKILL, p->pid, 0, 0);    /* ... kill it! */
683     }
684     psigtrace(p, SIGTRAP, true);
685     if ((p->pid = vfork()) == -1) {
686 	panic("can't fork");
687     }
688     if (ischild(p->pid)) {
689 	Fileid in, out;
690 
691 	traceme();
692 	if (infile != nil) {
693 	    in = open(infile, 0);
694 	    if (in == -1) {
695 		write(2, "can't read ", 11);
696 		write(2, infile, strlen(infile));
697 		write(2, "\n", 1);
698 		_exit(1);
699 	    }
700 	    fswap(0, in);
701 	}
702 	if (outfile != nil) {
703 	    out = creat(outfile, 0666);
704 	    if (out == -1) {
705 		write(2, "can't write ", 12);
706 		write(2, outfile, strlen(outfile));
707 		write(2, "\n", 1);
708 		_exit(1);
709 	    }
710 	    fswap(1, out);
711 	}
712 	execv(argv[0], argv);
713 	write(2, "can't exec ", 11);
714 	write(2, argv[0], strlen(argv[0]));
715 	write(2, "\n", 1);
716 	_exit(1);
717     }
718     pwait(p->pid, &status);
719     getinfo(p, status);
720     if (p->status != STOPPED) {
721 	error("program could not begin execution");
722     }
723 }
724 
725 /*
726  * Continue a stopped process.  The argument points to a PROCESS structure.
727  * Before the process is restarted it's user area is modified according to
728  * the values in the structure.  When this routine finishes,
729  * the structure has the new values from the process's user area.
730  *
731  * Pcont terminates when the process stops with a signal pending that
732  * is being traced (via psigtrace), or when the process terminates.
733  */
734 
735 private pcont(p)
736 Process p;
737 {
738     int status;
739 
740     if (p->pid == 0) {
741 	error("program not active");
742     }
743     do {
744 	setinfo(p);
745 	sigs_off();
746 	if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) {
747 	    panic("can't continue process");
748 	}
749 	pwait(p->pid, &status);
750 	sigs_on();
751 	getinfo(p, status);
752     } while (p->status == STOPPED and not istraced(p));
753 }
754 
755 /*
756  * Single step as best ptrace can.
757  */
758 
759 public pstep(p)
760 Process p;
761 {
762     int status;
763 
764     setinfo(p);
765     sigs_off();
766     ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo);
767     pwait(p->pid, &status);
768     sigs_on();
769     getinfo(p, status);
770 }
771 
772 /*
773  * Return from execution when the given signal is pending.
774  */
775 
776 public psigtrace(p, sig, sw)
777 Process p;
778 int sig;
779 Boolean sw;
780 {
781     if (sw) {
782 	p->sigset |= setrep(sig);
783     } else {
784 	p->sigset &= ~setrep(sig);
785     }
786 }
787 
788 /*
789  * Don't catch any signals.
790  * Particularly useful when letting a process finish uninhibited.
791  */
792 
793 public unsetsigtraces(p)
794 Process p;
795 {
796     p->sigset = 0;
797 }
798 
799 /*
800  * Turn off attention to signals not being caught.
801  */
802 
803 private Intfunc *sigfunc[NSIG];
804 
805 private sigs_off()
806 {
807     register int i;
808 
809     for (i = FIRSTSIG; i < LASTSIG; i++) {
810 	if (i != SIGKILL) {
811 	    sigfunc[i] = signal(i, SIG_IGN);
812 	}
813     }
814 }
815 
816 /*
817  * Turn back on attention to signals.
818  */
819 
820 private sigs_on()
821 {
822     register int i;
823 
824     for (i = FIRSTSIG; i < LASTSIG; i++) {
825 	if (i != SIGKILL) {
826 	    signal(i, sigfunc[i]);
827 	}
828     }
829 }
830 
831 /*
832  * Get process information from user area.
833  */
834 
835 private int rloc[] ={
836     R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, AP, FP, SP, PC
837 };
838 
839 private getinfo(p, status)
840 register Process p;
841 register int status;
842 {
843     register int i;
844 
845     p->signo = (status&0177);
846     p->exitval = ((status >> 8)&0377);
847     if (p->signo != STOPPED) {
848 	p->status = FINISHED;
849     } else {
850 	p->status = p->signo;
851 	p->signo = p->exitval;
852 	p->exitval = 0;
853 	p->mask = ptrace(UREAD, p->pid, regloc(PS), 0);
854 	for (i = 0; i < NREG; i++) {
855 	    p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0);
856 	    p->oreg[i] = p->reg[i];
857 	}
858 	savetty(stdout, &(p->ttyinfo));
859     }
860 }
861 
862 /*
863  * Set process's user area information from given process structure.
864  */
865 
866 private setinfo(p)
867 register Process p;
868 {
869     register int i;
870     register int r;
871 
872     if (istraced(p)) {
873 	p->signo = 0;
874     }
875     for (i = 0; i < NREG; i++) {
876 	if ((r = p->reg[i]) != p->oreg[i]) {
877 	    ptrace(UWRITE, p->pid, regloc(rloc[i]), r);
878 	}
879     }
880     restoretty(stdout, &(p->ttyinfo));
881 }
882 
883 /*
884  * Structure for reading and writing by words, but dealing with bytes.
885  */
886 
887 typedef union {
888     Word pword;
889     Byte pbyte[sizeof(Word)];
890 } Pword;
891 
892 /*
893  * Read (write) from (to) the process' address space.
894  * We must deal with ptrace's inability to look anywhere other
895  * than at a word boundary.
896  */
897 
898 private Word fetch();
899 private store();
900 
901 private pio(p, op, seg, buff, addr, nbytes)
902 Process p;
903 PioOp op;
904 PioSeg seg;
905 char *buff;
906 Address addr;
907 int nbytes;
908 {
909     register int i;
910     register Address newaddr;
911     register char *cp;
912     char *bufend;
913     Pword w;
914     Address wordaddr;
915     int byteoff;
916 
917     if (p->status != STOPPED) {
918 	error("program is not active");
919     }
920     cp = buff;
921     newaddr = addr;
922     wordaddr = (newaddr&WMASK);
923     if (wordaddr != newaddr) {
924 	w.pword = fetch(p, seg, wordaddr);
925 	for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) {
926 	    if (op == PREAD) {
927 		*cp++ = w.pbyte[i];
928 	    } else {
929 		w.pbyte[i] = *cp++;
930 	    }
931 	    nbytes--;
932 	}
933 	if (op == PWRITE) {
934 	    store(p, seg, wordaddr, w.pword);
935 	}
936 	newaddr = wordaddr + sizeof(Word);
937     }
938     byteoff = (nbytes&(~WMASK));
939     nbytes -= byteoff;
940     bufend = cp + nbytes;
941     while (cp < bufend) {
942 	if (op == PREAD) {
943 	    *((Word *) cp) = fetch(p, seg, newaddr);
944 	} else {
945 	    store(p, seg, newaddr, *((Word *) cp));
946 	}
947 	cp += sizeof(Word);
948 	newaddr += sizeof(Word);
949     }
950     if (byteoff > 0) {
951 	w.pword = fetch(p, seg, newaddr);
952 	for (i = 0; i < byteoff; i++) {
953 	    if (op == PREAD) {
954 		*cp++ = w.pbyte[i];
955 	    } else {
956 		w.pbyte[i] = *cp++;
957 	    }
958 	}
959 	if (op == PWRITE) {
960 	    store(p, seg, newaddr, w.pword);
961 	}
962     }
963 }
964 
965 /*
966  * Get a word from a process at the given address.
967  * The address is assumed to be on a word boundary.
968  *
969  * A simple cache scheme is used to avoid redundant ptrace calls
970  * to the instruction space since it is assumed to be pure.
971  *
972  * It is necessary to use a write-through scheme so that
973  * breakpoints right next to each other don't interfere.
974  */
975 
976 private Integer nfetchs, nreads, nwrites;
977 
978 private Word fetch(p, seg, addr)
979 Process p;
980 PioSeg seg;
981 register int addr;
982 {
983     register CacheWord *wp;
984     register Word w;
985 
986     switch (seg) {
987 	case TEXTSEG:
988 	    ++nfetchs;
989 	    wp = &p->word[cachehash(addr)];
990 	    if (addr == 0 or wp->addr != addr) {
991 		++nreads;
992 		w = ptrace(IREAD, p->pid, addr, 0);
993 		wp->addr = addr;
994 		wp->val = w;
995 	    } else {
996 		w = wp->val;
997 	    }
998 	    break;
999 
1000 	case DATASEG:
1001 	    w = ptrace(DREAD, p->pid, addr, 0);
1002 	    break;
1003 
1004 	default:
1005 	    panic("fetch: bad seg %d", seg);
1006 	    /* NOTREACHED */
1007     }
1008     return w;
1009 }
1010 
1011 /*
1012  * Put a word into the process' address space at the given address.
1013  * The address is assumed to be on a word boundary.
1014  */
1015 
1016 private store(p, seg, addr, data)
1017 Process p;
1018 PioSeg seg;
1019 int addr;
1020 Word data;
1021 {
1022     register CacheWord *wp;
1023 
1024     switch (seg) {
1025 	case TEXTSEG:
1026 	    ++nwrites;
1027 	    wp = &p->word[cachehash(addr)];
1028 	    wp->addr = addr;
1029 	    wp->val = data;
1030 	    ptrace(IWRITE, p->pid, addr, data);
1031 	    break;
1032 
1033 	case DATASEG:
1034 	    ptrace(DWRITE, p->pid, addr, data);
1035 	    break;
1036 
1037 	default:
1038 	    panic("store: bad seg %d", seg);
1039 	    /* NOTREACHED */
1040     }
1041 }
1042 
1043 public printptraceinfo()
1044 {
1045     printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites);
1046 }
1047 
1048 /*
1049  * Swap file numbers so as to redirect standard input and output.
1050  */
1051 
1052 private fswap(oldfd, newfd)
1053 int oldfd;
1054 int newfd;
1055 {
1056     if (oldfd != newfd) {
1057 	close(oldfd);
1058 	dup(newfd);
1059 	close(newfd);
1060     }
1061 }
1062