Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 10 Feb 2012 21:33:12 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r231443 - head/tools/test/ptrace
Message-ID:  <201202102133.q1ALXCu7095963@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Fri Feb 10 21:33:12 2012
New Revision: 231443
URL: http://svn.freebsd.org/changeset/base/231443

Log:
  Add a test program for recently added ptrace(2) interfaces.
  
  MFC after:	1 week

Added:
  head/tools/test/ptrace/
  head/tools/test/ptrace/Makefile   (contents, props changed)
  head/tools/test/ptrace/scescx.c   (contents, props changed)

Added: head/tools/test/ptrace/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/test/ptrace/Makefile	Fri Feb 10 21:33:12 2012	(r231443)
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+PROG=	scescx
+NO_MAN=
+WARNS?=	6
+
+.include <bsd.prog.mk>

Added: head/tools/test/ptrace/scescx.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/test/ptrace/scescx.c	Fri Feb 10 21:33:12 2012	(r231443)
@@ -0,0 +1,406 @@
+/*-
+ * Copyright (c) 2011, 2012 Konstantin Belousov <kib@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/sysctl.h>
+#include <sys/wait.h>
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define TRACE	">>>> "
+
+static const char *
+decode_wait_status(int status)
+{
+	static char c[128];
+	char b[32];
+	int first;
+
+	c[0] = '\0';
+	first = 1;
+	if (WIFCONTINUED(status)) {
+		first = 0;
+		strlcat(c, "CONT", sizeof(c));
+	}
+	if (WIFEXITED(status)) {
+		if (first)
+			first = 0;
+		else
+			strlcat(c, ",", sizeof(c));
+		snprintf(b, sizeof(b), "EXIT(%d)", WEXITSTATUS(status));
+		strlcat(c, b, sizeof(c));
+	}
+	if (WIFSIGNALED(status)) {
+		if (first)
+			first = 0;
+		else
+			strlcat(c, ",", sizeof(c));
+		snprintf(b, sizeof(b), "SIG(%s)", strsignal(WTERMSIG(status)));
+		strlcat(c, b, sizeof(c));
+		if (WCOREDUMP(status))
+			strlcat(c, ",CORE", sizeof(c));
+	}
+	if (WIFSTOPPED(status)) {
+		if (first)
+			first = 0;
+		else
+			strlcat(c, ",", sizeof(c));
+		snprintf(b, sizeof(b), "SIG(%s)", strsignal(WSTOPSIG(status)));
+		strlcat(c, b, sizeof(c));
+	}
+	return (c);
+}
+
+static const char *
+decode_pl_flags(struct ptrace_lwpinfo *lwpinfo)
+{
+	static char c[128];
+	static struct decode_tag {
+		int flag;
+		const char *desc;
+	} decode[] = {
+		{ PL_FLAG_SA, "SA" },
+		{ PL_FLAG_BOUND, "BOUND" },
+		{ PL_FLAG_SCE, "SCE" },
+		{ PL_FLAG_SCX, "SCX" },
+		{ PL_FLAG_EXEC, "EXEC" },
+		{ PL_FLAG_SI, "SI" },
+		{ PL_FLAG_FORKED, "FORKED" },
+	};
+	char de[32];
+	unsigned first, flags, i;
+
+	c[0] = '\0';
+	first = 1;
+	flags = lwpinfo->pl_flags;
+	for (i = 0; i < sizeof(decode) / sizeof(decode[0]); i++) {
+		if ((flags & decode[i].flag) != 0) {
+			if (first)
+				first = 0;
+			else
+				strlcat(c, ",", sizeof(c));
+			strlcat(c, decode[i].desc, sizeof(c));
+			flags &= ~decode[i].flag;
+		}
+	}
+	for (i = 0; i < sizeof(flags) * NBBY; i++) {
+		if ((flags & (1 << i)) != 0) {
+			if (first)
+				first = 0;
+			else
+				strlcat(c, ",", sizeof(c));
+			snprintf(de, sizeof(de), "<%d>", i);
+			strlcat(c, de, sizeof(c));
+		}
+	}
+	return (c);
+}
+
+static const char *
+decode_pl_event(struct ptrace_lwpinfo *lwpinfo)
+{
+
+	switch (lwpinfo->pl_event) {
+	case PL_EVENT_NONE:
+		return ("NONE");
+
+	case PL_EVENT_SIGNAL:
+		return ("SIG");
+
+	default:
+		return ("UNKNOWN");
+	}
+}
+
+static void
+get_pathname(pid_t pid)
+{
+	char pathname[PATH_MAX];
+	int error, name[4];
+	size_t len;
+
+	name[0] = CTL_KERN;
+	name[1] = KERN_PROC;
+	name[2] = KERN_PROC_PATHNAME;
+	name[3] = pid;
+
+	len = sizeof(pathname);
+	error = sysctl(name, 4, pathname, &len, NULL, 0);
+	if (error < 0) {
+		if (errno != ESRCH) {
+			fprintf(stderr, "sysctl kern.proc.pathname.%d: %s\n",
+			    pid, strerror(errno));
+			return;
+		}
+		fprintf(stderr, "pid %d exited\n", pid);
+		return;
+	}
+	if (len == 0 || strlen(pathname) == 0) {
+		fprintf(stderr, "No cached pathname for process %d\n", pid);
+		return;
+	}
+	printf(TRACE "pid %d path %s\n", pid, pathname);
+}
+
+static void
+wait_info(int pid, int status, struct ptrace_lwpinfo *lwpinfo)
+{
+
+	printf(TRACE "pid %d wait %s", pid,
+	    decode_wait_status(status));
+	if (lwpinfo != NULL) {
+		printf(" event %s flags %s",
+		    decode_pl_event(lwpinfo), decode_pl_flags(lwpinfo));
+	}
+	printf("\n");
+}
+
+static int
+trace_sc(int pid)
+{
+	struct ptrace_lwpinfo lwpinfo;
+	int status;
+
+	if (ptrace(PT_TO_SCE, pid, (caddr_t)1, 0) < 0) {
+		perror("PT_TO_SCE");
+		ptrace(PT_KILL, pid, NULL, 0);
+		return (-1);
+	}
+
+	if (waitpid(pid, &status, 0) == -1) {
+		perror("waitpid");
+		return (-1);
+	}
+	if (WIFEXITED(status) || WIFSIGNALED(status)) {
+		wait_info(pid, status, NULL);
+		return (-1);
+	}
+	assert(WIFSTOPPED(status));
+	assert(WSTOPSIG(status) == SIGTRAP);
+
+	if (ptrace(PT_LWPINFO, pid, (caddr_t)&lwpinfo, sizeof(lwpinfo)) < 0) {
+		perror("PT_LWPINFO");
+		ptrace(PT_KILL, pid, NULL, 0);
+		return (-1);
+	}
+	wait_info(pid, status, &lwpinfo);
+	assert(lwpinfo.pl_flags & PL_FLAG_SCE);
+
+	if (ptrace(PT_TO_SCX, pid, (caddr_t)1, 0) < 0) {
+		perror("PT_TO_SCX");
+		ptrace(PT_KILL, pid, NULL, 0);
+		return (-1);
+	}
+
+	if (waitpid(pid, &status, 0) == -1) {
+		perror("waitpid");
+		return (-1);
+	}
+	if (WIFEXITED(status) || WIFSIGNALED(status)) {
+		wait_info(pid, status, NULL);
+		return (-1);
+	}
+	assert(WIFSTOPPED(status));
+	assert(WSTOPSIG(status) == SIGTRAP);
+
+	if (ptrace(PT_LWPINFO, pid, (caddr_t)&lwpinfo, sizeof(lwpinfo)) < 0) {
+		perror("PT_LWPINFO");
+		ptrace(PT_KILL, pid, NULL, 0);
+		return (-1);
+	}
+	wait_info(pid, status, &lwpinfo);
+	assert(lwpinfo.pl_flags & PL_FLAG_SCX);
+
+	if (lwpinfo.pl_flags & PL_FLAG_EXEC)
+		get_pathname(pid);
+
+	if (lwpinfo.pl_flags & PL_FLAG_FORKED) {
+		printf(TRACE "forked child %d\n", lwpinfo.pl_child_pid);
+		return (lwpinfo.pl_child_pid);
+	}
+	return (0);
+}
+
+static int
+trace_cont(int pid)
+{
+	struct ptrace_lwpinfo lwpinfo;
+	int status;
+
+	if (ptrace(PT_CONTINUE, pid, (caddr_t)1, 0) < 0) {
+		perror("PT_CONTINUE");
+		ptrace(PT_KILL, pid, NULL, 0);
+		return (-1);
+	}
+
+	if (waitpid(pid, &status, 0) == -1) {
+		perror("waitpid");
+		return (-1);
+	}
+	if (WIFEXITED(status) || WIFSIGNALED(status)) {
+		wait_info(pid, status, NULL);
+		return (-1);
+	}
+	assert(WIFSTOPPED(status));
+	assert(WSTOPSIG(status) == SIGTRAP);
+
+	if (ptrace(PT_LWPINFO, pid, (caddr_t)&lwpinfo, sizeof(lwpinfo)) < 0) {
+		perror("PT_LWPINFO");
+		ptrace(PT_KILL, pid, NULL, 0);
+		return (-1);
+	}
+	wait_info(pid, status, &lwpinfo);
+
+	if ((lwpinfo.pl_flags & (PL_FLAG_EXEC | PL_FLAG_SCX)) ==
+	    (PL_FLAG_EXEC | PL_FLAG_SCX))
+		get_pathname(pid);
+
+	if ((lwpinfo.pl_flags & (PL_FLAG_FORKED | PL_FLAG_SCX)) ==
+	    (PL_FLAG_FORKED | PL_FLAG_SCX)) {
+		printf(TRACE "forked child %d\n", lwpinfo.pl_child_pid);
+		return (lwpinfo.pl_child_pid);
+	}
+
+	return (0);
+}
+
+static int trace_syscalls = 1;
+
+static int
+trace(pid_t pid)
+{
+
+	return (trace_syscalls ? trace_sc(pid) : trace_cont(pid));
+}
+
+
+int
+main(int argc, char *argv[])
+{
+	struct ptrace_lwpinfo lwpinfo;
+	int c, status, use_vfork;
+	pid_t pid, pid1;
+
+	trace_syscalls = 1;
+	use_vfork = 0;
+	while ((c = getopt(argc, argv, "csv")) != -1) {
+		switch (c) {
+		case 'c':
+			trace_syscalls = 0;
+			break;
+		case 's':
+			trace_syscalls = 1;
+			break;
+		case 'v':
+			use_vfork = 1;
+			break;
+		default:
+		case '?':
+			fprintf(stderr, "Usage: %s [-c] [-s] [-v]\n", argv[0]);
+			return (2);
+		}
+	}
+
+	if ((pid = fork()) < 0) {
+		perror("fork");
+		return 1;
+	}
+	else if (pid == 0) {
+		if (ptrace(PT_TRACE_ME, 0, NULL, 0) < 0) {
+			perror("PT_TRACE_ME");
+			_exit(1);
+		}
+		kill(getpid(), SIGSTOP);
+		getpid();
+		if ((pid1 = use_vfork ? vfork() : fork()) < 0) {
+			perror("fork1");
+			return (1);
+		} else if (pid1 == 0) {
+			printf("Hi from child %d\n", getpid());
+			execl("/bin/ls", "ls", "/", (char *)NULL);
+		}
+	}
+	else { /* parent */
+		if (waitpid(pid, &status, 0) == -1) {
+			perror("waitpid");
+			return (-1);
+		}
+		assert(WIFSTOPPED(status));
+		assert(WSTOPSIG(status) == SIGSTOP);
+
+		if (ptrace(PT_LWPINFO, pid, (caddr_t)&lwpinfo,
+		    sizeof(lwpinfo)) < 0) {
+			perror("PT_LWPINFO");
+			ptrace(PT_KILL, pid, NULL, 0);
+			return (-1);
+		}
+		wait_info(pid, status, &lwpinfo);
+
+		if (ptrace(PT_FOLLOW_FORK, pid, 0, 1) < 0) {
+			perror("PT_FOLLOW_FORK");
+			ptrace(PT_KILL, pid, NULL, 0);
+			return (2);
+		}
+
+		while ((pid1 = trace(pid)) >= 0) {
+			if (pid1 != 0) {
+				printf(TRACE "attached to pid %d\n", pid1);
+#if 0
+				kill(pid1, SIGCONT);
+#endif
+				if (waitpid(pid1, &status, 0) == -1) {
+					perror("waitpid");
+					return (-1);
+				}
+				printf(TRACE "nested loop, pid %d status %s\n",
+				    pid1, decode_wait_status(status));
+				assert(WIFSTOPPED(status));
+				assert(WSTOPSIG(status) == SIGSTOP);
+				if (ptrace(PT_LWPINFO, pid1, (caddr_t)&lwpinfo,
+				    sizeof(lwpinfo)) < 0) {
+					perror("PT_LWPINFO");
+					ptrace(PT_KILL, pid1, NULL, 0);
+					return (-1);
+				}
+				wait_info(pid1, status, &lwpinfo);
+
+				while (trace(pid1) >= 0)
+					;
+			}
+		}
+
+		ptrace(PT_CONTINUE, pid, (caddr_t)1, 0);
+	}
+	return (0);
+}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201202102133.q1ALXCu7095963>