|
|
1.1 root 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) 5/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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.