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