aboutsummaryrefslogtreecommitdiffstats
path: root/tools/kcovtrace
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2017-01-20 11:55:19 +0100
committerDmitry Vyukov <dvyukov@google.com>2017-01-20 14:56:20 +0100
commit3db67897de73dd9dcccddc9084bd5e18e1e7dde2 (patch)
treea440f52f7ccc5c1a1e299bfb406bbed340d73398 /tools/kcovtrace
parentf8b6a5831cda2f5dac81e7a3fdfcff27733adb4f (diff)
tools/kcovtrace: add KCOV-based tracing utility
kcovtrace is like strace but show kernel coverage collected with KCOV. It is very simplistic at this point and does not support multithreaded processes, etc. It can be used to understand, for example, exact location where kernel bails out with an error for a particular syscall.
Diffstat (limited to 'tools/kcovtrace')
-rw-r--r--tools/kcovtrace/kcovtrace.c62
1 files changed, 62 insertions, 0 deletions
diff --git a/tools/kcovtrace/kcovtrace.c b/tools/kcovtrace/kcovtrace.c
new file mode 100644
index 000000000..2d6188c2c
--- /dev/null
+++ b/tools/kcovtrace/kcovtrace.c
@@ -0,0 +1,62 @@
+// Copyright 2017 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+// kcovtrace is like strace but show kernel coverage collected with KCOV.
+// It is very simplistic at this point and does not support multithreaded processes, etc.
+// It can be used to understand, for example, exact location where kernel bails out
+// with an error for a particular syscall.
+
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define KCOV_INIT_TRACE _IOR('c', 1, unsigned long)
+#define KCOV_ENABLE _IO('c', 100)
+#define KCOV_DISABLE _IO('c', 101)
+#define COVER_SIZE (16 << 20)
+
+int main(int argc, char** argv, char** envp)
+{
+ int fd, pid, status;
+ unsigned long *cover, n, i;
+
+ if (argc == 1)
+ fprintf(stderr, "usage: kcovtrace program [args...]\n"), exit(1);
+ fd = open("/sys/kernel/debug/kcov", O_RDWR);
+ if (fd == -1)
+ perror("open"), exit(1);
+ if (ioctl(fd, KCOV_INIT_TRACE, COVER_SIZE))
+ perror("ioctl"), exit(1);
+ cover = (unsigned long*)mmap(NULL, COVER_SIZE * sizeof(unsigned long),
+ PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if ((void*)cover == MAP_FAILED)
+ perror("mmap"), exit(1);
+ pid = fork();
+ if (pid < 0)
+ perror("fork"), exit(1);
+ if (pid == 0) {
+ if (ioctl(fd, KCOV_ENABLE, 0))
+ perror("ioctl"), exit(1);
+ __atomic_store_n(&cover[0], 0, __ATOMIC_RELAXED);
+ execve(argv[1], argv + 1, envp);
+ perror("execve");
+ exit(1);
+ }
+ while (waitpid(-1, &status, __WALL) != pid) {
+ }
+ n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED);
+ for (i = 0; i < n; i++)
+ printf("0x%lx\n", cover[i + 1]);
+ if (munmap(cover, COVER_SIZE * sizeof(unsigned long)))
+ perror("munmap"), exit(1);
+ if (close(fd))
+ perror("close"), exit(1);
+ return 0;
+}