⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcontrol.c

📁 Sun Solaris 10 中的 DTrace 组件的源代码。请参看: http://www.sun.com/software/solaris/observability.jsp
💻 C
📖 第 1 页 / 共 5 页
字号:
	cwp->pr_vaddr = wp->pr_vaddr;	cwp->pr_size = wp->pr_size;	cwp->pr_wflags = wp->pr_wflags;	if (write(P->ctlfd, ctl, sizeof (ctl)) != sizeof (ctl))		return (-1);	return (0);}/* * Remove the watchpoint described by wp. */intPdelwapt(struct ps_prochandle *P, const prwatch_t *wp){	long ctl[1 + sizeof (prwatch_t) / sizeof (long)];	prwatch_t *cwp = (prwatch_t *)&ctl[1];	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||	    P->state == PS_IDLE) {		errno = ENOENT;		return (-1);	}	ctl[0] = PCWATCH;	cwp->pr_vaddr = wp->pr_vaddr;	cwp->pr_size = wp->pr_size;	cwp->pr_wflags = 0;	if (write(P->ctlfd, ctl, sizeof (ctl)) != sizeof (ctl))		return (-1);	return (0);}/* * Common code for Pxecwapt() and Lxecwapt().  Develop the array of requests * that will do the job, then write them to the specified control file * descriptor.  Return the non-zero errno if the write fails. */static intexecute_wapt(	int ctlfd,		/* process or LWP control file descriptor */	const fltset_t *faultset,	/* current set of traced faults */	const sigset_t *sigmask,	/* current signal mask */	const prwatch_t *wp)		/* watchpoint descriptor */{	long ctl[	    1 + sizeof (sigset_t) / sizeof (long) +		/* PCSHOLD */	    1 + sizeof (fltset_t) / sizeof (long) +		/* PCSFAULT */	    1 + sizeof (prwatch_t) / sizeof (long) +		/* PCWATCH */	    2 +							/* PCRUN */	    1 +							/* PCWSTOP */	    1 +							/* PCCFAULT */	    1 + sizeof (prwatch_t) / sizeof (long) +		/* PCWATCH */	    1 + sizeof (fltset_t) / sizeof (long) +		/* PCSFAULT */	    1 + sizeof (sigset_t) / sizeof (long)];		/* PCSHOLD */	long *ctlp = ctl;	int error = 0;	sigset_t unblock;	sigset_t *holdp;	fltset_t *faultp;	prwatch_t *prw;	ssize_t ssize;	size_t size;	(void) sigprocmask(SIG_BLOCK, &blockable_sigs, &unblock);	/*	 * Hold all posted signals in the victim process prior to stepping.	 */	*ctlp++ = PCSHOLD;	holdp = (sigset_t *)ctlp;	prfillset(holdp);	prdelset(holdp, SIGKILL);	prdelset(holdp, SIGSTOP);	ctlp += sizeof (sigset_t) / sizeof (long);	/*	 * Force tracing of FLTTRACE since we need to single step.	 */	if (!(prismember(faultset, FLTTRACE))) {		*ctlp++ = PCSFAULT;		faultp = (fltset_t *)ctlp;		*faultp = *faultset;		praddset(faultp, FLTTRACE);		ctlp += sizeof (fltset_t) / sizeof (long);	}	/*	 * Clear only the current watchpoint by setting pr_wflags to zero.	 */	*ctlp++ = PCWATCH;	prw = (prwatch_t *)ctlp;	prw->pr_vaddr = wp->pr_vaddr;	prw->pr_size = wp->pr_size;	prw->pr_wflags = 0;	ctlp += sizeof (prwatch_t) / sizeof (long);	/*	 * Clear the current signal and fault; set running with single-step.	 * Then wait for the victim to stop and cancel the FLTTRACE.	 */	*ctlp++ = PCRUN;	*ctlp++ = PRCSIG | PRCFAULT | PRSTEP;	*ctlp++ = PCWSTOP;	*ctlp++ = PCCFAULT;	/*	 * Restore the current watchpoint.	 */	*ctlp++ = PCWATCH;	(void) memcpy(ctlp, wp, sizeof (prwatch_t));	ctlp += sizeof (prwatch_t) / sizeof (long);	/*	 * Restore fault tracing set if we modified it.	 */	if (!(prismember(faultset, FLTTRACE))) {		*ctlp++ = PCSFAULT;		*(fltset_t *)ctlp = *faultset;		ctlp += sizeof (fltset_t) / sizeof (long);	}	/*	 * Restore the hold mask to the current hold mask (i.e. the one	 * before we executed any of the previous operations).	 */	*ctlp++ = PCSHOLD;	*(sigset_t *)ctlp = *sigmask;	ctlp += sizeof (sigset_t) / sizeof (long);	size = (char *)ctlp - (char *)ctl;	if ((ssize = write(ctlfd, ctl, size)) != size)		error = (ssize == -1)? errno : EINTR;	(void) sigprocmask(SIG_SETMASK, &unblock, NULL);	return (error);}/* * Step over a watchpoint, i.e., execute the instruction that was stopped by * the watchpoint, and then leave the LWP stopped at the next instruction. */intPxecwapt(struct ps_prochandle *P, const prwatch_t *wp){	int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd;	int rv, error;	if (P->state != PS_STOP) {		errno = EBUSY;		return (-1);	}	Psync(P);	error = execute_wapt(ctlfd,		&P->status.pr_flttrace, &P->status.pr_lwp.pr_lwphold, wp);	rv = Pstopstatus(P, PCNULL, 0);	if (error != 0) {		if (P->status.pr_lwp.pr_why == PR_JOBCONTROL &&		    error == EBUSY) {	/* jobcontrol stop -- back off */			P->state = PS_RUN;			return (0);		}		if (error == ENOENT)			return (0);		errno = error;		return (-1);	}	return (rv);}intPsetflags(struct ps_prochandle *P, long flags){	int rc;	long ctl[2];	ctl[0] = PCSET;	ctl[1] = flags;	if (write(P->ctlfd, ctl, 2*sizeof (long)) != 2*sizeof (long)) {		rc = -1;	} else {		P->status.pr_flags |= flags;		P->status.pr_lwp.pr_flags |= flags;		rc = 0;	}	return (rc);}intPunsetflags(struct ps_prochandle *P, long flags){	int rc;	long ctl[2];	ctl[0] = PCUNSET;	ctl[1] = flags;	if (write(P->ctlfd, ctl, 2*sizeof (long)) != 2*sizeof (long)) {		rc = -1;	} else {		P->status.pr_flags &= ~flags;		P->status.pr_lwp.pr_flags &= ~flags;		rc = 0;	}	return (rc);}/* * Common function to allow clients to manipulate the action to be taken * on receipt of a signal, receipt of machine fault, entry to a system call, * or exit from a system call.  We make use of our private prset_* functions * in order to make this code be common.  The 'which' parameter identifies * the code for the event of interest (0 means change the entire set), and * the 'stop' parameter is a boolean indicating whether the process should * stop when the event of interest occurs.  The previous value is returned * to the caller; -1 is returned if an error occurred. */static intPsetaction(struct ps_prochandle *P, void *sp, size_t size,    uint_t flag, int max, int which, int stop){	int oldval;	if (which < 0 || which > max) {		errno = EINVAL;		return (-1);	}	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||	    P->state == PS_IDLE) {		errno = ENOENT;		return (-1);	}	oldval = prset_ismember(sp, size, which) ? TRUE : FALSE;	if (stop) {		if (which == 0) {			prset_fill(sp, size);			P->flags |= flag;		} else if (!oldval) {			prset_add(sp, size, which);			P->flags |= flag;		}	} else {		if (which == 0) {			prset_empty(sp, size);			P->flags |= flag;		} else if (oldval) {			prset_del(sp, size, which);			P->flags |= flag;		}	}	if (P->state == PS_RUN)		Psync(P);	return (oldval);}/* * Set action on specified signal. */intPsignal(struct ps_prochandle *P, int which, int stop){	int oldval;	if (which == SIGKILL && stop != 0) {		errno = EINVAL;		return (-1);	}	oldval = Psetaction(P, &P->status.pr_sigtrace, sizeof (sigset_t),	    SETSIG, PRMAXSIG, which, stop);	if (oldval != -1 && which == 0 && stop != 0)		prdelset(&P->status.pr_sigtrace, SIGKILL);	return (oldval);}/* * Set all signal tracing flags. */voidPsetsignal(struct ps_prochandle *P, const sigset_t *set){	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||	    P->state == PS_IDLE)		return;	P->status.pr_sigtrace = *set;	P->flags |= SETSIG;	if (P->state == PS_RUN)		Psync(P);}/* * Set action on specified fault. */intPfault(struct ps_prochandle *P, int which, int stop){	return (Psetaction(P, &P->status.pr_flttrace, sizeof (fltset_t),	    SETFAULT, PRMAXFAULT, which, stop));}/* * Set all machine fault tracing flags. */voidPsetfault(struct ps_prochandle *P, const fltset_t *set){	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||	    P->state == PS_IDLE)		return;	P->status.pr_flttrace = *set;	P->flags |= SETFAULT;	if (P->state == PS_RUN)		Psync(P);}/* * Set action on specified system call entry. */intPsysentry(struct ps_prochandle *P, int which, int stop){	return (Psetaction(P, &P->status.pr_sysentry, sizeof (sysset_t),	    SETENTRY, PRMAXSYS, which, stop));}/* * Set all system call entry tracing flags. */voidPsetsysentry(struct ps_prochandle *P, const sysset_t *set){	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||	    P->state == PS_IDLE)		return;	P->status.pr_sysentry = *set;	P->flags |= SETENTRY;	if (P->state == PS_RUN)		Psync(P);}/* * Set action on specified system call exit. */intPsysexit(struct ps_prochandle *P, int which, int stop){	return (Psetaction(P, &P->status.pr_sysexit, sizeof (sysset_t),	    SETEXIT, PRMAXSYS, which, stop));}/* * Set all system call exit tracing flags. */voidPsetsysexit(struct ps_prochandle *P, const sysset_t *set){	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||	    P->state == PS_IDLE)		return;	P->status.pr_sysexit = *set;	P->flags |= SETEXIT;	if (P->state == PS_RUN)		Psync(P);}/* * Utility function to read the contents of a file that contains a * prheader_t at the start (/proc/pid/lstatus or /proc/pid/lpsinfo). * Returns a malloc()d buffer or NULL on failure. */static prheader_t *read_lfile(struct ps_prochandle *P, const char *lname){	prheader_t *Lhp;	char lpath[64];	struct stat64 statb;	int fd;	size_t size;	ssize_t rval;	(void) snprintf(lpath, sizeof (lpath), "/proc/%d/%s",	    (int)P->status.pr_pid, lname);	if ((fd = open(lpath, O_RDONLY)) < 0 || fstat64(fd, &statb) != 0) {		if (fd >= 0)			(void) close(fd);		return (NULL);	}	/*	 * 'size' is just the initial guess at the buffer size.	 * It will have to grow if the number of lwps increases	 * while we are looking at the process.	 * 'size' must be larger than the actual file size.	 */	size = statb.st_size + 32;	for (;;) {		if ((Lhp = malloc(size)) == NULL)			break;		if ((rval = pread(fd, Lhp, size, 0)) < 0 ||		    rval <= sizeof (prheader_t)) {			free(Lhp);			Lhp = NULL;			break;		}		if (rval < size)			break;		/* need a bigger buffer */		free(Lhp);		size *= 2;	}	(void) close(fd);	return (Lhp);}/* * LWP iteration interface. */intPlwp_iter(struct ps_prochandle *P, proc_lwp_f *func, void *cd){	prheader_t *Lhp;	lwpstatus_t *Lsp;	long nlwp;	int rv;	switch (P->state) {	case PS_RUN:		(void) Pstopstatus(P, PCNULL, 0);		break;	case PS_STOP:		Psync(P);		break;	case PS_IDLE:		errno = ENODATA;		return (-1);	}	/*	 * For either live processes or cores, the single LWP case is easy:	 * the pstatus_t contains the lwpstatus_t for the only LWP.	 */	if (P->status.pr_nlwp <= 1)		return (func(cd, &P->status.pr_lwp));	/*	 * For the core file multi-LWP case, we just iterate through the	 * list of LWP structs we read in from the core file.	 */	if (P->state == PS_DEAD) {		lwp_info_t *lwp = list_prev(&P->core->core_lwp_head);		uint_t i;		for (i = 0; i < P->core->core_nlwp; i++, lwp = list_prev(lwp)) {			if (lwp->lwp_psinfo.pr_sname != 'Z' &&			    (rv = func(cd, &lwp->lwp_status)) != 0)				break;		}		return (rv);	}	/*	 * For the live process multi-LWP case, we have to work a little	 * harder: the /proc/pid/lstatus file has the array of LWP structs.	 */	if ((Lhp = read_lfile(P, "lstatus")) == NULL)		return (-1);	for (nlwp = Lhp->pr_nent, Lsp = (lwpstatus_t *)(uintptr_t)(Lhp + 1);	    nlwp > 0;	    nlwp--, Lsp = (lwpstatus_t *)((uintptr_t)Lsp + Lhp->pr_entsize)) {		if ((rv = func(cd, Lsp)) != 0)			break;	}	free(Lhp);	return (rv);}/* * Extended LWP iteration interface. * Iterate over all LWPs, active and zombie. */intPlwp_iter_all(struct ps_prochandle *P, proc_lwp_all_f *func, void *cd){	prheader_t *Lhp = NULL;	lwpstatus_t *Lsp;	lwpstatus_t *sp;	prheader_t *Lphp = NULL;	lwpsinfo_t *Lpsp;	long nstat;	long ninfo;	int rv;retry:	if (Lhp != NULL)		free(Lhp);	if (Lphp != NULL)		free(Lphp);	if (P->state == PS_RUN)		(void) Pstopstatus(P, PCNULL, 0);	(void) Ppsinfo(P);	if (P->state == PS_STOP)		Psync(P);	/*	 * For either live processes or cores, the single LWP case is easy:	 * the pstatus_t contains the lwpstatus_t for the only LWP and	 * the psinfo_t contains the lwpsinfo_t for the only LWP.	 */	if (P->status.pr_nlwp + P->status.pr_nzomb <= 1)		return (func(cd, &P->status.pr_lwp, &P->psinfo.pr_lwp));	/*	 * For the core file multi-LWP case, we just iterate through the	 * list of LWP structs we read in from the core file.	 */	if (P->state == PS_DEAD) {		lwp_info_t *lwp = list_prev(&P->core->core_lwp_head);		uint_t i;		for (i = 0; i < P->core->core_nlwp; i++, lwp = list_prev(lwp)) {			sp = (lwp->lwp_psinfo.pr_sname == 'Z')? NULL :				&lwp->lwp_status;			if ((rv = func(cd, sp, &lwp->lwp_psinfo)) != 0

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -