github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/tools/kcovtrace/kcovtrace.c (about) 1 // Copyright 2017 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 // kcovtrace is like strace but show kernel coverage collected with KCOV. 5 // It is very simplistic at this point and does not support multithreaded processes, etc. 6 // It can be used to understand, for example, exact location where kernel bails out 7 // with an error for a particular syscall. 8 9 #include <fcntl.h> 10 #include <stddef.h> 11 #include <stdint.h> 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <sys/ioctl.h> 15 #include <sys/mman.h> 16 #include <sys/stat.h> 17 #include <sys/types.h> 18 #include <sys/wait.h> 19 #include <unistd.h> 20 21 #if defined(__FreeBSD__) || defined(__NetBSD__) 22 #include <sys/kcov.h> 23 #define KCOV_PATH "/dev/kcov" 24 typedef uint64_t cover_t; 25 #else 26 #define KCOV_INIT_TRACE _IOR('c', 1, unsigned long) 27 #define KCOV_ENABLE _IO('c', 100) 28 #define KCOV_DISABLE _IO('c', 101) 29 #define KCOV_ENTRY_SIZE sizeof(unsigned long) 30 #define KCOV_PATH "/sys/kernel/debug/kcov" 31 #define KCOV_TRACE_PC 0 32 typedef unsigned long cover_t; 33 #endif 34 #define COVER_SIZE (16 << 20) 35 36 int main(int argc, char** argv, char** envp) 37 { 38 int fd, pid, status; 39 cover_t *cover, n, i; 40 41 if (argc == 1) 42 fprintf(stderr, "usage: kcovtrace program [args...]\n"), exit(1); 43 fd = open(KCOV_PATH, O_RDWR); 44 if (fd == -1) 45 perror("open"), exit(1); 46 #if defined(__FreeBSD__) 47 if (ioctl(fd, KIOSETBUFSIZE, COVER_SIZE)) 48 #elif defined(__NetBSD__) 49 uint64_t cover_size = COVER_SIZE; 50 if (ioctl(fd, KCOV_IOC_SETBUFSIZE, &cover_size)) 51 #else 52 if (ioctl(fd, KCOV_INIT_TRACE, COVER_SIZE)) 53 #endif 54 perror("ioctl"), exit(1); 55 cover = (cover_t*)mmap(NULL, COVER_SIZE * KCOV_ENTRY_SIZE, 56 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 57 if ((void*)cover == MAP_FAILED) 58 perror("mmap"), exit(1); 59 pid = fork(); 60 if (pid < 0) 61 perror("fork"), exit(1); 62 if (pid == 0) { 63 #if defined(__FreeBSD__) 64 if (ioctl(fd, KIOENABLE, KCOV_MODE_TRACE_PC)) 65 #elif defined(__NetBSD__) 66 int kcov_mode = KCOV_MODE_TRACE_PC; 67 if (ioctl(cov->fd, KCOV_IOC_ENABLE, &kcov_mode)) 68 #else 69 if (ioctl(fd, KCOV_ENABLE, KCOV_TRACE_PC)) 70 #endif 71 perror("ioctl"), exit(1); 72 __atomic_store_n(&cover[0], 0, __ATOMIC_RELAXED); 73 execve(argv[1], argv + 1, envp); 74 perror("execve"); 75 exit(1); 76 } 77 #if defined(__FreeBSD__) 78 while (waitpid(-1, &status, 0) != pid) { 79 #else 80 while (waitpid(-1, &status, __WALL) != pid) { 81 #endif 82 } 83 n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED); 84 for (i = 0; i < n; i++) 85 printf("0x%jx\n", (uintmax_t)cover[i + 1]); 86 if (munmap(cover, COVER_SIZE * KCOV_ENTRY_SIZE)) 87 perror("munmap"), exit(1); 88 if (close(fd)) 89 perror("close"), exit(1); 90 return 0; 91 }