xref: /netbsd-src/share/man/man4/kcov.4 (revision 0701e2356ee850ec75d1268b9e7e13c8f3420dd4)
1.\"	$NetBSD: kcov.4,v 1.6 2019/05/28 21:31:53 kamil 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 May 28, 2019
18.Dt KCOV 4
19.Os
20.Sh NAME
21.Nm kcov
22.Nd kernel code coverage tracing
23.Sh SYNOPSIS
24.Cd options 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.
34.Pp
35The
36.Nm
37descriptors (KD) are allocated during
38.Xr open 2 ,
39and are associated with a file descriptor.
40A thread can enable the
41.Nm
42device.
43When this happens,
44this thread becomes the owner of the
45.Nm
46descriptors (KD),
47and no thread can disable this KD except the owner.
48.Pp
49A
50.Nm
51descriptor (KD)
52is freed when its file descriptor is closed iff the KD is not active on a thread.
53If it is,
54we ask the thread to free it when it exits.
55.Pp
56The collected coverage can be accessed by mapping the device
57using
58.Xr mmap 2 .
59The buffers are mapped without risk that the kernel frees a buffer still mapped in a process.
60.Pp
61By default,
62.Nm
63is not enabled but requires the compile-time configuration
64.Cd makeoptions KCOV
65.Cd options KCOV
66to be present,
67see
68.Xr options 4 .
69.Pp
70The following
71.Xr ioctl 2
72calls are provided:
73.Bl -tag -width 4n
74.It Dv KCOV_IOC_SETBUFSIZE Fa uint64_t *nentries
75Allocate a coverage buffer with a capacity of
76.Fa nentries .
77The buffer can be accessed using
78.Xr mmap 2
79whereas the returned pointer must be interpreted as an array of
80.Vt kcov_int_t
81entries.
82Note that kcov_int_t is volatile.
83The first entry contains the number of entries in the array,
84excluding the first entry.
85.It Dv KCOV_IOC_ENABLE Fa int *mode
86Enable code coverage tracing for the current thread.
87The
88.Fa mode
89must be one of the following:
90.Bl -ohang
91.It Dv KCOV_MODE_NONE
92No trace selected.
93This option is useful for testing the
94.Nm
95device.
96.It Dv KCOV_MODE_TRACE_PC
97Trace the kernel program counter.
98.It Dv KCOV_MODE_TRACE_CMP
99Trace comparison instructions and switch statements.
100For switch statements, the number of traced comparison instructions is equal to
101the number of switch cases.
102Each traced comparison instruction is represented by 4 entries in the coverage
103buffer:
104.Bl -enum
105.It
106A mask where the least significant bit is set if one of the comparison operands
107is a compile-time constant, which is always true for switch statements.
108The remaining bits represents the log2 size of the operands, ranging from 0 to
1093.
110.It
111First comparison operand.
112For switch statements, this operand corresponds to the case value.
113.It
114Second comparison operand.
115For switch statements, this operand corresponds to the value passed to switch.
116.It
117Kernel program counter where the comparison instruction took place.
118.El
119.Pp
120In this mode, the first entry in the coverage buffer reflects the number of
121traced comparison instructions.
122Thus, the effective number of entries in the coverage buffer is given by
123multiplying the first entry by 4.
124.El
125.It Dv KCOV_IOC_DISABLE Fa void
126Disable code coverage tracing for the current thread.
127.El
128.Sh FILES
129.Bl -tag -width /dev/kcov -compact
130.It Pa /dev/kcov
131Default device node.
132.El
133.Sh EXAMPLES
134In the following example,
135the
136.Xr read 2
137syscall is traced and the coverage displayed, which in turn can be passed to
138.Xr addr2line 1
139in order to translate the kernel program counter into the file name and line
140number it corresponds to.
141.Bd -literal
142#include <err.h>
143#include <fcntl.h>
144#include <stdio.h>
145#include <stdlib.h>
146#include <unistd.h>
147
148#include <sys/ioccom.h>
149#include <sys/ioctl.h>
150#include <sys/mman.h>
151
152#include <sys/kcov.h>
153
154int
155main(void)
156{
157	kcov_int_t *cover, i, n;
158	uint64_t size = 1024 * 100;
159	int fd;
160	int mode;
161
162	fd = open("/dev/kcov", O_RDWR);
163	if (fd == -1)
164		err(1, "open");
165	if (ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) == -1)
166		err(1, "ioctl: KCOV_IOC_SETBUFSIZE");
167	cover = mmap(NULL, size * KCOV_ENTRY_SIZE,
168	    PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
169	if (cover == MAP_FAILED)
170		err(1, "mmap");
171	mode = KCOV_MODE_TRACE_PC;
172	if (ioctl(fd, KCOV_IOC_ENABLE, &mode) == -1)
173		err(1, "ioctl: KCOV_IOC_ENABLE");
174	cover[0] = 0;
175	read(-1, NULL, 0); /* syscall paths to be traced */
176	n = cover[0];
177	if (ioctl(fd, KCOV_IOC_DISABLE) == -1)
178		err(1, "ioctl: KCOV_IOC_DISABLE");
179	for (i = 0; i < n; i++)
180		printf("%p\en", (void *)cover[i + 1]);
181	if (munmap(cover, size * KCOV_ENTRY_SIZE) == -1)
182		err(1, "munmap");
183	close(fd);
184
185	return 0;
186}
187.Ed
188.Sh SEE ALSO
189.Xr options 4
190.Sh HISTORY
191The
192.Nm
193driver was initially developed in Linux.
194A driver based on the same concept was then implemented in
195.Nx 9 .
196.Sh AUTHORS
197.An Siddharth Muralee Aq Mt siddharth.muralee@gmail.com
198