A small utility for extracting kernel coverage using /sys/kernel/debug/kcov. Signed-off-by: Chris Wilson <chris@xxxxxxxxxxxxxxxxxx> --- 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 Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx