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