diff options
Diffstat (limited to 'tools/kcovtrace')
| -rw-r--r-- | tools/kcovtrace/kcovtrace.c | 62 |
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; +} |
