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