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