1.\" $OpenBSD: kcov.4,v 1.7 2019/01/20 09:57:23 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: January 20 2019 $ 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 1 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. 62The 63.Fa mode 64must be one of the following: 65.Bl -ohang 66.It Dv KCOV_MODE_TRACE_PC 67Trace the kernel program counter. 68.It Dv KCOV_MODE_TRACE_CMP 69Trace comparison instructions and switch statements. 70For switch statements, the number of traced comparison instructions is equal to 71the number of switch cases. 72Each traced comparison instruction is represented by 4 entries in the coverage 73buffer: 74.Bl -enum 75.It 76A mask where the least significant bit is set if one of the comparison operands 77is a compile-time constant, which is always true for switch statements. 78The remaining bits represents the log2 size of the operands, ranging from 0 to 793. 80.It 81First comparison operand. 82For switch statements, this operand corresponds to the case value. 83.It 84Second comparison operand. 85For switch statements, this operand corresponds to the value passed to switch. 86.It 87Kernel program counter where the comparison instruction took place. 88.El 89.Pp 90In this mode, the first entry in the coverage buffer reflects the number of 91traced comparison instructions. 92Thus, the effective number of entries in the coverage buffer is given by 93multiplying the first entry by 4. 94.El 95.It Dv KIODISABLE Fa void 96Disable code coverage tracing for the current thread. 97.El 98.Sh FILES 99.Bl -tag -width /dev/kcov -compact 100.It Pa /dev/kcov 101Default device node. 102.El 103.Sh EXAMPLES 104In the following example, 105the 106.Xr read 2 107syscall is traced and the coverage displayed, which in turn can be passed to 108.Xr addr2line 1 109in order to translate the kernel program counter into the file name and line 110number it corresponds to. 111.Bd -literal 112#include <sys/ioctl.h> 113#include <sys/kcov.h> 114#include <sys/mman.h> 115 116#include <err.h> 117#include <fcntl.h> 118#include <stdio.h> 119#include <stdlib.h> 120#include <unistd.h> 121 122int 123main(void) 124{ 125 unsigned long *cover, i; 126 unsigned long size = 1024; 127 int fd, mode; 128 129 fd = open("/dev/kcov", O_RDWR); 130 if (fd == -1) 131 err(1, "open"); 132 133 if (ioctl(fd, KIOSETBUFSIZE, &size) == -1) 134 err(1, "ioctl: KIOSETBUFSIZE"); 135 cover = mmap(NULL, size * sizeof(unsigned long), 136 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 137 if (cover == MAP_FAILED) 138 err(1, "mmap"); 139 140 mode = KCOV_MODE_TRACE_PC; 141 if (ioctl(fd, KIOENABLE, &mode) == -1) 142 err(1, "ioctl: KIOENABLE"); 143 read(-1, NULL, 0); 144 if (ioctl(fd, KIODISABLE) == -1) 145 err(1, "ioctl: KIODISABLE"); 146 147 for (i = 0; i < cover[0]; i++) 148 printf("%p\en", (void *)cover[i + 1]); 149 150 if (munmap(cover, size * sizeof(unsigned long)) == -1) 151 err(1, "munmap"); 152 close(fd); 153 154 return 0; 155} 156.Ed 157.Sh SEE ALSO 158.Xr files.conf 5 159.Sh HISTORY 160The 161.Nm 162driver first appeared in 163.Ox 6.4 . 164.Sh AUTHORS 165The 166.Nm 167driver was written by 168.An Anton Lindqvist Aq Mt anton@openbsd.org . 169.Sh CAVEATS 170The 171.Nm 172driver is limited to architectures using 173.Xr clang 1 174as their default compiler. 175