diff mbox

[i-g-t,RFC,1/3] lib: Wrap kcov

Message ID 1465375925-8244-1-git-send-email-chris@chris-wilson.co.uk (mailing list archive)
State New, archived
Headers show

Commit Message

Chris Wilson June 8, 2016, 8:52 a.m. UTC
A small utility for extracting kernel coverage using
/sys/kernel/debug/kcov.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 lib/Makefile.sources |   2 +
 lib/igt_debugfs.c    |  20 ++++++
 lib/igt_debugfs.h    |   1 +
 lib/igt_kcov.c       | 188 +++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/igt_kcov.h       |  16 +++++
 5 files changed, 227 insertions(+)
 create mode 100644 lib/igt_kcov.c
 create mode 100644 lib/igt_kcov.h
diff mbox

Patch

diff --git a/lib/Makefile.sources b/lib/Makefile.sources
index f50ff4d..87bee2b 100644
--- a/lib/Makefile.sources
+++ b/lib/Makefile.sources
@@ -14,6 +14,8 @@  libintel_tools_la_SOURCES = 	\
 	igt_edid_template.h	\
 	igt_gt.c		\
 	igt_gt.h		\
+	igt_kcov.c		\
+	igt_kcov.h		\
 	igt_stats.c		\
 	igt_stats.h		\
 	igt_sysfs.c		\
diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c
index 5b6ac78..66d2392 100644
--- a/lib/igt_debugfs.c
+++ b/lib/igt_debugfs.c
@@ -138,6 +138,26 @@  static igt_debugfs_t *__igt_debugfs_singleton(void)
 }
 
 /**
+ * igt_debugfs_mount:
+ *
+ * This functions detects the mount point for debugfs, or mounts it if
+ * required, then reports the path to the root of debugfs.
+ *
+ * Returns:
+ * The path to find debufs, or NULL on failure.
+ */
+const char *igt_debugfs_mount(void)
+{
+	igt_debugfs_t *debugfs;
+
+	debugfs = __igt_debugfs_singleton();
+	if (!debugfs)
+		return NULL;
+
+	return debugfs->root;
+}
+
+/**
  * igt_debugfs_open:
  * @filename: name of the debugfs node to open
  * @mode: mode bits as used by open()
diff --git a/lib/igt_debugfs.h b/lib/igt_debugfs.h
index 261e31b..cf9d74c 100644
--- a/lib/igt_debugfs.h
+++ b/lib/igt_debugfs.h
@@ -31,6 +31,7 @@ 
 
 enum pipe;
 
+const char *igt_debugfs_mount(void);
 int igt_debugfs_open(const char *filename, int mode);
 FILE *igt_debugfs_fopen(const char *filename,
 			const char *mode);
diff --git a/lib/igt_kcov.c b/lib/igt_kcov.c
new file mode 100644
index 0000000..dd16c2e
--- /dev/null
+++ b/lib/igt_kcov.c
@@ -0,0 +1,188 @@ 
+/*
+ * Copyright © 20136Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "igt_kcov.h"
+#include "igt_debugfs.h"
+
+/**
+ * SECTION:igt_kcov
+ * @short_description: Support for kernel basic block coverage
+ * @title: kcov
+ * @include: igt.h
+ *
+ * This facility provides routines to access the reporting of basic block
+ * coverage by the kernel. By enabling kcov around syscalls, we can determine
+ * the path through the kernel that the syscall took. We can use this
+ * information to refine the test or confirm we have sufficient path coverages
+ * in our tests.
+ *
+ * After calling igt_kcov_init() to setup the tracing buffer, use
+ * igt_kcov_enable() and igt_kcov_disable() to enable basic block tracing
+ * around the syscall of interest. The buffer should be constructed per thread,
+ * and allows for thread local basic block tracing.
+ *
+ * This facility is only currently available on recent kernels and x86_64.
+ * The kernel itself must be compiled with gcc-6 and with CONFIG_KCOV.
+ */
+
+#define KCOV_INIT_TRACE	_IOR('c', 1, unsigned long)
+#define KCOV_ENABLE	_IO('c', 100)
+#define KCOV_DISABLE	_IO('c', 101)
+#define COVER_SIZE	(64<<10)
+
+/**
+ * igt_kcov_init:
+ * @kcov: the coverage struct
+ *
+ * Setup the tracking buffer.
+ *
+ * Returns:
+ * 0 on success, or a negative error code.
+ */
+int igt_kcov_init(struct igt_kcov *kcov)
+{
+	struct igt_kcov tmp;
+	const char *path;
+	char buf[128];
+	int ret;
+
+	memset(kcov, 0, sizeof(*kcov));
+
+	path = igt_debugfs_mount();
+	if (!path)
+		return -ENOENT;
+
+	snprintf(buf, sizeof(buf), "%s/kcov", path);
+	tmp.fd = open(buf, O_RDWR);
+	if (tmp.fd < 0)
+		return -ENOENT;
+
+	if (ioctl(tmp.fd, KCOV_INIT_TRACE, COVER_SIZE)) {
+		ret = -errno;
+		goto err_fd;
+	}
+
+	tmp.bb = mmap(NULL, COVER_SIZE * sizeof(unsigned long),
+		      PROT_READ | PROT_WRITE, MAP_SHARED, tmp.fd, 0);
+	if (tmp.bb == MAP_FAILED) {
+		ret = -errno;
+		goto err_fd;
+	}
+
+	*kcov = tmp;
+	return 0;
+
+err_fd:
+	close(tmp.fd);
+	return ret;
+}
+
+/**
+ * igt_kcov_enable:
+ * @kcov: the coverage struct
+ *
+ * Enable basic block tracing.
+ *
+ * Returns:
+ * 0 on success, or a negative error code.
+ */
+int igt_kcov_enable(struct igt_kcov *kcov)
+{
+	if (!kcov->bb)
+		return 0;
+
+	if (ioctl(kcov->fd, KCOV_ENABLE, 0))
+		return -errno;
+
+	return 0;
+}
+
+/**
+ * igt_kcov_reset:
+ * @kcov: the coverage struct
+ *
+ * Reset the position in the coverage buffer to 0. All subsequent
+ * tracing will then overwrite previous entrie.s
+ */
+void igt_kcov_reset(struct igt_kcov *kcov)
+{
+	if (!kcov->bb)
+		return;
+
+	__atomic_store_n(&kcov->bb[0], 0, __ATOMIC_RELAXED);
+}
+
+/**
+ * igt_kcov_disable:
+ * @kcov: the coverage struct
+ *
+ * Disable basic block tracing.
+ */
+void igt_kcov_disable(struct igt_kcov *kcov)
+{
+	if (!kcov->bb)
+		return;
+
+	ioctl(kcov->fd, KCOV_DISABLE, 0);
+}
+
+void igt_kcov_print(struct igt_kcov *kcov)
+{
+	unsigned long n, i;
+
+	if (!kcov->bb)
+		return;
+
+	n = __atomic_load_n(&kcov->bb[0], __ATOMIC_RELAXED);
+	for (i = 0; i < n; i++)
+		printf("0x%lx\n", kcov->bb[i + 1]);
+}
+
+/**
+ * igt_kcov_fini:
+ * @kcov: the coverage struct
+ *
+ * Release all resources associated with the coverage struct.
+ */
+void igt_kcov_fini(struct igt_kcov *kcov)
+{
+	if (!kcov->bb)
+		return;
+
+	munmap(kcov->bb, COVER_SIZE*sizeof(unsigned long));
+	close(kcov->fd);
+}
diff --git a/lib/igt_kcov.h b/lib/igt_kcov.h
new file mode 100644
index 0000000..dbd3d1e
--- /dev/null
+++ b/lib/igt_kcov.h
@@ -0,0 +1,16 @@ 
+#ifndef IGT_KCOV_H
+#define IGT_KCOV_H
+
+struct igt_kcov {
+	int fd;
+	unsigned long *bb;
+};
+
+int igt_kcov_init(struct igt_kcov *kcov);
+int igt_kcov_enable(struct igt_kcov *kcov);
+void igt_kcov_reset(struct igt_kcov *kcov);
+void igt_kcov_disable(struct igt_kcov *kcov);
+void igt_kcov_print(struct igt_kcov *kcov);
+void igt_kcov_fini(struct igt_kcov *kcov);
+
+#endif /* IGT_KCOV_H */