📄 pcontrol.c
字号:
if (P->core->core_priv != NULL) { size = MIN(P->core->core_priv_size, size); (void) memcpy(pprv, P->core->core_priv, size); return (size); } errno = ENODATA; return (-1);}intPsetpriv(struct ps_prochandle *P, prpriv_t *pprv){ int rc; long *ctl; size_t sz; if (P->state == PS_DEAD) { errno = EBADF; return (-1); } sz = PRIV_PRPRIV_SIZE(pprv) + sizeof (long); sz = ((sz - 1) / sizeof (long) + 1) * sizeof (long); ctl = malloc(sz); if (ctl == NULL) return (-1); ctl[0] = PCSPRIV; (void) memcpy(&ctl[1], pprv, PRIV_PRPRIV_SIZE(pprv)); if (write(P->ctlfd, ctl, sz) != sz) rc = -1; else rc = 0; free(ctl); return (rc);}void *Pprivinfo(struct ps_prochandle *P){ /* Use default from libc */ if (P->state != PS_DEAD) return (NULL); return (P->core->core_privinfo);}/* * Ensure that all cached state is written to the process. * The cached state is the LWP's signal mask and registers * and the process's tracing flags. */voidPsync(struct ps_prochandle *P){ int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd; long cmd[6]; iovec_t iov[12]; int n = 0; if (P->flags & SETHOLD) { cmd[0] = PCSHOLD; iov[n].iov_base = (caddr_t)&cmd[0]; iov[n++].iov_len = sizeof (long); iov[n].iov_base = (caddr_t)&P->status.pr_lwp.pr_lwphold; iov[n++].iov_len = sizeof (P->status.pr_lwp.pr_lwphold); } if (P->flags & SETREGS) { cmd[1] = PCSREG;#ifdef __i386 /* XX64 we should probably restore REG_GS after this */ if (ctlfd == P->agentctlfd) P->status.pr_lwp.pr_reg[GS] = 0;#elif defined(__amd64) /* XX64 */#endif iov[n].iov_base = (caddr_t)&cmd[1]; iov[n++].iov_len = sizeof (long); iov[n].iov_base = (caddr_t)&P->status.pr_lwp.pr_reg[0]; iov[n++].iov_len = sizeof (P->status.pr_lwp.pr_reg); } if (P->flags & SETSIG) { cmd[2] = PCSTRACE; iov[n].iov_base = (caddr_t)&cmd[2]; iov[n++].iov_len = sizeof (long); iov[n].iov_base = (caddr_t)&P->status.pr_sigtrace; iov[n++].iov_len = sizeof (P->status.pr_sigtrace); } if (P->flags & SETFAULT) { cmd[3] = PCSFAULT; iov[n].iov_base = (caddr_t)&cmd[3]; iov[n++].iov_len = sizeof (long); iov[n].iov_base = (caddr_t)&P->status.pr_flttrace; iov[n++].iov_len = sizeof (P->status.pr_flttrace); } if (P->flags & SETENTRY) { cmd[4] = PCSENTRY; iov[n].iov_base = (caddr_t)&cmd[4]; iov[n++].iov_len = sizeof (long); iov[n].iov_base = (caddr_t)&P->status.pr_sysentry; iov[n++].iov_len = sizeof (P->status.pr_sysentry); } if (P->flags & SETEXIT) { cmd[5] = PCSEXIT; iov[n].iov_base = (caddr_t)&cmd[5]; iov[n++].iov_len = sizeof (long); iov[n].iov_base = (caddr_t)&P->status.pr_sysexit; iov[n++].iov_len = sizeof (P->status.pr_sysexit); } if (n == 0 || writev(ctlfd, iov, n) < 0) return; /* nothing to do or write failed */ P->flags &= ~(SETSIG|SETFAULT|SETENTRY|SETEXIT|SETHOLD|SETREGS);}/* * Reopen the /proc file (after PS_LOST). */intPreopen(struct ps_prochandle *P){ int fd; char procname[100]; char *fname; if (P->state == PS_DEAD || P->state == PS_IDLE) return (0); if (P->agentcnt > 0) { P->agentcnt = 1; Pdestroy_agent(P); } (void) sprintf(procname, "/proc/%d/", (int)P->pid); fname = procname + strlen(procname); (void) strcpy(fname, "as"); if ((fd = open(procname, O_RDWR)) < 0 || close(P->asfd) < 0 || (fd = dupfd(fd, P->asfd)) != P->asfd) { dprintf("Preopen: failed to open %s: %s\n", procname, strerror(errno)); if (fd >= 0) (void) close(fd); return (-1); } P->asfd = fd; (void) strcpy(fname, "status"); if ((fd = open(procname, O_RDONLY)) < 0 || close(P->statfd) < 0 || (fd = dupfd(fd, P->statfd)) != P->statfd) { dprintf("Preopen: failed to open %s: %s\n", procname, strerror(errno)); if (fd >= 0) (void) close(fd); return (-1); } P->statfd = fd; (void) strcpy(fname, "ctl"); if ((fd = open(procname, O_WRONLY)) < 0 || close(P->ctlfd) < 0 || (fd = dupfd(fd, P->ctlfd)) != P->ctlfd) { dprintf("Preopen: failed to open %s: %s\n", procname, strerror(errno)); if (fd >= 0) (void) close(fd); return (-1); } P->ctlfd = fd; /* * Set the state to PS_RUN and wait for the process to stop so that * we re-read the status from the new P->statfd. If this fails, Pwait * will reset the state to PS_LOST and we fail the reopen. Before * returning, we also forge a bit of P->status to allow the debugger to * see that we are PS_LOST following a successful exec. */ P->state = PS_RUN; if (Pwait(P, 0) == -1) {#ifdef _ILP32 if (errno == EOVERFLOW) P->status.pr_dmodel = PR_MODEL_LP64;#endif P->status.pr_lwp.pr_why = PR_SYSEXIT; P->status.pr_lwp.pr_what = SYS_execve; P->status.pr_lwp.pr_errno = 0; return (-1); } /* * The process should be stopped on exec (REQUESTED) * or else should be stopped on exit from exec() (SYSEXIT) */ if (P->state == PS_STOP && (P->status.pr_lwp.pr_why == PR_REQUESTED || (P->status.pr_lwp.pr_why == PR_SYSEXIT && (P->status.pr_lwp.pr_what == SYS_exec || P->status.pr_lwp.pr_what == SYS_execve)))) { /* fake up stop-on-exit-from-execve */ if (P->status.pr_lwp.pr_why == PR_REQUESTED) { P->status.pr_lwp.pr_why = PR_SYSEXIT; P->status.pr_lwp.pr_what = SYS_execve; P->status.pr_lwp.pr_errno = 0; } } else { dprintf("Preopen: expected REQUESTED or " "SYSEXIT(SYS_execve) stop\n"); } return (0);}/* * Define all settable flags other than the microstate accounting flags. */#define ALL_SETTABLE_FLAGS (PR_FORK|PR_RLC|PR_KLC|PR_ASYNC|PR_BPTADJ|PR_PTRACE)/* * Restore /proc tracing flags to their original values * in preparation for releasing the process. * Also called by Pcreate() to clear all tracing flags. */static voidrestore_tracing_flags(struct ps_prochandle *P){ long flags; long cmd[4]; iovec_t iov[8]; if (P->flags & CREATED) { /* we created this process; clear all tracing flags */ premptyset(&P->status.pr_sigtrace); premptyset(&P->status.pr_flttrace); premptyset(&P->status.pr_sysentry); premptyset(&P->status.pr_sysexit); if ((P->status.pr_flags & ALL_SETTABLE_FLAGS) != 0) (void) Punsetflags(P, ALL_SETTABLE_FLAGS); } else { /* we grabbed the process; restore its tracing flags */ P->status.pr_sigtrace = P->orig_status.pr_sigtrace; P->status.pr_flttrace = P->orig_status.pr_flttrace; P->status.pr_sysentry = P->orig_status.pr_sysentry; P->status.pr_sysexit = P->orig_status.pr_sysexit; if ((P->status.pr_flags & ALL_SETTABLE_FLAGS) != (flags = (P->orig_status.pr_flags & ALL_SETTABLE_FLAGS))) { (void) Punsetflags(P, ALL_SETTABLE_FLAGS); if (flags) (void) Psetflags(P, flags); } } cmd[0] = PCSTRACE; iov[0].iov_base = (caddr_t)&cmd[0]; iov[0].iov_len = sizeof (long); iov[1].iov_base = (caddr_t)&P->status.pr_sigtrace; iov[1].iov_len = sizeof (P->status.pr_sigtrace); cmd[1] = PCSFAULT; iov[2].iov_base = (caddr_t)&cmd[1]; iov[2].iov_len = sizeof (long); iov[3].iov_base = (caddr_t)&P->status.pr_flttrace; iov[3].iov_len = sizeof (P->status.pr_flttrace); cmd[2] = PCSENTRY; iov[4].iov_base = (caddr_t)&cmd[2]; iov[4].iov_len = sizeof (long); iov[5].iov_base = (caddr_t)&P->status.pr_sysentry; iov[5].iov_len = sizeof (P->status.pr_sysentry); cmd[3] = PCSEXIT; iov[6].iov_base = (caddr_t)&cmd[3]; iov[6].iov_len = sizeof (long); iov[7].iov_base = (caddr_t)&P->status.pr_sysexit; iov[7].iov_len = sizeof (P->status.pr_sysexit); (void) writev(P->ctlfd, iov, 8); P->flags &= ~(SETSIG|SETFAULT|SETENTRY|SETEXIT);}/* * Release the process. Frees the process control structure. * flags: * PRELEASE_CLEAR Clear all tracing flags. * PRELEASE_RETAIN Retain current tracing flags. * PRELEASE_HANG Leave the process stopped and abandoned. * PRELEASE_KILL Terminate the process with SIGKILL. */voidPrelease(struct ps_prochandle *P, int flags){ if (P->state == PS_DEAD) { dprintf("Prelease: releasing handle %p PS_DEAD of pid %d\n", (void *)P, (int)P->pid); Pfree(P); return; } if (P->state == PS_IDLE) { file_info_t *fptr = list_next(&P->file_head); dprintf("Prelease: releasing handle %p PS_IDLE of file %s\n", (void *)P, fptr->file_pname); Pfree(P); return; } dprintf("Prelease: releasing handle %p pid %d\n", (void *)P, (int)P->pid); if (P->ctlfd == -1) { Pfree(P); return; } if (P->agentcnt > 0) { P->agentcnt = 1; Pdestroy_agent(P); } /* * Attempt to stop the process. */ P->state = PS_RUN; (void) Pstop(P, 1000); if (flags & PRELEASE_KILL) { if (P->state == PS_STOP) (void) Psetrun(P, SIGKILL, 0); (void) kill(P->pid, SIGKILL); Pfree(P); return; } /* * If we lost control, all we can do now is close the files. * In this case, the last close sets the process running. */ if (P->state != PS_STOP && (P->status.pr_lwp.pr_flags & (PR_ISTOP|PR_DSTOP)) == 0) { Pfree(P); return; } /* * We didn't lose control; we do more. */ Psync(P); if (flags & PRELEASE_CLEAR) P->flags |= CREATED; if (!(flags & PRELEASE_RETAIN)) restore_tracing_flags(P); if (flags & PRELEASE_HANG) { /* Leave the process stopped and abandoned */ (void) Punsetflags(P, PR_RLC|PR_KLC); Pfree(P); return; } /* * Set the process running if we created it or if it was * not originally stopped or directed to stop via /proc * or if we were given the PRELEASE_CLEAR flag. */ if ((P->flags & CREATED) || (P->orig_status.pr_lwp.pr_flags & (PR_ISTOP|PR_DSTOP)) == 0) { (void) Psetflags(P, PR_RLC); /* * We do this repeatedly because the process may have * more than one LWP stopped on an event of interest. * This makes sure all of them are set running. */ do { if (Psetrun(P, 0, 0) == -1 && errno == EBUSY) break; /* Agent LWP may be stuck */ } while (Pstopstatus(P, PCNULL, 0) == 0 && P->status.pr_lwp.pr_flags & (PR_ISTOP|PR_DSTOP)); if (P->status.pr_lwp.pr_flags & (PR_ISTOP|PR_DSTOP)) dprintf("Prelease: failed to set process running\n"); } Pfree(P);}/* debugging */voidprldump(const char *caller, lwpstatus_t *lsp){ char name[32]; uint32_t bits; switch (lsp->pr_why) { case PR_REQUESTED: dprintf("%s: REQUESTED\n", caller); break; case PR_SIGNALLED: dprintf("%s: SIGNALLED %s\n", caller, proc_signame(lsp->pr_what, name, sizeof (name))); break; case PR_FAULTED: dprintf("%s: FAULTED %s\n", caller, proc_fltname(lsp->pr_what, name, sizeof (name))); break; case PR_SYSENTRY: dprintf("%s: SYSENTRY %s\n", caller, proc_sysname(lsp->pr_what, name, sizeof (name))); break; case PR_SYSEXIT: dprintf("%s: SYSEXIT %s\n", caller, proc_sysname(lsp->pr_what, name, sizeof (name))); break; case PR_JOBCONTROL: dprintf("%s: JOBCONTROL %s\n", caller, proc_signame(lsp->pr_what, name, sizeof (name))); break; case PR_SUSPENDED: dprintf("%s: SUSPENDED\n", caller); break; default: dprintf("%s: Unknown\n", caller); break; } if (lsp->pr_cursig) dprintf("%s: p_cursig = %d\n", caller, lsp->pr_cursig); bits = *((uint32_t *)&lsp->pr_lwppend); if (bits) dprintf("%s: pr_lwppend = 0x%.8X\n", caller, bits);}/* debugging */static voidprdump(struct ps_prochandle *P){ uint32_t bits; prldump("Pstopstatus", &P->status.pr_lwp); bits = *((uint32_t *)&P->status.pr_sigpend); if (bits) dprintf("Pstopstatus: pr_sigpend = 0x%.8X\n", bits);}/* * Wait for the specified process to stop or terminate. * Or, just get the current status (PCNULL). * Or, direct it to stop and get the current status (PCDSTOP). * If the agent LWP exists, do these things to the agent, * else do these things to the process as a whole. */intPstopstatus(struct ps_prochandle *P, long request, /* PCNULL, PCDSTOP, PCSTOP, PCWSTOP */ uint_t msec) /* if non-zero, timeout in milliseconds */{ int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd; long ctl[3]; ssize_t rc; int err; int old_state = P->state; switch (P->state) { case PS_RUN: break; case PS_STOP: if (request != PCNULL && request != PCDSTOP) return (0); break; case PS_LOST: if (request != PCNULL) { errno = EAGAIN; return (-1); } break; case PS_UNDEAD: case PS_DEAD: case PS_IDLE: if (request != PCNULL) { errno = ENOENT; return (-1); } break; default: /* corrupted state */ dprintf("Pstopstatus: corrupted state: %d\n", P->state); errno = EINVAL; return (-1); } ctl[0] = PCDSTOP; ctl[1] = PCTWSTOP; ctl[2] = (long)msec; rc = 0; switch (request) { case PCSTOP: rc = write(ctlfd, &ctl[0], 3*sizeof (long)); break; case PCWSTOP: rc = write(ctlfd, &ctl[1], 2*sizeof (long)); break; case PCDSTOP: rc = write(ctlfd, &ctl[0], 1*sizeof (long)); break; case PCNULL: if (P->state == PS_DEAD || P->state == PS_IDLE) return (0); break; default: /* programming error */ errno = EINVAL; return (-1); } err = (rc < 0)? errno : 0; Psync(P); if (P->agentstatfd < 0) { if (pread(P->statfd, &P->status, sizeof (P->status), (off_t)0) < 0) err = errno; } else { if (pread(P->agentstatfd, &P->status.pr_lwp, sizeof (P->status.pr_lwp), (off_t)0) < 0) err = errno; P->status.pr_flags = P->status.pr_lwp.pr_flags; } if (err) { switch (err) { case EINTR: /* user typed ctl-C */ case ERESTART: dprintf("Pstopstatus: EINTR\n"); break; case EAGAIN: /* we lost control of the the process */ case EOVERFLOW: dprintf("Pstopstatus: PS_LOST, errno=%d\n", err); P->state = PS_LOST; break; default: /* check for dead process */ if (_libproc_debug) { const char *errstr; switch (request) { case PCNULL: errstr = "Pstopstatus PCNULL"; break; case PCSTOP: errstr = "Pstopstatus PCSTOP"; break; case PCDSTOP:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -