xref: /openbsd/share/man/man4/kcov.4 (revision 76d0caae)
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