• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #define KCOV_INIT_TRACE _IOR('c', 1, unsigned long)
22 #define KCOV_ENABLE _IO('c', 100)
23 #define KCOV_DISABLE _IO('c', 101)
24 #define COVER_SIZE (16 << 20)
25 
main(int argc,char ** argv,char ** envp)26 int main(int argc, char** argv, char** envp)
27 {
28 	int fd, pid, status;
29 	unsigned long *cover, n, i;
30 
31 	if (argc == 1)
32 		fprintf(stderr, "usage: kcovtrace program [args...]\n"), exit(1);
33 	fd = open("/sys/kernel/debug/kcov", O_RDWR);
34 	if (fd == -1)
35 		perror("open"), exit(1);
36 	if (ioctl(fd, KCOV_INIT_TRACE, COVER_SIZE))
37 		perror("ioctl"), exit(1);
38 	cover = (unsigned long*)mmap(NULL, COVER_SIZE * sizeof(unsigned long),
39 				     PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
40 	if ((void*)cover == MAP_FAILED)
41 		perror("mmap"), exit(1);
42 	pid = fork();
43 	if (pid < 0)
44 		perror("fork"), exit(1);
45 	if (pid == 0) {
46 		if (ioctl(fd, KCOV_ENABLE, 0))
47 			perror("ioctl"), exit(1);
48 		__atomic_store_n(&cover[0], 0, __ATOMIC_RELAXED);
49 		execve(argv[1], argv + 1, envp);
50 		perror("execve");
51 		exit(1);
52 	}
53 	while (waitpid(-1, &status, __WALL) != pid) {
54 	}
55 	n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED);
56 	for (i = 0; i < n; i++)
57 		printf("0x%lx\n", cover[i + 1]);
58 	if (munmap(cover, COVER_SIZE * sizeof(unsigned long)))
59 		perror("munmap"), exit(1);
60 	if (close(fd))
61 		perror("close"), exit(1);
62 	return 0;
63 }
64