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