1.\" $OpenBSD: kcov.4,v 1.9 2020/12/08 20:17:10 anton Exp $ 2.\" 3.\" Copyright (c) 2018 Anton Lindqvist <anton@openbsd.org> 4.\" 5.\" Permission to use, copy, modify, and distribute this software for any 6.\" purpose with or without fee is hereby granted, provided that the above 7.\" copyright notice and this permission notice appear in all copies. 8.\" 9.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16.\" 17.Dd $Mdocdate: December 8 2020 $ 18.Dt KCOV 4 19.Os 20.Sh NAME 21.Nm kcov 22.Nd kernel code coverage tracing 23.Sh SYNOPSIS 24.Cd pseudo-device kcov 25.Pp 26.In sys/kcov.h 27.Sh DESCRIPTION 28The 29.Nm 30driver implements collection of code coverage inside the kernel. 31It can be enabled on a per thread basis from userland, 32allowing the kernel program counter to be collected during syscalls triggered by 33the same thread. 34The collected coverage can be accessed by mapping the device 35using 36.Xr mmap 2 . 37.Pp 38By default, 39.Nm 40is not enabled but instead requires the following line to be present in the 41kernel configuration: 42.Bd -literal -offset indent 43pseudo-device kcov 1 44.Ed 45.Pp 46The following 47.Xr ioctl 2 48calls are provided: 49.Bl -tag -width 4n 50.It Dv KIOSETBUFSIZE Fa unsigned long *nentries 51Allocate a coverage buffer with a capacity of 52.Fa nentries . 53The buffer can be accessed using 54.Xr mmap 2 , 55whereas the returned pointer must be interpreted as an array of 56.Vt unsigned long 57entries. 58The first entry contains the number of entries in the array, 59excluding the first entry. 60.It Dv KIOENABLE Fa int *mode 61Enable code coverage tracing for the current thread or any remote 62subsystem attached using 63.Dv KIOREMOTEATTACH . 64The 65.Fa mode 66must be one of the following: 67.Bl -ohang 68.It Dv KCOV_MODE_TRACE_PC 69Trace the kernel program counter. 70.It Dv KCOV_MODE_TRACE_CMP 71Trace comparison instructions and switch statements. 72For switch statements, the number of traced comparison instructions is equal to 73the number of switch cases. 74Each traced comparison instruction is represented by 4 entries in the coverage 75buffer: 76.Bl -enum 77.It 78A mask where the least significant bit is set if one of the comparison operands 79is a compile-time constant, which is always true for switch statements. 80The remaining bits represents the log2 size of the operands, ranging from 0 to 813. 82.It 83First comparison operand. 84For switch statements, this operand corresponds to the case value. 85.It 86Second comparison operand. 87For switch statements, this operand corresponds to the value passed to switch. 88.It 89Kernel program counter where the comparison instruction took place. 90.El 91.Pp 92In this mode, the first entry in the coverage buffer reflects the number of 93traced comparison instructions. 94Thus, the effective number of entries in the coverage buffer is given by 95multiplying the first entry by 4. 96.El 97.It Dv KIODISABLE Fa void 98Disable code coverage tracing for the current thread. 99.It Dv KIOREMOTEATTACH Fa struct kio_remote_attach *remote 100Attach collection of remote coverage from other kernel threads, identified 101by a subsystem. 102Collection of remote coverage is mutually exclusive with coverage collection 103of the current thread. 104The 105.Va remote 106argument is a pointer to the following structure: 107.Bd -literal 108struct kio_remote_attach { 109 int subsystem; 110 int id; 111}; 112.Ed 113.Pp 114The 115.Va subsystem 116field must be one of the following: 117.Bl -ohang 118.It Dv KCOV_REMOTE_COMMON 119Collect coverage from tasks and timeouts scheduled by the current process, 120see 121.Xr task_add 9 122and 123.Xr timeout 9 . 124The 125.Fa id 126field is ignored. 127.El 128.El 129.Sh FILES 130.Bl -tag -width /dev/kcov -compact 131.It Pa /dev/kcov 132Default device node. 133.El 134.Sh EXAMPLES 135In the following example, 136the 137.Xr read 2 138syscall is traced and the coverage displayed, which in turn can be passed to 139.Xr addr2line 1 140in order to translate the kernel program counter into the file name and line 141number it corresponds to. 142.Bd -literal 143#include <sys/ioctl.h> 144#include <sys/kcov.h> 145#include <sys/mman.h> 146 147#include <err.h> 148#include <fcntl.h> 149#include <stdio.h> 150#include <stdlib.h> 151#include <unistd.h> 152 153int 154main(void) 155{ 156 unsigned long *cover, i; 157 unsigned long size = 1024; 158 int fd, mode; 159 160 fd = open("/dev/kcov", O_RDWR); 161 if (fd == -1) 162 err(1, "open"); 163 164 if (ioctl(fd, KIOSETBUFSIZE, &size) == -1) 165 err(1, "ioctl: KIOSETBUFSIZE"); 166 cover = mmap(NULL, size * sizeof(unsigned long), 167 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 168 if (cover == MAP_FAILED) 169 err(1, "mmap"); 170 171 mode = KCOV_MODE_TRACE_PC; 172 if (ioctl(fd, KIOENABLE, &mode) == -1) 173 err(1, "ioctl: KIOENABLE"); 174 read(-1, NULL, 0); 175 if (ioctl(fd, KIODISABLE) == -1) 176 err(1, "ioctl: KIODISABLE"); 177 178 for (i = 0; i < cover[0]; i++) 179 printf("%p\en", (void *)cover[i + 1]); 180 181 if (munmap(cover, size * sizeof(unsigned long)) == -1) 182 err(1, "munmap"); 183 close(fd); 184 185 return 0; 186} 187.Ed 188.Sh SEE ALSO 189.Xr files.conf 5 , 190.Xr kcov_remote_register 9 191.Sh HISTORY 192The 193.Nm 194driver first appeared in 195.Ox 6.4 . 196.Sh AUTHORS 197The 198.Nm 199driver was written by 200.An Anton Lindqvist Aq Mt anton@openbsd.org . 201.Sh CAVEATS 202The 203.Nm 204driver is limited to architectures using 205.Xr clang 1 206as their default compiler. 207