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

📄 strace.c

📁 linux进程跟踪的工具和源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
				break;			default:				perror("proc_poller: PIOCWSTOP");			}			write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));			_exit(0);		}		pollinfo.revents = POLLWANT;		write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));		sigsuspend(&empty_set);	}}#endif /* !HAVE_POLLABLE_PROCFS */static intchoose_pfd(){	int i, j;	struct tcb *tcp;	static int last;	if (followfork < 2 &&	    last < nprocs && (pollv[last].revents & POLLWANT)) {		/*		 * The previous process is ready to run again.  We'll		 * let it do so if it is currently in a syscall.  This		 * heuristic improves the readability of the trace.		 */		tcp = pfd2tcb(pollv[last].fd);		if (tcp && (tcp->flags & TCB_INSYSCALL))			return pollv[last].fd;	}	for (i = 0; i < nprocs; i++) {		/* Let competing children run round robin. */		j = (i + last + 1) % nprocs;		if (pollv[j].revents & (POLLHUP | POLLERR)) {			tcp = pfd2tcb(pollv[j].fd);			if (!tcp) {				fprintf(stderr, "strace: lost proc\n");				exit(1);			}			droptcb(tcp);			return -1;		}		if (pollv[j].revents & POLLWANT) {			last = j;			return pollv[j].fd;		}	}	fprintf(stderr, "strace: nothing ready\n");	exit(1);}static inttrace(){#ifdef POLL_HACK	struct tcb *in_syscall;#endif	struct tcb *tcp;	int pfd;	int what;	int ioctl_result = 0, ioctl_errno = 0;	long arg;	for (;;) {		if (interactive)			sigprocmask(SIG_SETMASK, &empty_set, NULL);		if (nprocs == 0)			break;		switch (nprocs) {		case 1:#ifndef HAVE_POLLABLE_PROCFS			if (proc_poll_pipe[0] == -1) {#endif				tcp = pid2tcb(0);				if (!tcp)					continue;				pfd = tcp->pfd;				if (pfd == -1)					continue;				break;#ifndef HAVE_POLLABLE_PROCFS			}			/* fall through ... */#endif /* !HAVE_POLLABLE_PROCFS */		default:#ifdef HAVE_POLLABLE_PROCFS#ifdef POLL_HACK		        /* On some systems (e.g. UnixWare) we get too much ugly			   "unfinished..." stuff when multiple proceses are in			   syscalls.  Here's a nasty hack */		    			if (in_syscall) {				struct pollfd pv;				tcp = in_syscall;				in_syscall = NULL;				pv.fd = tcp->pfd;				pv.events = POLLWANT;				if ((what = poll (&pv, 1, 1)) < 0) {					if (interrupted)						return 0;					continue;				}				else if (what == 1 && pv.revents & POLLWANT) {					goto FOUND;				}			}#endif			if (poll(pollv, nprocs, INFTIM) < 0) {				if (interrupted)					return 0;				continue;			}#else /* !HAVE_POLLABLE_PROCFS */			if (proc_poll(pollv, nprocs, INFTIM) < 0) {				if (interrupted)					return 0;				continue;			}#endif /* !HAVE_POLLABLE_PROCFS */			pfd = choose_pfd();			if (pfd == -1)				continue;			break;		}		/* Look up `pfd' in our table. */		if ((tcp = pfd2tcb(pfd)) == NULL) {			fprintf(stderr, "unknown pfd: %u\n", pfd);			exit(1);		}	FOUND:		/* Get the status of the process. */		if (!interrupted) {#ifndef FREEBSD			ioctl_result = IOCTL_WSTOP (tcp);#else /* FREEBSD */			/* Thanks to some scheduling mystery, the first poller			   sometimes waits for the already processed end of fork			   event. Doing a non blocking poll here solves the problem. */			if (proc_poll_pipe[0] != -1)				ioctl_result = IOCTL_STATUS (tcp);			else			  	ioctl_result = IOCTL_WSTOP (tcp);#endif /* FREEBSD */			  			ioctl_errno = errno;#ifndef HAVE_POLLABLE_PROCFS			if (proc_poll_pipe[0] != -1) {				if (ioctl_result < 0)					kill(poller_pid, SIGKILL);				else					kill(poller_pid, SIGUSR1);			}#endif /* !HAVE_POLLABLE_PROCFS */		}		if (interrupted)			return 0;		if (interactive)			sigprocmask(SIG_BLOCK, &blocked_set, NULL);		if (ioctl_result < 0) {			/* Find out what happened if it failed. */			switch (ioctl_errno) {			case EINTR:			case EBADF:				continue;#ifdef FREEBSD			case ENOTTY:#endif			  			case ENOENT:				droptcb(tcp);				continue;			default:				perror("PIOCWSTOP");				exit(1);			}		}#ifdef FREEBSD		if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {			/* discard first event for a syscall we never entered */			IOCTL (tcp->pfd, PIOCRUN, 0);			continue;		}#endif						/* clear the just started flag */		tcp->flags &= ~TCB_STARTUP;		/* set current output file */		outf = tcp->outf;		if (cflag) {			struct timeval stime;#ifdef FREEBSD			char buf[1024];			int len;			if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {				buf[len] = '\0';				sscanf(buf,				       "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",				       &stime.tv_sec, &stime.tv_usec);			} else				stime.tv_sec = stime.tv_usec = 0;#else /* !FREEBSD */						stime.tv_sec = tcp->status.pr_stime.tv_sec;			stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;#endif /* !FREEBSD */			tv_sub(&tcp->dtime, &stime, &tcp->stime);			tcp->stime = stime;		}		what = tcp->status.PR_WHAT;		switch (tcp->status.PR_WHY) {#ifndef FREEBSD		case PR_REQUESTED:			if (tcp->status.PR_FLAGS & PR_ASLEEP) {				tcp->status.PR_WHY = PR_SYSENTRY;				if (trace_syscall(tcp) < 0) {					fprintf(stderr, "syscall trouble\n");					exit(1);				}			}			break;#endif /* !FREEBSD */		case PR_SYSENTRY:#ifdef POLL_HACK		        in_syscall = tcp;#endif		case PR_SYSEXIT:			if (trace_syscall(tcp) < 0) {				fprintf(stderr, "syscall trouble\n");				exit(1);			}			break;		case PR_SIGNALLED:			if (!cflag && (qual_flags[what] & QUAL_SIGNAL)) {				printleader(tcp);				tprintf("--- %s (%s) ---",					signame(what), strsignal(what));				printtrailer(tcp);			}			break;		case PR_FAULTED:			if (!cflag && (qual_flags[what] & QUAL_FAULT)) {				printleader(tcp);				tprintf("=== FAULT %d ===", what);				printtrailer(tcp);			}			break;#ifdef FREEBSD		case 0: /* handle case we polled for nothing */		  	continue;#endif					default:			fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);			exit(1);			break;		}		arg = 0;#ifndef FREEBSD				if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {#else		  		if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0) {#endif		  			perror("PIOCRUN");			exit(1);		}	}	return 0;}#else /* !USE_PROCFS */static inttrace(){	int pid;	int wait_errno;	int status;	struct tcb *tcp;#ifdef LINUX	struct rusage ru;#ifdef __WALL	static int wait4_options = __WALL;#endif#endif /* LINUX */	while (nprocs != 0) {		if (interactive)			sigprocmask(SIG_SETMASK, &empty_set, NULL);#ifdef LINUX#ifdef __WALL		pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);		if ((wait4_options & __WALL) && errno == EINVAL) {			/* this kernel does not support __WALL */			wait4_options &= ~__WALL;			errno = 0;			pid = wait4(-1, &status, wait4_options,					cflag ? &ru : NULL);		}		if (!(wait4_options & __WALL) && errno == ECHILD) {			/* most likely a "cloned" process */			pid = wait4(-1, &status, __WCLONE,					cflag ? &ru : NULL);			if (pid == -1) {				fprintf(stderr, "strace: clone wait4 "						"failed: %s\n", strerror(errno));			}		}#else		pid = wait4(-1, &status, 0, cflag ? &ru : NULL);#endif /* __WALL */#endif /* LINUX */#ifdef SUNOS4		pid = wait(&status);#endif /* SUNOS4 */		wait_errno = errno;		if (interactive)			sigprocmask(SIG_BLOCK, &blocked_set, NULL);		if (interrupted)			return 0;		if (pid == -1) {			switch (wait_errno) {			case EINTR:				continue;			case ECHILD:				/*				 * We would like to verify this case				 * but sometimes a race in Solbourne's				 * version of SunOS sometimes reports				 * ECHILD before sending us SIGCHILD.				 */#if 0				if (nprocs == 0)					return 0;				fprintf(stderr, "strace: proc miscount\n");				exit(1);#endif				return 0;			default:				errno = wait_errno;				perror("strace: wait");				return -1;			}		}		if (debug)			fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);		/* Look up `pid' in our table. */		if ((tcp = pid2tcb(pid)) == NULL) {#if 0 /* XXX davidm */ /* WTA: disabled again */			struct tcb *tcpchild;			if ((tcpchild = alloctcb(pid)) == NULL) {				fprintf(stderr, " [tcb table full]\n");				kill(pid, SIGKILL); /* XXX */				return 0;			}			tcpchild->flags |= TCB_ATTACHED;			newoutf(tcpchild);			tcp->nchildren++;			if (!qflag)				fprintf(stderr, "Process %d attached\n", pid);#else			fprintf(stderr, "unknown pid: %u\n", pid);			if (WIFSTOPPED(status))				ptrace(PTRACE_CONT, pid, (char *) 1, 0);			exit(1);#endif		}		/* set current output file */		outf = tcp->outf;		if (cflag) {#ifdef LINUX			tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);			tcp->stime = ru.ru_stime;#endif /* !LINUX */		}		if (tcp->flags & TCB_SUSPENDED) {			/*			 * Apparently, doing any ptrace() call on a stopped			 * process, provokes the kernel to report the process			 * status again on a subsequent wait(), even if the			 * process has not been actually restarted.			 * Since we have inspected the arguments of suspended			 * processes we end up here testing for this case.			 */			continue;		}		if (WIFSIGNALED(status)) {			if (!cflag			    && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {				printleader(tcp);				tprintf("+++ killed by %s +++",					signame(WTERMSIG(status)));				printtrailer(tcp);			}			droptcb(tcp);			continue;		}		if (WIFEXITED(status)) {			if (debug)				fprintf(stderr, "pid %u exited\n", pid);			if (tcp->flags & TCB_ATTACHED)				fprintf(stderr,					"PANIC: attached pid %u exited\n",					pid);			droptcb(tcp);			continue;		}		if (!WIFSTOPPED(status)) {			fprintf(stderr, "PANIC: pid %u not stopped\n", pid);			droptcb(tcp);			continue;		}		if (debug)			fprintf(stderr, "pid %u stopped, [%s]\n",				pid, signame(WSTOPSIG(status)));		if (tcp->flags & TCB_STARTUP) {			/*			 * This flag is there to keep us in sync.			 * Next time this process stops it should			 * really be entering a system call.			 */			tcp->flags &= ~TCB_STARTUP;			if (tcp->flags & TCB_ATTACHED) {				/*				 * Interestingly, the process may stop				 * with STOPSIG equal to some other signal				 * than SIGSTOP if we happend to attach				 * just before the process takes a signal.				 */				if (!WIFSTOPPED(status)) {					fprintf(stderr,						"pid %u not stopped\n", pid);					detach(tcp, WSTOPSIG(status));					continue;				}			}			else {#ifdef SUNOS4				/* A child of us stopped at exec */				if (WSTOPSIG(status) == SIGTRAP && followvfork)					fixvfork(tcp);#endif /* SUNOS4 */			}			if (tcp->flags & TCB_BPTSET) {				if (clearbpt(tcp) < 0) /* Pretty fatal */ {					droptcb(tcp);					cleanup();					return -1;				}			}			goto tracing;		}		if (WSTOPSIG(status) != SIGTRAP) {			if (WSTOPSIG(status) == SIGSTOP &&					(tcp->flags & TCB_SIGTRAPPED)) {				/*				 * Trapped attempt to block SIGTRAP				 * Hope we are back in control now.				 */				tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);				if (ptrace(PTRACE_SYSCALL,						pid, (char *) 1, 0) < 0) {					perror("trace: ptrace(PTRACE_SYSCALL, ...)");					cleanup();					return -1;				}				continue;			}			if (!cflag			    && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {				printleader(tcp);				tprintf("--- %s (%s) ---",					signame(WSTOPSIG(status)),					strsignal(WSTOPSIG(status)));				printtrailer(tcp);			}			if ((tcp->flags & TCB_ATTACHED) &&				!sigishandled(tcp, WSTOPSIG(status))) {				detach(tcp, WSTOPSIG(status));				continue;			}			if (ptrace(PTRACE_SYSCALL, pid, (char *) 1,				   WSTOPSIG(status)) < 0) {				perror("trace: ptrace(PTRACE_SYSCALL, ...)");				cleanup();				return -1;			}			tcp->flags &= ~TCB_SUSPENDED;			continue;		}		if (trace_syscall(tcp) < 0) {			if (tcp->flags & TCB_ATTACHED)				detach(tcp, 0);			else {				ptrace(PTRACE_KILL,					tcp->pid, (char *) 1, SIGTERM);				droptcb(tcp);			}			continue;		}		if (tcp->flags & TCB_EXITING) {			if (tcp->flags & TCB_ATTACHED)				detach(tcp, 0);			else if (ptrace(PTRACE_CONT, pid, (char *) 1, 0) < 0) {				perror("strace: ptrace(PTRACE_CONT, ...)");				cleanup();				return -1;			}			continue;		}		if (tcp->flags & TCB_SUSPENDED) {			if (!qflag)				fprintf(stderr, "Process %u suspended\n", pid);			continue;		}	tracing:		if (ptrace(PTRACE_SYSCALL, pid, (char *) 1, 0) < 0) {			perror("trace: ptrace(PTRACE_SYSCALL, ...)");			cleanup();			return -1;		}	}	return 0;}#endif /* !USE_PROCFS */static int curcol;#ifdef __STDC__#include <stdarg.h>#define VA_START(a, b) va_start(a, b)#else#include <varargs.h>#define VA_START(a, b) va_start(a)#endifvoid#ifdef __STDC__tprintf(const char *fmt, ...)#elsetprintf(fmt, va_alist)char *fmt;va_dcl#endif{	va_list args;	VA_START(args, fmt);	if (outf)		curcol += vfprintf(outf, fmt, args);	va_end(args);	return;}voidprintleader(tcp)struct tcb *tcp;{	if (tcp_last && (!outfname || followfork < 2 || tcp_last == tcp)) {		tcp_last->flags |= TCB_REPRINT;		tprintf(" <unfinished ...>\n");	}	curcol = 0;	if ((followfork == 1 || pflag_seen > 1) && outfname)		tprintf("%-5d ", tcp->pid);	else if (nprocs > 1 && !outfname)		tprintf("[pid %5u] ", tcp->pid);	if (tflag) {		char str[sizeof("HH:MM:SS")];		struct timeval tv, dtv;		static struct timeval otv;		gettimeofday(&tv, NULL);		if (rflag) {			if (otv.tv_sec == 0)				otv = tv;			tv_sub(&dtv, &tv, &otv);			tprintf("%6ld.%06ld ",				(long) dtv.tv_sec, (long) dtv.tv_usec);			otv = tv;		}		else if (tflag > 2) {			tprintf("%ld.%06ld ",				(long) tv.tv_sec, (long) tv.tv_usec);		}		else {			time_t local = tv.tv_sec;			strftime(str, sizeof(str), "%T", localtime(&local));			if (tflag > 1)				tprintf("%s.%06ld ", str, (long) tv.tv_usec);			else				tprintf("%s ", str);		}	}	if (iflag)		printcall(tcp);}voidtabto(col)int col;{	if (curcol < col)		tprintf("%*s", col - curcol, "");}voidprinttrailer(tcp)struct tcb *tcp;{	tprintf("\n");	tcp_last = NULL;}#ifdef HAVE_MP_PROCFSint mp_ioctl (int fd, int cmd, void *arg, int size) {	struct iovec iov[2];	int n = 1;		iov[0].iov_base = &cmd;	iov[0].iov_len = sizeof cmd;	if (arg) {		++n;		iov[1].iov_base = arg;		iov[1].iov_len = size;	}		return writev (fd, iov, n);}#endif

⌨️ 快捷键说明

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