1.\"- 2.\" Copyright (c) 2020 The FreeBSD Foundation 3.\" 4.\" This documentation was written by Mark Johnston under sponsorship from 5.\" the FreeBSD Foundation. 6.\" 7.\" Redistribution and use in source and binary forms, with or without 8.\" modification, are permitted provided that the following conditions 9.\" are met: 10.\" 1. Redistributions of source code must retain the above copyright 11.\" notice, this list of conditions and the following disclaimer. 12.\" 2. Redistributions in binary form must reproduce the above copyright 13.\" notice, this list of conditions and the following disclaimer in the 14.\" documentation and/or other materials provided with the distribution. 15.\" 16.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26.\" SUCH DAMAGE. 27.\" 28.Dd August 18, 2020 29.Dt KCOV 4 30.Os 31.Sh NAME 32.Nm kcov 33.Nd interface for collecting kernel code coverage information 34.Sh SYNOPSIS 35To compile KCOV into the kernel, place the following lines in your kernel 36configuration file: 37.Bd -ragged -offset indent 38.Cd "options COVERAGE" 39.Cd "options KCOV" 40.Ed 41.Pp 42The following header file defines the application interface provided 43by KCOV: 44.Pp 45.In sys/kcov.h 46.Sh DESCRIPTION 47.Nm 48is a module that enables collection of code coverage information from the 49kernel. 50It relies on code instrumentation enabled by the 51.Dv COVERAGE 52kernel option. 53When 54.Nm 55is enabled by a user-mode thread, it collects coverage information only for 56that thread, excluding hard interrupt handlers. 57As a result, 58.Nm 59is not suited to collect comprehensive coverage data for the entire kernel; 60its main purpose is to provide input for coverage-guided system call fuzzers. 61.Pp 62In typical usage, a user-mode thread first allocates a chunk of memory to be 63shared with 64.Nm . 65The thread then enables coverage tracing, with coverage data being written by 66the kernel to the shared memory region. 67When tracing is disabled, the kernel relinquishes its access to the shared 68memory region, and the written coverage data may be consumed. 69.Pp 70The shared memory buffer can be treated as a 64-bit unsigned integer followed 71by an array of records. 72The integer records the number of valid records and is updated by the kernel as 73coverage information is recorded. 74The state of the tracing buffer can be reset by writing the value 0 to this 75field. 76The record layout depends on the tracing mode set using the 77.Dv KIOENABLE 78ioctl. 79.Pp 80Two tracing modes are implemented, 81.Dv KCOV_MODE_TRACE_PC 82and 83.Dv KCOV_MODE_TRACE_CMP . 84PC-tracing records a program counter value for each basic block executed while 85tracing is enabled. 86In this mode, each record is a single 64-bit unsigned integer containing the 87program counter value. 88Comparison tracing provides information about data flow; information about 89dynamic variable comparisons is recorded. 90Such records provide information about the results of 91.Xr c 7 92.Ql if 93or 94.Ql switch 95statements, for example. 96In this mode each record consists of four 64-bit unsigned integers. 97The first integer is a bitmask defining attributes of the variables involved in 98the comparison. 99.Dv KCOV_CMP_CONST 100is set if one of the variables has a constant value at compile-time, and 101.Dv KCOV_CMP_SIZE(n) 102specifies the width of the variables: 103.Pp 104.Bl -inset -offset indent -compact 105.It Dv KCOV_CMP_SIZE(0) : 106a comparison of 8-bit integers 107.It Dv KCOV_CMP_SIZE(1) : 108a comparison of 16-bit integers 109.It Dv KCOV_CMP_SIZE(2) : 110a comparison of 32-bit integers 111.It Dv KCOV_CMP_SIZE(3) : 112a comparison of 64-bit integers 113.El 114.Pp 115The second and third fields record the values of the two variables, and the 116fourth and final field stores the program counter value of the comparison. 117.Sh IOCTL INTERFACE 118Applications interact with 119.Nm 120using the 121.Xr ioctl 2 122system call. 123Each thread making use of 124.Nm 125must use a separate file descriptor for 126.Fa /dev/kcov . 127The following ioctls are defined: 128.Bl -tag -width indent 129.It Dv KIOSETBUFSIZE Fa size_t entries 130Set the size of the tracing buffer in units of 131.Dv KCOV_ENTRY_SIZE . 132The buffer may then be mapped into the calling thread's address space by 133calling 134.Xr mmap 2 135on the 136.Nm 137device file. 138.It Dv KIOENABLE Fa int mode 139Enable coverage tracing for the calling thread. 140Valid modes are 141.Dv KCOV_MODE_TRACE_PC 142and 143.Dv KCOV_MODE_TRACE_CMP . 144.It Dv KIODISABLE 145Disable coverage tracing for the calling thread. 146.El 147.Sh FILES 148.Nm 149creates the 150.Pa /dev/kcov 151device file. 152.Sh EXAMPLES 153The following code sample collects information about basic block coverage for 154kernel code executed while printing 155.Ql "Hello, world" . 156.Bd -literal 157size_t sz; 158uint64_t *buf; 159int fd; 160 161fd = open("/dev/kcov", O_RDWR); 162if (fd == -1) 163 err(1, "open(/dev/kcov)"); 164sz = 1ul << 20; /* 1MB */ 165if (ioctl(fd, KIOSETBUFSIZE, sz / KCOV_ENTRY_SIZE) != 0) 166 err(1, "ioctl(KIOSETBUFSIZE)"); 167buf = mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 168if (buf == MAP_FAILED) 169 err(1, "mmap"); 170 171/* Enable PC tracing. */ 172if (ioctl(fd, KIOENABLE, KCOV_MODE_TRACE_PC) != 0) 173 err(1, "ioctl(KIOENABLE)"); 174 175/* Clear trace records from the preceding ioctl() call. */ 176buf[0] = 0; 177 178printf("Hello, world!\\n"); 179 180/* Disable PC tracing. */ 181if (ioctl(fd, KIODISABLE, 0) != 0) 182 err(1, "ioctl(KIODISABLE)"); 183 184for (uint64_t i = 1; i < buf[0]; i++) 185 printf("%#jx\\n", (uintmax_t)buf[i]); 186.Ed 187The output of this program can be approximately mapped to line numbers 188in kernel source code: 189.Bd -literal 190# ./kcov-test | sed 1d | addr2line -e /usr/lib/debug/boot/kernel/kernel.debug 191.Ed 192.Sh SEE ALSO 193.Xr ioctl 2 , 194.Xr mmap 2 195.Sh HISTORY 196.Nm 197first appeared in 198.Fx 13.0 . 199.Sh BUGS 200The 201.Fx 202implementation of 203.Nm 204does not yet support remote tracing. 205