📄 process.c
字号:
}/* * Continue execution up to the next source line. * * There are two ways to define the next source line depending on what * is desired when a procedure or function call is encountered. Step * stops at the beginning of the procedure or call; next skips over it. *//* * Stepc or stepv is what is called when the step command is given. * It has to play with the "isstopped" information. */public stepv(){ Address newfrp, oldpc; if (not isstopped) { error("can't continue execution"); } isstopped = false; oldpc = pc; do { if(dostep(false, true)) { if((newfrp = reg(FRP)) != 0) { if(oldpc == pc) { dostep(false, false); continue; } break; } } else { newfrp = reg(FRP); } } while (newfrp != 0); isstopped = true;}public stepc(){ if (not isstopped) { error("can't continue execution"); } isstopped = false; dostep(false, false); isstopped = true;}public nextv(){ Address oldfrp, newfrp, oldpc; if (not isstopped) { error("can't continue execution"); } isstopped = false; oldfrp = reg(FRP); oldpc = pc; do { if(dostep(true, true)) { if((newfrp = reg(FRP)) == oldfrp) { if(oldpc == pc) { dostep(false, false); continue; } break; } } else { newfrp = reg(FRP); } } while (newfrp != 0); isstopped = true;}public next(){ Address oldfrp, newfrp; if (not isstopped) { error("can't continue execution"); } isstopped = false; if (inst_tracing) { dostep(true, false); } else { oldfrp = reg(FRP); do { dostep(true, false); newfrp = reg(FRP); } while (newfrp < oldfrp and newfrp != 0); } isstopped = true;}/* * Continue execution until the current function returns, or, * if the given argument is non-nil, until execution returns to * somewhere within the given function. */public rtnfunc (f)Symbol f;{ Address addr; Symbol t; if (not isstopped) { error("can't continue execution"); } else if (f != nil and not isactive(f)) { error("%s is not active", symname(f)); } else { addr = return_addr(); if (addr == nil) { error("no place to return to"); } else { isstopped = false; contto(addr); if (f != nil) { for (;;) { t = whatblock(pc); addr = return_addr(); if (t == f or addr == nil) break; contto(addr); } } if (not bpact()) { isstopped = true; printstatus(); } } }}/* * Single-step over the current machine instruction. * * If we're single-stepping by source line we want to step to the * next source line. Otherwise we're going to continue so there's * no reason to do all the work necessary to single-step to the next * source line. */public stepover(){ Boolean b; if (traceexec) { printf("!! stepping over 0x%x\n", process->reg[PROGCTR]); } if (single_stepping) { dostep(false, false); } else { b = inst_tracing; inst_tracing = true; dostep(false, false); inst_tracing = b; } if (traceexec) { printf("!! stepped over to 0x%x\n", process->reg[PROGCTR]); }}/* * Resume execution up to the given address. We can either ignore * breakpoints (stepto) or catch them (contto). */public stepto(addr)Address addr;{ xto(addr, false);}private contto (addr)Address addr;{ xto(addr, true);}private xto (addr, catchbps)Address addr;boolean catchbps;{ Address curpc; if (catchbps) { stepover(); } curpc = process->reg[PROGCTR]; if (addr != curpc) { if (traceexec) { printf("!! stepping from 0x%x to 0x%x\n", curpc, addr); } if (catchbps) { setallbps(); } setbp(addr); resume(DEFSIG); unsetbp(addr); if (catchbps) { unsetallbps(); } if (not isbperr()) { printstatus(); } }}/* * Print the status of the process. * This routine does not return. */public printstatus(){ int status; if (process->status == FINISHED) { exit(0); } else { setcurfunc(whatblock(pc)); getsrcpos(); if (process->signo == SIGINT) { isstopped = true; printerror(); } else if (isbperr() and isstopped) { printf("stopped "); printloc(); putchar('\n'); if (curline > 0) { printlines(curline, curline); } else { printinst(pc, pc); } erecover(); } else { fixintr(); isstopped = true; printerror(); } }}/* * Print out the current location in the debuggee. */public printloc(){ Symbol f; printf("in "); f = curfunc; while (isinline(f)) { f = container(f); } printname(stdout, f); putchar(' '); if (curline > 0 and not useInstLoc) { printsrcpos(); } else { useInstLoc = false; curline = 0; printf("at 0x%x", pc); }}/* * Some functions for testing the state of the process. */public Boolean notstarted(p)Process p;{ return (Boolean) (p->status == NOTSTARTED);}public Boolean isfinished(p)Process p;{ return (Boolean) (p->status == FINISHED);}/* * Predicate to test if the reason the process stopped was because * of a breakpoint. If so, as a side effect clear the local copy of * signal handler associated with process. We must do this so as to * not confuse future stepping or continuing by possibly concluding * the process should continue with a SIGTRAP handler. */public boolean isbperr(){ Process p; boolean b; p = process; if (p->status == STOPPED and p->signo == SIGTRAP) { b = true; p->sigstatus = 0; } else { b = false; } return b;}/* * Return the signal number that stopped the process. */public integer errnum (p)Process p;{ return p->signo;}/* * Return the signal code associated with the signal. */public integer errcode (p)Process p;{ return p->sigcode;}/* * Return the termination code of the process. */public integer exitcode (p)Process p;{ return p->exitval;}/* * These routines are used to access the debuggee process from * outside this module. * * They invoke "pio" which eventually leads to a call to "ptrace". * The system generates an I/O error when a ptrace fails. During reads * these are ignored, during writes they are reported as an error, and * for anything else they cause a fatal error. */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; badaddr = addr; if (coredump) { f = onsyserr(EFAULT, read_err); coredump_readdata(buff, addr, nbytes); onsyserr(EFAULT, f); } else { f = onsyserr(EIO, read_err); 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 */#define VREAD 10 /* read a vector register from process's user area */#define VWRITE 11 /* writes a vector register to process's user area *//* this routine is used to check if the process being debugged has a vector * context area. */boolean vector_context(){#ifndef NOVECTORS int acflag = ~AVP; acflag = ptrace(UREAD, process->pid, &((struct user *) 0)->u_acflag, 0); if((acflag) & AVP) return(true); else#endif /* NOVECTORS */ return(false);}/* * 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; TTYWindow *tw; struct sgttyb s; struct ltchars l; int localMode; if (p->pid != 0) { pterm(p); cacheflush(p); } fflush(stdout); psigtrace(p, SIGTRAP, true); p->pid = vfork(); if (p->pid == -1) { panic("can't fork"); } if (ischild(p->pid)) { nocatcherrs(); traceme(); if (xdb) { /* 007 - xdb support */ if (xdbwinflag == false) { xdbwinflag = true; } else { tw = CreateTTYWindow(); ioctl(tw->file,(int)TIOCGETP,(char *) &s); s.sg_flags |= ANYP | CRMOD | ECHO; s.sg_flags &= ~(RAW | CBREAK); s.sg_erase = CERASE; s.sg_kill = CKILL; ioctl(tw->file,(int)TIOCSETP,(char *) &s); ioctl(tw->file, (int) TIOCGLTC, (char *) &l); l.t_rprntc = CRPRNT; l.t_werasc = CWERASE; ioctl(tw->file, (int) TIOCSLTC, (char *) &l); localMode = LCRTBS | LCRTERA | LCRTKIL | LCTLECH; ioctl(tw->file, (int) TIOCLBIS, (char *) &localMode); dup2(tw->file,0); dup2(tw->file,1); dup2(tw->file,2); /* added by bjg */ } } if (infile != nil) { infrom(infile); } if (outfile != nil) { outto(outfile); } execv(argv[0], argv); _exit(1); } /* 010 - change format */ if (xdb) printf("%d iopid\n",p->pid); /* 008 - xdb support */ pwait(p->pid, &status); getinfo(p, status); if (p->status != STOPPED) { beginerrmsg(); fprintf(stderr, "warning: cannot execute %s\n", argv[0]); } else { 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 is 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) { p->pid = 0; p->status = FINISHED; error("error %d trying to continue process with %s", errno, sys_siglist[p->signo]); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -