Blame view

Documentation/kcov.txt 3.42 KB
5c9a8750a   Dmitry Vyukov   kernel: add kcov ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
  kcov: code coverage for fuzzing
  ===============================
  
  kcov exposes kernel code coverage information in a form suitable for coverage-
  guided fuzzing (randomized testing). Coverage data of a running kernel is
  exported via the "kcov" debugfs file. Coverage collection is enabled on a task
  basis, and thus it can capture precise coverage of a single system call.
  
  Note that kcov does not aim to collect as much coverage as possible. It aims
  to collect more or less stable coverage that is function of syscall inputs.
  To achieve this goal it does not collect coverage in soft/hard interrupts
  and instrumentation of some inherently non-deterministic parts of kernel is
  disbled (e.g. scheduler, locking).
  
  Usage:
  ======
  
  Configure kernel with:
  
          CONFIG_KCOV=y
  
  CONFIG_KCOV requires gcc built on revision 231296 or later.
  Profiling data will only become accessible once debugfs has been mounted:
  
          mount -t debugfs none /sys/kernel/debug
  
  The following program demonstrates kcov usage from within a test program:
  
  #include <stdio.h>
  #include <stddef.h>
  #include <stdint.h>
  #include <stdlib.h>
  #include <sys/types.h>
  #include <sys/stat.h>
  #include <sys/ioctl.h>
  #include <sys/mman.h>
  #include <unistd.h>
  #include <fcntl.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			(64<<10)
  
  int main(int argc, char **argv)
  {
  	int fd;
  	unsigned long *cover, n, i;
  
  	/* A single fd descriptor allows coverage collection on a single
  	 * thread.
  	 */
  	fd = open("/sys/kernel/debug/kcov", O_RDWR);
  	if (fd == -1)
  		perror("open"), exit(1);
  	/* Setup trace mode and trace size. */
  	if (ioctl(fd, KCOV_INIT_TRACE, COVER_SIZE))
  		perror("ioctl"), exit(1);
  	/* Mmap buffer shared between kernel- and user-space. */
  	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);
  	/* Enable coverage collection on the current thread. */
  	if (ioctl(fd, KCOV_ENABLE, 0))
  		perror("ioctl"), exit(1);
  	/* Reset coverage from the tail of the ioctl() call. */
  	__atomic_store_n(&cover[0], 0, __ATOMIC_RELAXED);
  	/* That's the target syscal call. */
  	read(-1, NULL, 0);
  	/* Read number of PCs collected. */
  	n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED);
  	for (i = 0; i < n; i++)
  		printf("0x%lx
  ", cover[i + 1]);
  	/* Disable coverage collection for the current thread. After this call
  	 * coverage can be enabled for a different thread.
  	 */
  	if (ioctl(fd, KCOV_DISABLE, 0))
  		perror("ioctl"), exit(1);
  	/* Free resources. */
  	if (munmap(cover, COVER_SIZE * sizeof(unsigned long)))
  		perror("munmap"), exit(1);
  	if (close(fd))
  		perror("close"), exit(1);
  	return 0;
  }
  
  After piping through addr2line output of the program looks as follows:
  
  SyS_read
  fs/read_write.c:562
  __fdget_pos
  fs/file.c:774
  __fget_light
  fs/file.c:746
  __fget_light
  fs/file.c:750
  __fget_light
  fs/file.c:760
  __fdget_pos
  fs/file.c:784
  SyS_read
  fs/read_write.c:562
  
  If a program needs to collect coverage from several threads (independently),
  it needs to open /sys/kernel/debug/kcov in each thread separately.
  
  The interface is fine-grained to allow efficient forking of test processes.
  That is, a parent process opens /sys/kernel/debug/kcov, enables trace mode,
  mmaps coverage buffer and then forks child processes in a loop. Child processes
  only need to enable coverage (disable happens automatically on thread end).