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