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