📄 process.c
字号:
extern Intfunc *onsyserr();private badaddr;private read_err(), write_err();/* * Read from the process' instruction area. */public iread(buff, addr, nbytes)char *buff;Address addr;int nbytes;{ Intfunc *f; f = onsyserr(EIO, read_err); badaddr = addr; if (coredump) { coredump_readtext(buff, addr, nbytes); } else { pio(process, PREAD, TEXTSEG, buff, addr, nbytes); } onsyserr(EIO, f);}/* * Write to the process' instruction area, usually in order to set * or unset a breakpoint. */public iwrite(buff, addr, nbytes)char *buff;Address addr;int nbytes;{ Intfunc *f; if (coredump) { error("no process to write to"); } f = onsyserr(EIO, write_err); badaddr = addr; pio(process, PWRITE, TEXTSEG, buff, addr, nbytes); onsyserr(EIO, f);}/* * Read for the process' data area. */public dread(buff, addr, nbytes)char *buff;Address addr;int nbytes;{ Intfunc *f; f = onsyserr(EIO, read_err); badaddr = addr; if (coredump) { coredump_readdata(buff, addr, nbytes); } else { pio(process, PREAD, DATASEG, buff, addr, nbytes); } onsyserr(EIO, f);}/* * Write to the process' data area. */public dwrite(buff, addr, nbytes)char *buff;Address addr;int nbytes;{ Intfunc *f; if (coredump) { error("no process to write to"); } f = onsyserr(EIO, write_err); badaddr = addr; pio(process, PWRITE, DATASEG, buff, addr, nbytes); onsyserr(EIO, f);}/* * Trap for errors in reading or writing to a process. * The current approach is to "ignore" read errors and complain * bitterly about write errors. */private read_err(){ /* * Ignore. */}private write_err(){ error("can't write to process (address 0x%x)", badaddr);}/* * Ptrace interface. *//* * This magic macro enables us to look at the process' registers * in its user structure. */#define regloc(reg) (ctob(UPAGES) + ( sizeof(int) * (reg) ))#define WMASK (~(sizeof(Word) - 1))#define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE))#define FIRSTSIG SIGINT#define LASTSIG SIGQUIT#define ischild(pid) ((pid) == 0)#define traceme() ptrace(0, 0, 0, 0)#define setrep(n) (1 << ((n)-1))#define istraced(p) (p->sigset&setrep(p->signo))/* * Ptrace options (specified in first argument). */#define UREAD 3 /* read from process's user structure */#define UWRITE 6 /* write to process's user structure */#define IREAD 1 /* read from process's instruction space */#define IWRITE 4 /* write to process's instruction space */#define DREAD 2 /* read from process's data space */#define DWRITE 5 /* write to process's data space */#define CONT 7 /* continue stopped process */#define SSTEP 9 /* continue for approximately one instruction */#define PKILL 8 /* terminate the process *//* * Start up a new process by forking and exec-ing the * given argument list, returning when the process is loaded * and ready to execute. The PROCESS information (pointed to * by the first argument) is appropriately filled. * * If the given PROCESS structure is associated with an already running * process, we terminate it. *//* VARARGS2 */private pstart(p, argv, infile, outfile)Process p;String argv[];String infile;String outfile;{ int status; if (p->pid != 0) { pterm(p); } psigtrace(p, SIGTRAP, true); p->pid = vfork(); if (p->pid == -1) { panic("can't fork"); } if (ischild(p->pid)) { traceme(); if (infile != nil) { infrom(infile); } if (outfile != nil) { outto(outfile); } execv(argv[0], argv); write(2, "can't exec ", 11); write(2, argv[0], strlen(argv[0])); write(2, "\n", 1); _exit(1); } pwait(p->pid, &status); getinfo(p, status); if (p->status != STOPPED) { error("program could not begin execution"); } ptraced(p->pid);}/* * Terminate a ptrace'd process. */public pterm (p)Process p;{ integer status; if (p != nil and p->pid != 0) { ptrace(PKILL, p->pid, 0, 0); pwait(p->pid, &status); unptraced(p->pid); }}/* * Continue a stopped process. The first argument points to a Process * structure. Before the process is restarted it's user area is modified * according to the values in the structure. When this routine finishes, * the structure has the new values from the process's user area. * * Pcont terminates when the process stops with a signal pending that * is being traced (via psigtrace), or when the process terminates. */private pcont(p, signo)Process p;int signo;{ int s, status; if (p->pid == 0) { error("program not active"); } s = signo; do { setinfo(p, s); if (traceexec) { printf("!! pcont from 0x%x with signal %d (%d)\n", p->reg[PROGCTR], s, p->signo); fflush(stdout); } sigs_off(); if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) { panic("error %d trying to continue process", errno); } pwait(p->pid, &status); sigs_on(); getinfo(p, status); if (traceexec and not istraced(p)) { printf("!! ignored signal %d at 0x%x\n", p->signo, p->reg[PROGCTR]); fflush(stdout); } s = p->signo; } while (p->status == STOPPED and not istraced(p)); if (traceexec) { printf("!! pcont to 0x%x on signal %d\n", p->reg[PROGCTR], p->signo); fflush(stdout); }}/* * Single step as best ptrace can. */public pstep(p, signo)Process p;integer signo;{ int status; setinfo(p, signo); if (traceexec) { printf("!! pstep from pc 0x%x with signal %d (%d)\n", p->reg[PROGCTR], signo, p->signo); fflush(stdout); } sigs_off(); if (ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo) < 0) { panic("error %d trying to step process", errno); } pwait(p->pid, &status); sigs_on(); getinfo(p, status); if (traceexec) { printf("!! pstep to pc 0x%x on signal %d\n", p->reg[PROGCTR], p->signo); fflush(stdout); } if (p->status != STOPPED) { error("program unexpectedly exited with %d\n", p->exitval); }}/* * Return from execution when the given signal is pending. */public psigtrace(p, sig, sw)Process p;int sig;Boolean sw;{ if (sw) { p->sigset |= setrep(sig); } else { p->sigset &= ~setrep(sig); }}/* * Don't catch any signals. * Particularly useful when letting a process finish uninhibited. */public unsetsigtraces(p)Process p;{ p->sigset = 0;}/* * Turn off attention to signals not being caught. */private Intfunc *sigfunc[NSIG];private sigs_off(){ register int i; for (i = FIRSTSIG; i < LASTSIG; i++) { if (i != SIGKILL) { sigfunc[i] = signal(i, SIG_IGN); } }}/* * Turn back on attention to signals. */private sigs_on(){ register int i; for (i = FIRSTSIG; i < LASTSIG; i++) { if (i != SIGKILL) { signal(i, sigfunc[i]); } }}/* * Get process information from user area. */private int rloc[] ={ R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, AP, FP, SP, PC};private getinfo(p, status)register Process p;register int status;{ register int i; Address addr; p->signo = (status&0177); p->exitval = ((status >> 8)&0377); if (p->signo != STOPPED) { p->status = FINISHED; p->pid = 0; p->reg[PROGCTR] = 0; } else { p->status = p->signo; p->signo = p->exitval; p->exitval = 0; p->mask = ptrace(UREAD, p->pid, regloc(PS), 0); for (i = 0; i < NREG; i++) { p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0); p->oreg[i] = p->reg[i]; } savetty(stdout, &(p->ttyinfo)); addr = (Address) &(((struct user *) 0)->u_signal[p->signo]); p->sigstatus = (Address) ptrace(UREAD, p->pid, addr, 0); }}/* * Set process's user area information from given process structure. */private setinfo(p, signo)register Process p;int signo;{ register int i; register int r; if (signo == DEFSIG) { if (istraced(p) and (p->sigstatus == 0 or p->sigstatus == 1)) { p->signo = 0; } } else { p->signo = signo; } for (i = 0; i < NREG; i++) { if ((r = p->reg[i]) != p->oreg[i]) { ptrace(UWRITE, p->pid, regloc(rloc[i]), r); } } restoretty(stdout, &(p->ttyinfo));}/* * Return the address associated with the current signal. * (Plus two since the address points to the beginning of a procedure). */public Address usignal (p)Process p;{ Address r; r = p->sigstatus; if (r != 0 and r != 1) { r += 2; } return r;}/* * Structure for reading and writing by words, but dealing with bytes. */typedef union { Word pword; Byte pbyte[sizeof(Word)];} Pword;/* * Read (write) from (to) the process' address space. * We must deal with ptrace's inability to look anywhere other * than at a word boundary. */private Word fetch();private store();private pio(p, op, seg, buff, addr, nbytes)Process p;PioOp op;PioSeg seg;char *buff;Address addr;int nbytes;{ register int i; register Address newaddr; register char *cp; char *bufend; Pword w; Address wordaddr; int byteoff; if (p->status != STOPPED) { error("program is not active"); } cp = buff; newaddr = addr; wordaddr = (newaddr&WMASK); if (wordaddr != newaddr) { w.pword = fetch(p, seg, wordaddr); for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) { if (op == PREAD) { *cp++ = w.pbyte[i]; } else { w.pbyte[i] = *cp++; } nbytes--; } if (op == PWRITE) { store(p, seg, wordaddr, w.pword); } newaddr = wordaddr + sizeof(Word); } byteoff = (nbytes&(~WMASK)); nbytes -= byteoff; bufend = cp + nbytes; while (cp < bufend) { if (op == PREAD) { *((Word *) cp) = fetch(p, seg, newaddr); } else { store(p, seg, newaddr, *((Word *) cp)); } cp += sizeof(Word); newaddr += sizeof(Word); } if (byteoff > 0) { w.pword = fetch(p, seg, newaddr); for (i = 0; i < byteoff; i++) { if (op == PREAD) { *cp++ = w.pbyte[i]; } else { w.pbyte[i] = *cp++; } } if (op == PWRITE) { store(p, seg, newaddr, w.pword); } }}/* * Get a word from a process at the given address. * The address is assumed to be on a word boundary. * * A simple cache scheme is used to avoid redundant ptrace calls * to the instruction space since it is assumed to be pure. * * It is necessary to use a write-through scheme so that * breakpoints right next to each other don't interfere. */private Integer nfetchs, nreads, nwrites;private Word fetch(p, seg, addr)Process p;PioSeg seg;register int addr;{ register CacheWord *wp; register Word w; switch (seg) { case TEXTSEG: ++nfetchs; wp = &p->word[cachehash(addr)]; if (addr == 0 or wp->addr != addr) { ++nreads; w = ptrace(IREAD, p->pid, addr, 0); wp->addr = addr; wp->val = w; } else { w = wp->val; } break; case DATASEG: w = ptrace(DREAD, p->pid, addr, 0); break; default: panic("fetch: bad seg %d", seg); /* NOTREACHED */ } return w;}/* * Put a word into the process' address space at the given address. * The address is assumed to be on a word boundary. */private store(p, seg, addr, data)Process p;PioSeg seg;int addr;Word data;{ register CacheWord *wp; switch (seg) { case TEXTSEG: ++nwrites; wp = &p->word[cachehash(addr)]; wp->addr = addr; wp->val = data; ptrace(IWRITE, p->pid, addr, data); break; case DATASEG: ptrace(DWRITE, p->pid, addr, data); break; default: panic("store: bad seg %d", seg); /* NOTREACHED */ }}public printptraceinfo(){ printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites);}/* * Redirect input. * Assuming this is called from a child, we should be careful to avoid * (possibly) shared standard I/O buffers. */private infrom (filename)String filename;{ Fileid in; in = open(filename, 0); if (in == -1) { write(2, "can't read ", 11); write(2, filename, strlen(filename)); write(2, "\n", 1); _exit(1); } fswap(0, in);}/* * Redirect standard output. * Same assumptions as for "infrom" above. */private outto (filename)String filename;{ Fileid out; out = creat(filename, 0666); if (out == -1) { write(2, "can't write ", 12); write(2, filename, strlen(filename)); write(2, "\n", 1); _exit(1); } fswap(1, out);}/* * Swap file numbers, useful for redirecting standard input or output. */private fswap(oldfd, newfd)Fileid oldfd;Fileid newfd;{ if (oldfd != newfd) { close(oldfd); dup(newfd); close(newfd); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -