1*7b32137bSAndrey KonovalovKCOV: code coverage for fuzzing
2758f726eSJonathan Corbet===============================
3758f726eSJonathan Corbet
4*7b32137bSAndrey KonovalovKCOV collects and exposes kernel code coverage information in a form suitable
5*7b32137bSAndrey Konovalovfor coverage-guided fuzzing. Coverage data of a running kernel is exported via
6*7b32137bSAndrey Konovalovthe ``kcov`` debugfs file. Coverage collection is enabled on a task basis, and
7*7b32137bSAndrey Konovalovthus KCOV can capture precise coverage of a single system call.
8758f726eSJonathan Corbet
9*7b32137bSAndrey KonovalovNote that KCOV does not aim to collect as much coverage as possible. It aims
10*7b32137bSAndrey Konovalovto collect more or less stable coverage that is a function of syscall inputs.
11*7b32137bSAndrey KonovalovTo achieve this goal, it does not collect coverage in soft/hard interrupts
12*7b32137bSAndrey Konovalov(unless remove coverage collection is enabled, see below) and from some
13*7b32137bSAndrey Konovalovinherently non-deterministic parts of the kernel (e.g. scheduler, locking).
14758f726eSJonathan Corbet
15*7b32137bSAndrey KonovalovBesides collecting code coverage, KCOV can also collect comparison operands.
16*7b32137bSAndrey KonovalovSee the "Comparison operands collection" section for details.
17*7b32137bSAndrey Konovalov
18*7b32137bSAndrey KonovalovBesides collecting coverage data from syscall handlers, KCOV can also collect
19*7b32137bSAndrey Konovalovcoverage for annotated parts of the kernel executing in background kernel
20*7b32137bSAndrey Konovalovtasks or soft interrupts. See the "Remote coverage collection" section for
21*7b32137bSAndrey Konovalovdetails.
22c512ac01SVictor Chibotaru
23c512ac01SVictor ChibotaruPrerequisites
24c512ac01SVictor Chibotaru-------------
25758f726eSJonathan Corbet
26*7b32137bSAndrey KonovalovKCOV relies on compiler instrumentation and requires GCC 6.1.0 or later
27*7b32137bSAndrey Konovalovor any Clang version supported by the kernel.
28*7b32137bSAndrey Konovalov
29*7b32137bSAndrey KonovalovCollecting comparison operands is supported with GCC 8+ or with Clang.
30*7b32137bSAndrey Konovalov
31*7b32137bSAndrey KonovalovTo enable KCOV, configure the kernel with::
32758f726eSJonathan Corbet
33758f726eSJonathan Corbet        CONFIG_KCOV=y
34758f726eSJonathan Corbet
35*7b32137bSAndrey KonovalovTo enable comparison operands collection, set::
36c512ac01SVictor Chibotaru
37c512ac01SVictor Chibotaru	CONFIG_KCOV_ENABLE_COMPARISONS=y
38c512ac01SVictor Chibotaru
39*7b32137bSAndrey KonovalovCoverage data only becomes accessible once debugfs has been mounted::
40758f726eSJonathan Corbet
41758f726eSJonathan Corbet        mount -t debugfs none /sys/kernel/debug
42758f726eSJonathan Corbet
43c512ac01SVictor ChibotaruCoverage collection
44c512ac01SVictor Chibotaru-------------------
45eec028c9SAndrey Konovalov
46*7b32137bSAndrey KonovalovThe following program demonstrates how to use KCOV to collect coverage for a
47*7b32137bSAndrey Konovalovsingle syscall from within a test program:
4857131dd3SJani Nikula
4957131dd3SJani Nikula.. code-block:: c
50758f726eSJonathan Corbet
51758f726eSJonathan Corbet    #include <stdio.h>
52758f726eSJonathan Corbet    #include <stddef.h>
53758f726eSJonathan Corbet    #include <stdint.h>
54758f726eSJonathan Corbet    #include <stdlib.h>
55758f726eSJonathan Corbet    #include <sys/types.h>
56758f726eSJonathan Corbet    #include <sys/stat.h>
57758f726eSJonathan Corbet    #include <sys/ioctl.h>
58758f726eSJonathan Corbet    #include <sys/mman.h>
59758f726eSJonathan Corbet    #include <unistd.h>
60758f726eSJonathan Corbet    #include <fcntl.h>
61d687a9ccSSebastian Andrzej Siewior    #include <linux/types.h>
62758f726eSJonathan Corbet
63758f726eSJonathan Corbet    #define KCOV_INIT_TRACE			_IOR('c', 1, unsigned long)
64758f726eSJonathan Corbet    #define KCOV_ENABLE			_IO('c', 100)
65758f726eSJonathan Corbet    #define KCOV_DISABLE			_IO('c', 101)
66758f726eSJonathan Corbet    #define COVER_SIZE			(64<<10)
67758f726eSJonathan Corbet
68c512ac01SVictor Chibotaru    #define KCOV_TRACE_PC  0
69c512ac01SVictor Chibotaru    #define KCOV_TRACE_CMP 1
70c512ac01SVictor Chibotaru
71758f726eSJonathan Corbet    int main(int argc, char **argv)
72758f726eSJonathan Corbet    {
73758f726eSJonathan Corbet	int fd;
74758f726eSJonathan Corbet	unsigned long *cover, n, i;
75758f726eSJonathan Corbet
76758f726eSJonathan Corbet	/* A single fd descriptor allows coverage collection on a single
77758f726eSJonathan Corbet	 * thread.
78758f726eSJonathan Corbet	 */
79758f726eSJonathan Corbet	fd = open("/sys/kernel/debug/kcov", O_RDWR);
80758f726eSJonathan Corbet	if (fd == -1)
81758f726eSJonathan Corbet		perror("open"), exit(1);
82758f726eSJonathan Corbet	/* Setup trace mode and trace size. */
83758f726eSJonathan Corbet	if (ioctl(fd, KCOV_INIT_TRACE, COVER_SIZE))
84758f726eSJonathan Corbet		perror("ioctl"), exit(1);
85758f726eSJonathan Corbet	/* Mmap buffer shared between kernel- and user-space. */
86758f726eSJonathan Corbet	cover = (unsigned long*)mmap(NULL, COVER_SIZE * sizeof(unsigned long),
87758f726eSJonathan Corbet				     PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
88758f726eSJonathan Corbet	if ((void*)cover == MAP_FAILED)
89758f726eSJonathan Corbet		perror("mmap"), exit(1);
90758f726eSJonathan Corbet	/* Enable coverage collection on the current thread. */
91c512ac01SVictor Chibotaru	if (ioctl(fd, KCOV_ENABLE, KCOV_TRACE_PC))
92758f726eSJonathan Corbet		perror("ioctl"), exit(1);
93758f726eSJonathan Corbet	/* Reset coverage from the tail of the ioctl() call. */
94758f726eSJonathan Corbet	__atomic_store_n(&cover[0], 0, __ATOMIC_RELAXED);
95*7b32137bSAndrey Konovalov	/* Call the target syscall call. */
96758f726eSJonathan Corbet	read(-1, NULL, 0);
97758f726eSJonathan Corbet	/* Read number of PCs collected. */
98758f726eSJonathan Corbet	n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED);
99758f726eSJonathan Corbet	for (i = 0; i < n; i++)
100758f726eSJonathan Corbet		printf("0x%lx\n", cover[i + 1]);
101758f726eSJonathan Corbet	/* Disable coverage collection for the current thread. After this call
102758f726eSJonathan Corbet	 * coverage can be enabled for a different thread.
103758f726eSJonathan Corbet	 */
104758f726eSJonathan Corbet	if (ioctl(fd, KCOV_DISABLE, 0))
105758f726eSJonathan Corbet		perror("ioctl"), exit(1);
106758f726eSJonathan Corbet	/* Free resources. */
107758f726eSJonathan Corbet	if (munmap(cover, COVER_SIZE * sizeof(unsigned long)))
108758f726eSJonathan Corbet		perror("munmap"), exit(1);
109758f726eSJonathan Corbet	if (close(fd))
110758f726eSJonathan Corbet		perror("close"), exit(1);
111758f726eSJonathan Corbet	return 0;
112758f726eSJonathan Corbet    }
113758f726eSJonathan Corbet
114*7b32137bSAndrey KonovalovAfter piping through ``addr2line`` the output of the program looks as follows::
115758f726eSJonathan Corbet
116758f726eSJonathan Corbet    SyS_read
117758f726eSJonathan Corbet    fs/read_write.c:562
118758f726eSJonathan Corbet    __fdget_pos
119758f726eSJonathan Corbet    fs/file.c:774
120758f726eSJonathan Corbet    __fget_light
121758f726eSJonathan Corbet    fs/file.c:746
122758f726eSJonathan Corbet    __fget_light
123758f726eSJonathan Corbet    fs/file.c:750
124758f726eSJonathan Corbet    __fget_light
125758f726eSJonathan Corbet    fs/file.c:760
126758f726eSJonathan Corbet    __fdget_pos
127758f726eSJonathan Corbet    fs/file.c:784
128758f726eSJonathan Corbet    SyS_read
129758f726eSJonathan Corbet    fs/read_write.c:562
130758f726eSJonathan Corbet
131758f726eSJonathan CorbetIf a program needs to collect coverage from several threads (independently),
132*7b32137bSAndrey Konovalovit needs to open ``/sys/kernel/debug/kcov`` in each thread separately.
133758f726eSJonathan Corbet
134758f726eSJonathan CorbetThe interface is fine-grained to allow efficient forking of test processes.
135*7b32137bSAndrey KonovalovThat is, a parent process opens ``/sys/kernel/debug/kcov``, enables trace mode,
136*7b32137bSAndrey Konovalovmmaps coverage buffer, and then forks child processes in a loop. The child
137*7b32137bSAndrey Konovalovprocesses only need to enable coverage (it gets disabled automatically when
138*7b32137bSAndrey Konovalova thread exits).
139c512ac01SVictor Chibotaru
140c512ac01SVictor ChibotaruComparison operands collection
141c512ac01SVictor Chibotaru------------------------------
142eec028c9SAndrey Konovalov
143c512ac01SVictor ChibotaruComparison operands collection is similar to coverage collection:
144c512ac01SVictor Chibotaru
145c512ac01SVictor Chibotaru.. code-block:: c
146c512ac01SVictor Chibotaru
147c512ac01SVictor Chibotaru    /* Same includes and defines as above. */
148c512ac01SVictor Chibotaru
149c512ac01SVictor Chibotaru    /* Number of 64-bit words per record. */
150c512ac01SVictor Chibotaru    #define KCOV_WORDS_PER_CMP 4
151c512ac01SVictor Chibotaru
152c512ac01SVictor Chibotaru    /*
153c512ac01SVictor Chibotaru     * The format for the types of collected comparisons.
154c512ac01SVictor Chibotaru     *
155c512ac01SVictor Chibotaru     * Bit 0 shows whether one of the arguments is a compile-time constant.
156c512ac01SVictor Chibotaru     * Bits 1 & 2 contain log2 of the argument size, up to 8 bytes.
157c512ac01SVictor Chibotaru     */
158c512ac01SVictor Chibotaru
159c512ac01SVictor Chibotaru    #define KCOV_CMP_CONST          (1 << 0)
160c512ac01SVictor Chibotaru    #define KCOV_CMP_SIZE(n)        ((n) << 1)
161c512ac01SVictor Chibotaru    #define KCOV_CMP_MASK           KCOV_CMP_SIZE(3)
162c512ac01SVictor Chibotaru
163c512ac01SVictor Chibotaru    int main(int argc, char **argv)
164c512ac01SVictor Chibotaru    {
165c512ac01SVictor Chibotaru	int fd;
166c512ac01SVictor Chibotaru	uint64_t *cover, type, arg1, arg2, is_const, size;
167c512ac01SVictor Chibotaru	unsigned long n, i;
168c512ac01SVictor Chibotaru
169c512ac01SVictor Chibotaru	fd = open("/sys/kernel/debug/kcov", O_RDWR);
170c512ac01SVictor Chibotaru	if (fd == -1)
171c512ac01SVictor Chibotaru		perror("open"), exit(1);
172c512ac01SVictor Chibotaru	if (ioctl(fd, KCOV_INIT_TRACE, COVER_SIZE))
173c512ac01SVictor Chibotaru		perror("ioctl"), exit(1);
174c512ac01SVictor Chibotaru	/*
175c512ac01SVictor Chibotaru	* Note that the buffer pointer is of type uint64_t*, because all
176c512ac01SVictor Chibotaru	* the comparison operands are promoted to uint64_t.
177c512ac01SVictor Chibotaru	*/
178c512ac01SVictor Chibotaru	cover = (uint64_t *)mmap(NULL, COVER_SIZE * sizeof(unsigned long),
179c512ac01SVictor Chibotaru				     PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
180c512ac01SVictor Chibotaru	if ((void*)cover == MAP_FAILED)
181c512ac01SVictor Chibotaru		perror("mmap"), exit(1);
182c512ac01SVictor Chibotaru	/* Note KCOV_TRACE_CMP instead of KCOV_TRACE_PC. */
183c512ac01SVictor Chibotaru	if (ioctl(fd, KCOV_ENABLE, KCOV_TRACE_CMP))
184c512ac01SVictor Chibotaru		perror("ioctl"), exit(1);
185c512ac01SVictor Chibotaru	__atomic_store_n(&cover[0], 0, __ATOMIC_RELAXED);
186c512ac01SVictor Chibotaru	read(-1, NULL, 0);
187c512ac01SVictor Chibotaru	/* Read number of comparisons collected. */
188c512ac01SVictor Chibotaru	n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED);
189c512ac01SVictor Chibotaru	for (i = 0; i < n; i++) {
1906f1d34bdSSebastian Andrzej Siewior		uint64_t ip;
1916f1d34bdSSebastian Andrzej Siewior
192c512ac01SVictor Chibotaru		type = cover[i * KCOV_WORDS_PER_CMP + 1];
193c512ac01SVictor Chibotaru		/* arg1 and arg2 - operands of the comparison. */
194c512ac01SVictor Chibotaru		arg1 = cover[i * KCOV_WORDS_PER_CMP + 2];
195c512ac01SVictor Chibotaru		arg2 = cover[i * KCOV_WORDS_PER_CMP + 3];
196c512ac01SVictor Chibotaru		/* ip - caller address. */
197c512ac01SVictor Chibotaru		ip = cover[i * KCOV_WORDS_PER_CMP + 4];
198c512ac01SVictor Chibotaru		/* size of the operands. */
199c512ac01SVictor Chibotaru		size = 1 << ((type & KCOV_CMP_MASK) >> 1);
200c512ac01SVictor Chibotaru		/* is_const - true if either operand is a compile-time constant.*/
201c512ac01SVictor Chibotaru		is_const = type & KCOV_CMP_CONST;
202c512ac01SVictor Chibotaru		printf("ip: 0x%lx type: 0x%lx, arg1: 0x%lx, arg2: 0x%lx, "
203c512ac01SVictor Chibotaru			"size: %lu, %s\n",
204c512ac01SVictor Chibotaru			ip, type, arg1, arg2, size,
205c512ac01SVictor Chibotaru		is_const ? "const" : "non-const");
206c512ac01SVictor Chibotaru	}
207c512ac01SVictor Chibotaru	if (ioctl(fd, KCOV_DISABLE, 0))
208c512ac01SVictor Chibotaru		perror("ioctl"), exit(1);
209c512ac01SVictor Chibotaru	/* Free resources. */
210c512ac01SVictor Chibotaru	if (munmap(cover, COVER_SIZE * sizeof(unsigned long)))
211c512ac01SVictor Chibotaru		perror("munmap"), exit(1);
212c512ac01SVictor Chibotaru	if (close(fd))
213c512ac01SVictor Chibotaru		perror("close"), exit(1);
214c512ac01SVictor Chibotaru	return 0;
215c512ac01SVictor Chibotaru    }
216c512ac01SVictor Chibotaru
217*7b32137bSAndrey KonovalovNote that the KCOV modes (collection of code coverage or comparison operands)
218*7b32137bSAndrey Konovalovare mutually exclusive.
219eec028c9SAndrey Konovalov
220eec028c9SAndrey KonovalovRemote coverage collection
221eec028c9SAndrey Konovalov--------------------------
222eec028c9SAndrey Konovalov
223*7b32137bSAndrey KonovalovBesides collecting coverage data from handlers of syscalls issued from a
224*7b32137bSAndrey Konovalovuserspace process, KCOV can also collect coverage for parts of the kernel
225*7b32137bSAndrey Konovalovexecuting in other contexts - so-called "remote" coverage.
226eec028c9SAndrey Konovalov
227*7b32137bSAndrey KonovalovUsing KCOV to collect remote coverage requires:
228eec028c9SAndrey Konovalov
229*7b32137bSAndrey Konovalov1. Modifying kernel code to annotate the code section from where coverage
230*7b32137bSAndrey Konovalov   should be collected with ``kcov_remote_start`` and ``kcov_remote_stop``.
231eec028c9SAndrey Konovalov
232*7b32137bSAndrey Konovalov2. Using ``KCOV_REMOTE_ENABLE`` instead of ``KCOV_ENABLE`` in the userspace
233*7b32137bSAndrey Konovalov   process that collects coverage.
234eec028c9SAndrey Konovalov
235*7b32137bSAndrey KonovalovBoth ``kcov_remote_start`` and ``kcov_remote_stop`` annotations and the
236*7b32137bSAndrey Konovalov``KCOV_REMOTE_ENABLE`` ioctl accept handles that identify particular coverage
237*7b32137bSAndrey Konovalovcollection sections. The way a handle is used depends on the context where the
238*7b32137bSAndrey Konovalovmatching code section executes.
239eec028c9SAndrey Konovalov
240*7b32137bSAndrey KonovalovKCOV supports collecting remote coverage from the following contexts:
241*7b32137bSAndrey Konovalov
242*7b32137bSAndrey Konovalov1. Global kernel background tasks. These are the tasks that are spawned during
243*7b32137bSAndrey Konovalov   kernel boot in a limited number of instances (e.g. one USB ``hub_event``
244*7b32137bSAndrey Konovalov   worker is spawned per one USB HCD).
245*7b32137bSAndrey Konovalov
246*7b32137bSAndrey Konovalov2. Local kernel background tasks. These are spawned when a userspace process
247*7b32137bSAndrey Konovalov   interacts with some kernel interface and are usually killed when the process
248*7b32137bSAndrey Konovalov   exits (e.g. vhost workers).
249*7b32137bSAndrey Konovalov
250*7b32137bSAndrey Konovalov3. Soft interrupts.
251*7b32137bSAndrey Konovalov
252*7b32137bSAndrey KonovalovFor #1 and #3, a unique global handle must be chosen and passed to the
253*7b32137bSAndrey Konovalovcorresponding ``kcov_remote_start`` call. Then a userspace process must pass
254*7b32137bSAndrey Konovalovthis handle to ``KCOV_REMOTE_ENABLE`` in the ``handles`` array field of the
255*7b32137bSAndrey Konovalov``kcov_remote_arg`` struct. This will attach the used KCOV device to the code
256*7b32137bSAndrey Konovalovsection referenced by this handle. Multiple global handles identifying
257*7b32137bSAndrey Konovalovdifferent code sections can be passed at once.
258*7b32137bSAndrey Konovalov
259*7b32137bSAndrey KonovalovFor #2, the userspace process instead must pass a non-zero handle through the
260*7b32137bSAndrey Konovalov``common_handle`` field of the ``kcov_remote_arg`` struct. This common handle
261*7b32137bSAndrey Konovalovgets saved to the ``kcov_handle`` field in the current ``task_struct`` and
262*7b32137bSAndrey Konovalovneeds to be passed to the newly spawned local tasks via custom kernel code
263*7b32137bSAndrey Konovalovmodifications. Those tasks should in turn use the passed handle in their
264*7b32137bSAndrey Konovalov``kcov_remote_start`` and ``kcov_remote_stop`` annotations.
265*7b32137bSAndrey Konovalov
266*7b32137bSAndrey KonovalovKCOV follows a predefined format for both global and common handles. Each
267*7b32137bSAndrey Konovalovhandle is a ``u64`` integer. Currently, only the one top and the lower 4 bytes
268*7b32137bSAndrey Konovalovare used. Bytes 4-7 are reserved and must be zero.
269*7b32137bSAndrey Konovalov
270*7b32137bSAndrey KonovalovFor global handles, the top byte of the handle denotes the id of a subsystem
271*7b32137bSAndrey Konovalovthis handle belongs to. For example, KCOV uses ``1`` as the USB subsystem id.
272*7b32137bSAndrey KonovalovThe lower 4 bytes of a global handle denote the id of a task instance within
273*7b32137bSAndrey Konovalovthat subsystem. For example, each ``hub_event`` worker uses the USB bus number
274*7b32137bSAndrey Konovalovas the task instance id.
275*7b32137bSAndrey Konovalov
276*7b32137bSAndrey KonovalovFor common handles, a reserved value ``0`` is used as a subsystem id, as such
277*7b32137bSAndrey Konovalovhandles don't belong to a particular subsystem. The lower 4 bytes of a common
278*7b32137bSAndrey Konovalovhandle identify a collective instance of all local tasks spawned by the
279*7b32137bSAndrey Konovalovuserspace process that passed a common handle to ``KCOV_REMOTE_ENABLE``.
280*7b32137bSAndrey Konovalov
281*7b32137bSAndrey KonovalovIn practice, any value can be used for common handle instance id if coverage
282*7b32137bSAndrey Konovalovis only collected from a single userspace process on the system. However, if
283*7b32137bSAndrey Konovalovcommon handles are used by multiple processes, unique instance ids must be
284*7b32137bSAndrey Konovalovused for each process. One option is to use the process id as the common
285*7b32137bSAndrey Konovalovhandle instance id.
286*7b32137bSAndrey Konovalov
287*7b32137bSAndrey KonovalovThe following program demonstrates using KCOV to collect coverage from both
288*7b32137bSAndrey Konovalovlocal tasks spawned by the process and the global task that handles USB bus #1:
289eec028c9SAndrey Konovalov
290eec028c9SAndrey Konovalov.. code-block:: c
291eec028c9SAndrey Konovalov
292d687a9ccSSebastian Andrzej Siewior    /* Same includes and defines as above. */
293d687a9ccSSebastian Andrzej Siewior
294eec028c9SAndrey Konovalov    struct kcov_remote_arg {
295a69b83e1SAndrey Konovalov	__u32		trace_mode;
296a69b83e1SAndrey Konovalov	__u32		area_size;
297a69b83e1SAndrey Konovalov	__u32		num_handles;
298a69b83e1SAndrey Konovalov	__aligned_u64	common_handle;
299a69b83e1SAndrey Konovalov	__aligned_u64	handles[0];
300eec028c9SAndrey Konovalov    };
301eec028c9SAndrey Konovalov
302eec028c9SAndrey Konovalov    #define KCOV_INIT_TRACE			_IOR('c', 1, unsigned long)
303eec028c9SAndrey Konovalov    #define KCOV_DISABLE			_IO('c', 101)
304eec028c9SAndrey Konovalov    #define KCOV_REMOTE_ENABLE		_IOW('c', 102, struct kcov_remote_arg)
305eec028c9SAndrey Konovalov
306eec028c9SAndrey Konovalov    #define COVER_SIZE	(64 << 10)
307eec028c9SAndrey Konovalov
308eec028c9SAndrey Konovalov    #define KCOV_TRACE_PC	0
309eec028c9SAndrey Konovalov
310eec028c9SAndrey Konovalov    #define KCOV_SUBSYSTEM_COMMON	(0x00ull << 56)
311eec028c9SAndrey Konovalov    #define KCOV_SUBSYSTEM_USB	(0x01ull << 56)
312eec028c9SAndrey Konovalov
313eec028c9SAndrey Konovalov    #define KCOV_SUBSYSTEM_MASK	(0xffull << 56)
314eec028c9SAndrey Konovalov    #define KCOV_INSTANCE_MASK	(0xffffffffull)
315eec028c9SAndrey Konovalov
316eec028c9SAndrey Konovalov    static inline __u64 kcov_remote_handle(__u64 subsys, __u64 inst)
317eec028c9SAndrey Konovalov    {
318eec028c9SAndrey Konovalov	if (subsys & ~KCOV_SUBSYSTEM_MASK || inst & ~KCOV_INSTANCE_MASK)
319eec028c9SAndrey Konovalov		return 0;
320eec028c9SAndrey Konovalov	return subsys | inst;
321eec028c9SAndrey Konovalov    }
322eec028c9SAndrey Konovalov
323eec028c9SAndrey Konovalov    #define KCOV_COMMON_ID	0x42
324eec028c9SAndrey Konovalov    #define KCOV_USB_BUS_NUM	1
325eec028c9SAndrey Konovalov
326eec028c9SAndrey Konovalov    int main(int argc, char **argv)
327eec028c9SAndrey Konovalov    {
328eec028c9SAndrey Konovalov	int fd;
329eec028c9SAndrey Konovalov	unsigned long *cover, n, i;
330eec028c9SAndrey Konovalov	struct kcov_remote_arg *arg;
331eec028c9SAndrey Konovalov
332eec028c9SAndrey Konovalov	fd = open("/sys/kernel/debug/kcov", O_RDWR);
333eec028c9SAndrey Konovalov	if (fd == -1)
334eec028c9SAndrey Konovalov		perror("open"), exit(1);
335eec028c9SAndrey Konovalov	if (ioctl(fd, KCOV_INIT_TRACE, COVER_SIZE))
336eec028c9SAndrey Konovalov		perror("ioctl"), exit(1);
337eec028c9SAndrey Konovalov	cover = (unsigned long*)mmap(NULL, COVER_SIZE * sizeof(unsigned long),
338eec028c9SAndrey Konovalov				     PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
339eec028c9SAndrey Konovalov	if ((void*)cover == MAP_FAILED)
340eec028c9SAndrey Konovalov		perror("mmap"), exit(1);
341eec028c9SAndrey Konovalov
342eec028c9SAndrey Konovalov	/* Enable coverage collection via common handle and from USB bus #1. */
343eec028c9SAndrey Konovalov	arg = calloc(1, sizeof(*arg) + sizeof(uint64_t));
344eec028c9SAndrey Konovalov	if (!arg)
345eec028c9SAndrey Konovalov		perror("calloc"), exit(1);
346eec028c9SAndrey Konovalov	arg->trace_mode = KCOV_TRACE_PC;
347eec028c9SAndrey Konovalov	arg->area_size = COVER_SIZE;
348eec028c9SAndrey Konovalov	arg->num_handles = 1;
349eec028c9SAndrey Konovalov	arg->common_handle = kcov_remote_handle(KCOV_SUBSYSTEM_COMMON,
350eec028c9SAndrey Konovalov							KCOV_COMMON_ID);
351eec028c9SAndrey Konovalov	arg->handles[0] = kcov_remote_handle(KCOV_SUBSYSTEM_USB,
352eec028c9SAndrey Konovalov						KCOV_USB_BUS_NUM);
353eec028c9SAndrey Konovalov	if (ioctl(fd, KCOV_REMOTE_ENABLE, arg))
354eec028c9SAndrey Konovalov		perror("ioctl"), free(arg), exit(1);
355eec028c9SAndrey Konovalov	free(arg);
356eec028c9SAndrey Konovalov
357eec028c9SAndrey Konovalov	/*
358eec028c9SAndrey Konovalov	 * Here the user needs to trigger execution of a kernel code section
359eec028c9SAndrey Konovalov	 * that is either annotated with the common handle, or to trigger some
360eec028c9SAndrey Konovalov	 * activity on USB bus #1.
361eec028c9SAndrey Konovalov	 */
362eec028c9SAndrey Konovalov	sleep(2);
363eec028c9SAndrey Konovalov
364eec028c9SAndrey Konovalov	n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED);
365eec028c9SAndrey Konovalov	for (i = 0; i < n; i++)
366eec028c9SAndrey Konovalov		printf("0x%lx\n", cover[i + 1]);
367eec028c9SAndrey Konovalov	if (ioctl(fd, KCOV_DISABLE, 0))
368eec028c9SAndrey Konovalov		perror("ioctl"), exit(1);
369eec028c9SAndrey Konovalov	if (munmap(cover, COVER_SIZE * sizeof(unsigned long)))
370eec028c9SAndrey Konovalov		perror("munmap"), exit(1);
371eec028c9SAndrey Konovalov	if (close(fd))
372eec028c9SAndrey Konovalov		perror("close"), exit(1);
373eec028c9SAndrey Konovalov	return 0;
374eec028c9SAndrey Konovalov    }
375