A small utility for extracting kernel coverage using
/sys/kernel/debug/kcov.

Signed-off-by: Chris Wilson <[email protected]>
---
 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 --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 */
-- 
2.8.1

_______________________________________________
Intel-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to