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

📄 strace.c

📁 linux进程跟踪的工具和源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		return -1;	}	if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {		perror("F_SETFD");		return -1;	}#endif#ifdef FREEBSD	sprintf(proc, "/proc/%d/regs", tcp->pid);	if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {		perror("strace: open(\"/proc/.../regs\", ...)");		return -1;	}	if (cflag) {		sprintf(proc, "/proc/%d/status", tcp->pid);		if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {			perror("strace: open(\"/proc/.../status\", ...)");			return -1;		}	} else		tcp->pfd_status = -1;#endif /* FREEBSD */	rebuild_pollv();	if (!attaching) {		/*		 * Wait for the child to pause.  Because of a race		 * condition we have to poll for the event.		 */		for (;;) {			if (IOCTL_STATUS (tcp) < 0) {				perror("strace: PIOCSTATUS");				return -1;			}			if (tcp->status.PR_FLAGS & PR_ASLEEP)			    break;		}	}#ifndef FREEBSD	/* Stop the process so that we own the stop. */	if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {		perror("strace: PIOCSTOP");		return -1;	}#endif	#ifdef PIOCSET	/* Set Run-on-Last-Close. */	arg = PR_RLC;	if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {		perror("PIOCSET PR_RLC");		return -1;	}	/* Set or Reset Inherit-on-Fork. */	arg = PR_FORK;	if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {		perror("PIOC{SET,RESET} PR_FORK");		return -1;	}#else  /* !PIOCSET */#ifndef FREEBSD		if (ioctl(tcp->pfd, PIOCSRLC) < 0) {		perror("PIOCSRLC");		return -1;	}	if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {		perror("PIOC{S,R}FORK");		return -1;	}#else /* FREEBSD */	/* just unset the PF_LINGER flag for the Run-on-Last-Close. */	if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {	        perror("PIOCGFL");	        return -1;	}	arg &= ~PF_LINGER;	if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {	        perror("PIOCSFL");	        return -1;	}#endif /* FREEBSD */#endif /* !PIOCSET */#ifndef FREEBSD	/* Enable all syscall entries. */	prfillset(&sc_enter);	if (IOCTL(tcp->pfd, PIOCSENTRY, &sc_enter) < 0) {		perror("PIOCSENTRY");		return -1;	}	/* Enable all syscall exits. */	prfillset(&sc_exit);	if (IOCTL(tcp->pfd, PIOCSEXIT, &sc_exit) < 0) {		perror("PIOSEXIT");		return -1;	}	/* Enable all signals. */	prfillset(&signals);	if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {		perror("PIOCSTRACE");		return -1;	}	/* Enable all faults. */	prfillset(&faults);	if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {		perror("PIOCSFAULT");		return -1;	}#else /* FREEBSD */	/* set events flags. */	arg = S_SIG | S_SCE | S_SCX ;	if(ioctl(tcp->pfd, PIOCBIS, arg) < 0) {		perror("PIOCBIS");		return -1;	}#endif /* FREEBSD */	if (!attaching) {#ifdef MIPS		/*		 * The SGI PRSABORT doesn't work for pause() so		 * we send it a caught signal to wake it up.		 */		kill(tcp->pid, SIGINT);#else /* !MIPS */#ifdef PRSABORT			/* The child is in a pause(), abort it. */		arg = PRSABORT;		if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {			perror("PIOCRUN");			return -1;		}#endif		#endif /* !MIPS*/#ifdef FREEBSD		/* wake up the child if it received the SIGSTOP */		kill(tcp->pid, SIGCONT);#endif				for (;;) {			/* Wait for the child to do something. */			if (IOCTL_WSTOP (tcp) < 0) {				perror("PIOCWSTOP");				return -1;			}			if (tcp->status.PR_WHY == PR_SYSENTRY) {				tcp->flags &= ~TCB_INSYSCALL;				get_scno(tcp);				if (tcp->scno == SYS_execve)					break;			}			/* Set it running: maybe execve will be next. */#ifndef FREEBSD			arg = 0;			if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {#else /* FREEBSD */			if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {#endif /* FREEBSD */			  				perror("PIOCRUN");				return -1;			}#ifdef FREEBSD			/* handle the case where we "opened" the child before			   it did the kill -STOP */			if (tcp->status.PR_WHY == PR_SIGNALLED &&			    tcp->status.PR_WHAT == SIGSTOP)			        kill(tcp->pid, SIGCONT);#endif					}#ifndef FREEBSD	}#else /* FREEBSD */	} else {		if (attaching < 2) { 			/* We are attaching to an already running process.			 * Try to figure out the state of the process in syscalls,			 * to handle the first event well.			 * This is done by having a look at the "wchan" property of the			 * process, which tells where it is stopped (if it is). */			FILE * status;			char wchan[20]; /* should be enough */						sprintf(proc, "/proc/%d/status", tcp->pid);			status = fopen(proc, "r");			if (status &&			    (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"				    "%*d,%*d %*d,%*d %19s", wchan) == 1) &&			    strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&			    strcmp(wchan, "stopevent")) {				/* The process is asleep in the middle of a syscall.				   Fake the syscall entry event */				tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);				tcp->status.PR_WHY = PR_SYSENTRY;				trace_syscall(tcp);			}			if (status)				fclose(status);		} /* otherwise it's a fork being followed */	}#endif /* FREEBSD */#ifndef HAVE_POLLABLE_PROCFS	if (proc_poll_pipe[0] != -1)		proc_poller(tcp->pfd);	else if (nprocs > 1) {		proc_poll_open();		proc_poller(last_pfd);		proc_poller(tcp->pfd);	}	last_pfd = tcp->pfd;#endif /* !HAVE_POLLABLE_PROCFS */	return 0;}#endif /* USE_PROCFS */static struct tcb *pid2tcb(pid)int pid;{	int i;	struct tcb *tcp;	for (i = 0, tcp = tcbtab; i < MAX_PROCS; i++, tcp++) {		if (pid && tcp->pid != pid)			continue;		if (tcp->flags & TCB_INUSE)			return tcp;	}	return NULL;}#ifdef USE_PROCFSstatic struct tcb *pfd2tcb(pfd)int pfd;{	int i;	struct tcb *tcp;	for (i = 0, tcp = tcbtab; i < MAX_PROCS; i++, tcp++) {		if (tcp->pfd != pfd)			continue;		if (tcp->flags & TCB_INUSE)			return tcp;	}	return NULL;}#endif /* USE_PROCFS */voiddroptcb(tcp)struct tcb *tcp;{	if (tcp->pid == 0)		return;	nprocs--;	tcp->pid = 0;	tcp->flags = 0;	if (tcp->pfd != -1) {		close(tcp->pfd);		tcp->pfd = -1;#ifdef FREEBSD		if (tcp->pfd_reg != -1) {		        close(tcp->pfd_reg);		        tcp->pfd_reg = -1;		}		if (tcp->pfd_status != -1) {			close(tcp->pfd_status);			tcp->pfd_status = -1;		}#endif /* !FREEBSD */		#ifdef USE_PROCFS		rebuild_pollv();#endif	}	if (tcp->parent != NULL) {		tcp->parent->nchildren--;		tcp->parent = NULL;	}#if 0	if (tcp->outf != stderr)		fclose(tcp->outf);#endif	tcp->outf = 0;}#ifndef USE_PROCFSstatic intresume(tcp)struct tcb *tcp;{	if (tcp == NULL)		return -1;	if (!(tcp->flags & TCB_SUSPENDED)) {		fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);		return -1;	}	tcp->flags &= ~TCB_SUSPENDED;	if (ptrace(PTRACE_SYSCALL, tcp->pid, (char *) 1, 0) < 0) {		perror("resume: ptrace(PTRACE_SYSCALL, ...)");		return -1;	}	if (!qflag)		fprintf(stderr, "Process %u resumed\n", tcp->pid);	return 0;}#endif /* !USE_PROCFS *//* detach traced process; continue with sig */static intdetach(tcp, sig)struct tcb *tcp;int sig;{	int error = 0;#ifdef LINUX	int status;#endif	if (tcp->flags & TCB_BPTSET)		sig = SIGKILL;#ifdef LINUX	/*	 * Linux wrongly insists the child be stopped	 * before detaching.  Arghh.  We go through hoops	 * to make a clean break of things.	 */#if defined(SPARC)#undef PTRACE_DETACH#define PTRACE_DETACH PTRACE_SUNDETACH#endif	if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {		/* On a clear day, you can see forever. */	}	else if (errno != ESRCH) {		/* Shouldn't happen. */		perror("detach: ptrace(PTRACE_DETACH, ...)");	}	else if (kill(tcp->pid, 0) < 0) {		if (errno != ESRCH)			perror("detach: checking sanity");	}	else if (kill(tcp->pid, SIGSTOP) < 0) {		if (errno != ESRCH)			perror("detach: stopping child");	}	else {		for (;;) {			if (waitpid(tcp->pid, &status, 0) < 0) {				if (errno != ECHILD)					perror("detach: waiting");				break;			}			if (!WIFSTOPPED(status)) {				/* Au revoir, mon ami. */				break;			}			if (WSTOPSIG(status) == SIGSTOP) {				if ((error = ptrace(PTRACE_DETACH,				    tcp->pid, (char *) 1, sig)) < 0) {					if (errno != ESRCH)						perror("detach: ptrace(PTRACE_DETACH, ...)");					/* I died trying. */				}				break;			}			if ((error = ptrace(PTRACE_CONT, tcp->pid, (char *) 1,			    WSTOPSIG(status) == SIGTRAP ?			    0 : WSTOPSIG(status))) < 0) {				if (errno != ESRCH)					perror("detach: ptrace(PTRACE_CONT, ...)");				break;			}		}	}#endif /* LINUX */#if defined(SUNOS4)	/* PTRACE_DETACH won't respect `sig' argument, so we post it here. */	if (sig && kill(tcp->pid, sig) < 0)		perror("detach: kill");	sig = 0;	if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) < 0)		perror("detach: ptrace(PTRACE_DETACH, ...)");#endif /* SUNOS4 */#ifndef USE_PROCFS	if (waiting_parent(tcp))		error = resume(tcp->parent);#endif /* !USE_PROCFS */	if (!qflag)		fprintf(stderr, "Process %u detached\n", tcp->pid);	droptcb(tcp);	return error;}#ifdef USE_PROCFSstatic voidreaper(sig)int sig;{	int pid;	int status;	while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {#if 0		struct tcb *tcp;		tcp = pid2tcb(pid);		if (tcp)			droptcb(tcp);#endif	}}#endif /* USE_PROCFS */static voidcleanup(){	int i;	struct tcb *tcp;	for (i = 0, tcp = tcbtab; i < MAX_PROCS; i++, tcp++) {		if (!(tcp->flags & TCB_INUSE))			continue;		if (debug)			fprintf(stderr,				"cleanup: looking at pid %u\n", tcp->pid);		if (tcp_last &&		    (!outfname || followfork < 2 || tcp_last == tcp)) {			tprintf(" <unfinished ...>\n");			tcp_last = NULL;		}		if (tcp->flags & TCB_ATTACHED)			detach(tcp, 0);		else {			kill(tcp->pid, SIGCONT);			kill(tcp->pid, SIGTERM);		}	}	if (cflag)		call_summary(outf);}static voidinterrupt(sig)int sig;{	interrupted = 1;}#ifndef HAVE_STRERROR#ifndef SYS_ERRLIST_DECLAREDextern int sys_nerr;extern char *sys_errlist[];#endif /* SYS_ERRLIST_DECLARED */const char *strerror(errno)int errno;{	static char buf[64];	if (errno < 1 || errno >= sys_nerr) {		sprintf(buf, "Unknown error %d", errno);		return buf;	}	return sys_errlist[errno];}#endif /* HAVE_STERRROR */#ifndef HAVE_STRSIGNAL#ifndef SYS_SIGLIST_DECLARED#ifdef HAVE__SYS_SIGLIST	extern char *_sys_siglist[];#else	extern char *sys_siglist[];#endif#endif /* SYS_SIGLIST_DECLARED */const char *strsignal(sig)int sig;{	static char buf[64];	if (sig < 1 || sig >= NSIG) {		sprintf(buf, "Unknown signal %d", sig);		return buf;	}#ifdef HAVE__SYS_SIGLIST	return _sys_siglist[sig];#else	return sys_siglist[sig];#endif}#endif /* HAVE_STRSIGNAL */#ifdef USE_PROCFSstatic voidrebuild_pollv(){	int i, j;	struct tcb *tcp;	for (i = j = 0, tcp = tcbtab; i < MAX_PROCS; i++, tcp++) {		if (!(tcp->flags & TCB_INUSE))			continue;		pollv[j].fd = tcp->pfd;		pollv[j].events = POLLWANT;		j++;	}	if (j != nprocs) {		fprintf(stderr, "strace: proc miscount\n");		exit(1);	}}#ifndef HAVE_POLLABLE_PROCFSstatic voidproc_poll_open(){	int arg;	int i;	if (pipe(proc_poll_pipe) < 0) {		perror("pipe");		exit(1);	}	for (i = 0; i < 2; i++) {		if ((arg = fcntl(proc_poll_pipe[i], F_GETFD)) < 0) {			perror("F_GETFD");			exit(1);		}		if (fcntl(proc_poll_pipe[i], F_SETFD, arg|FD_CLOEXEC) < 0) {			perror("F_SETFD");			exit(1);		}	}}static intproc_poll(pollv, nfds, timeout)struct pollfd *pollv;int nfds;int timeout;{	int i;	int n;	struct proc_pollfd pollinfo;	if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)		return n;	if (n != sizeof(struct proc_pollfd)) {		fprintf(stderr, "panic: short read: %d\n", n);		exit(1);	}	for (i = 0; i < nprocs; i++) {		if (pollv[i].fd == pollinfo.fd)			pollv[i].revents = pollinfo.revents;		else			pollv[i].revents = 0;	}	poller_pid = pollinfo.pid;	return 1;}static voidwakeup_handler(sig)int sig;{}static voidproc_poller(pfd)int pfd;{	struct proc_pollfd pollinfo;	struct sigaction sa;	sigset_t blocked_set, empty_set;	int i;	int n;	struct rlimit rl;#ifdef FREEBSD	struct procfs_status pfs;#endif /* FREEBSD */	switch (fork()) {	case -1:		perror("fork");		_exit(0);	case 0:		break;	default:		return;	}	sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;	sa.sa_flags = 0;	sigemptyset(&sa.sa_mask);	sigaction(SIGHUP, &sa, NULL);	sigaction(SIGINT, &sa, NULL);	sigaction(SIGQUIT, &sa, NULL);	sigaction(SIGPIPE, &sa, NULL);	sigaction(SIGTERM, &sa, NULL);	sa.sa_handler = wakeup_handler;	sigaction(SIGUSR1, &sa, NULL);	sigemptyset(&blocked_set);	sigaddset(&blocked_set, SIGUSR1);	sigprocmask(SIG_BLOCK, &blocked_set, NULL);	sigemptyset(&empty_set);	if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {		perror("getrlimit(RLIMIT_NOFILE, ...)");		_exit(0);	}	n = rl.rlim_cur;	for (i = 0; i < n; i++) {		if (i != pfd && i != proc_poll_pipe[1])			close(i);	}	pollinfo.fd = pfd;	pollinfo.pid = getpid();	for (;;) {#ifndef FREEBSD	        if (ioctl(pfd, PIOCWSTOP, NULL) < 0)#else /* FREEBSD */	        if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)#endif /* FREEBSD */		{			switch (errno) {			case EINTR:				continue;			case EBADF:				pollinfo.revents = POLLERR;				break;			case ENOENT:				pollinfo.revents = POLLHUP;

⌨️ 快捷键说明

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