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