]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tests/sys/kern/kcov.c
Add support for the Clang Coverage Sanitizer in the kernel (KCOV).
[FreeBSD/FreeBSD.git] / tests / sys / kern / kcov.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2018, 2019 Andrew Turner
5  *
6  * This software was developed by SRI International and the University of
7  * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
8  * ("CTSRD"), as part of the DARPA CRASH research programme.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 #include <sys/param.h>
36 #include <sys/ioctl.h>
37 #include <sys/kcov.h>
38 #include <sys/mman.h>
39
40 #include <machine/atomic.h>
41
42 #include <fcntl.h>
43 #include <pthread.h>
44 #include <semaphore.h>
45
46 #include <atf-c.h>
47
48 static const char *modes[] = {
49     "PC tracing",
50     "comparison tracing",
51 };
52
53 static int
54 open_kcov(void)
55 {
56         int fd;
57
58         fd = open("/dev/kcov", O_RDWR);
59         if (fd == -1)
60                 atf_tc_skip("Failed to open /dev/kcov");
61
62         return (fd);
63 }
64
65 ATF_TC_WITHOUT_HEAD(kcov_bufsize);
66 ATF_TC_BODY(kcov_bufsize, tc)
67 {
68         int fd;
69
70         fd = open_kcov();
71
72         ATF_CHECK(ioctl(fd, KIOSETBUFSIZE, 0) == -1);
73         ATF_CHECK(ioctl(fd, KIOSETBUFSIZE, 1) == -1);
74         ATF_CHECK(ioctl(fd, KIOSETBUFSIZE, 2) == 0);
75         ATF_CHECK(ioctl(fd, KIOSETBUFSIZE, 2) == -1);
76
77         close(fd);
78 }
79
80 ATF_TC_WITHOUT_HEAD(kcov_mmap);
81 ATF_TC_BODY(kcov_mmap, tc)
82 {
83         void *data;
84         int fd;
85
86         fd = open_kcov();
87
88         ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
89             fd, 0) == MAP_FAILED);
90
91         ATF_REQUIRE(ioctl(fd, KIOSETBUFSIZE,
92             2 * PAGE_SIZE / sizeof(uint64_t)) == 0);
93
94         ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
95             fd, 0) == MAP_FAILED);
96         ATF_CHECK(mmap(NULL, 3 * PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
97             fd, 0) == MAP_FAILED);
98         ATF_REQUIRE((data = mmap(NULL, 2 * PAGE_SIZE, PROT_READ | PROT_WRITE,
99             MAP_SHARED, fd, 0)) != MAP_FAILED);
100         ATF_CHECK(mmap(NULL, 2 * PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
101             fd, 0) == MAP_FAILED);
102
103         munmap(data, 2 * PAGE_SIZE);
104
105         close(fd);
106 }
107
108 /* This shouldn't panic */
109 ATF_TC_WITHOUT_HEAD(kcov_mmap_no_munmap);
110 ATF_TC_BODY(kcov_mmap_no_munmap, tc)
111 {
112         int fd;
113
114         fd = open_kcov();
115
116         ATF_REQUIRE(ioctl(fd, KIOSETBUFSIZE, PAGE_SIZE / sizeof(uint64_t)) ==0);
117
118         ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
119             fd, 0) != MAP_FAILED);
120
121         close(fd);
122 }
123
124 ATF_TC_WITHOUT_HEAD(kcov_mmap_no_munmap_no_close);
125 ATF_TC_BODY(kcov_mmap_no_munmap_no_close, tc)
126 {
127         int fd;
128
129         fd = open_kcov();
130
131         ATF_REQUIRE(ioctl(fd, KIOSETBUFSIZE, PAGE_SIZE / sizeof(uint64_t)) ==0);
132
133         ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
134             fd, 0) != MAP_FAILED);
135 }
136
137 static sem_t sem1, sem2;
138
139 static void *
140 kcov_mmap_enable_thread(void *data)
141 {
142         int fd;
143
144         fd = open_kcov();
145         *(int *)data = fd;
146
147         ATF_REQUIRE(ioctl(fd, KIOSETBUFSIZE, PAGE_SIZE / sizeof(uint64_t)) ==0);
148         ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
149             fd, 0) != MAP_FAILED);
150         ATF_CHECK(ioctl(fd, KIOENABLE, KCOV_MODE_TRACE_PC) == 0);
151
152         sem_post(&sem1);
153         sem_wait(&sem2);
154
155         return (NULL);
156 }
157
158 ATF_TC_WITHOUT_HEAD(kcov_mmap_enable_thread_close);
159 ATF_TC_BODY(kcov_mmap_enable_thread_close, tc)
160 {
161         pthread_t thread;
162         int fd;
163
164         sem_init(&sem1, 0, 0);
165         sem_init(&sem2, 0, 0);
166         pthread_create(&thread, NULL,
167             kcov_mmap_enable_thread, &fd);
168         sem_wait(&sem1);
169         close(fd);
170         sem_post(&sem2);
171         pthread_join(thread, NULL);
172 }
173
174 ATF_TC_WITHOUT_HEAD(kcov_enable);
175 ATF_TC_BODY(kcov_enable, tc)
176 {
177         int fd;
178
179         fd = open_kcov();
180
181         ATF_CHECK(ioctl(fd, KIOENABLE, KCOV_MODE_TRACE_PC) == -1);
182
183         ATF_REQUIRE(ioctl(fd, KIOSETBUFSIZE, PAGE_SIZE / sizeof(uint64_t)) ==0);
184
185         /* We need to enable before disable */
186         ATF_CHECK(ioctl(fd, KIODISABLE, 0) == -1);
187
188         /* Check enabling works only with a valid trace method */
189         ATF_CHECK(ioctl(fd, KIOENABLE, -1) == -1);
190         ATF_CHECK(ioctl(fd, KIOENABLE, KCOV_MODE_TRACE_PC) == 0);
191         ATF_CHECK(ioctl(fd, KIOENABLE, KCOV_MODE_TRACE_PC) == -1);
192         ATF_CHECK(ioctl(fd, KIOENABLE, KCOV_MODE_TRACE_CMP) == -1);
193
194         /* Disable should only be called once */
195         ATF_CHECK(ioctl(fd, KIODISABLE, 0) == 0);
196         ATF_CHECK(ioctl(fd, KIODISABLE, 0) == -1);
197
198         /* Re-enabling should also work */
199         ATF_CHECK(ioctl(fd, KIOENABLE, KCOV_MODE_TRACE_CMP) == 0);
200         ATF_CHECK(ioctl(fd, KIODISABLE, 0) == 0);
201
202         close(fd);
203 }
204
205 ATF_TC_WITHOUT_HEAD(kcov_enable_no_disable);
206 ATF_TC_BODY(kcov_enable_no_disable, tc)
207 {
208         int fd;
209
210         fd = open_kcov();
211         ATF_REQUIRE(ioctl(fd, KIOSETBUFSIZE, PAGE_SIZE / sizeof(uint64_t)) ==0);
212         ATF_CHECK(ioctl(fd, KIOENABLE, KCOV_MODE_TRACE_PC) == 0);
213         close(fd);
214 }
215
216 ATF_TC_WITHOUT_HEAD(kcov_enable_no_disable_no_close);
217 ATF_TC_BODY(kcov_enable_no_disable_no_close, tc)
218 {
219         int fd;
220
221         fd = open_kcov();
222         ATF_REQUIRE(ioctl(fd, KIOSETBUFSIZE, PAGE_SIZE / sizeof(uint64_t)) ==0);
223         ATF_CHECK(ioctl(fd, KIOENABLE, KCOV_MODE_TRACE_PC) == 0);
224 }
225
226 static void *
227 common_head(int *fdp)
228 {
229         void *data;
230         int fd;
231
232         fd = open_kcov();
233
234         ATF_REQUIRE_MSG(ioctl(fd, KIOSETBUFSIZE,
235             PAGE_SIZE / sizeof(uint64_t)) == 0,
236             "Unable to set the kcov buffer size");
237
238         data = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
239         ATF_REQUIRE_MSG(data != MAP_FAILED, "Unable to mmap the kcov buffer");
240
241         *fdp = fd;
242         return (data);
243 }
244
245 static void
246 common_tail(int fd, void *data)
247 {
248
249         ATF_REQUIRE_MSG(munmap(data, PAGE_SIZE) == 0,
250             "Unable to unmap the kcov buffer");
251
252         close(fd);
253 }
254
255 static void
256 basic_test(u_int mode)
257 {
258         uint64_t *buf;
259         int fd;
260
261         buf = common_head(&fd);
262         ATF_REQUIRE_MSG(ioctl(fd, KIOENABLE, mode) == 0,
263             "Unable to enable kcov %s",
264             mode < nitems(modes) ? modes[mode] : "unknown mode");
265
266         atomic_store_64(&buf[0], 0);
267
268         sleep(0);
269         ATF_REQUIRE_MSG(atomic_load_64(&buf[0]) != 0, "No records found");
270
271         ATF_REQUIRE_MSG(ioctl(fd, KIODISABLE, 0) == 0,
272             "Unable to disable kcov");
273
274         common_tail(fd, buf);
275 }
276
277 ATF_TC_WITHOUT_HEAD(kcov_basic_pc);
278 ATF_TC_BODY(kcov_basic_pc, tc)
279 {
280         basic_test(KCOV_MODE_TRACE_PC);
281 }
282
283 ATF_TC_WITHOUT_HEAD(kcov_basic_cmp);
284 ATF_TC_BODY(kcov_basic_cmp, tc)
285 {
286         basic_test(KCOV_MODE_TRACE_CMP);
287 }
288
289 static void *
290 thread_test_helper(void *ptr)
291 {
292         uint64_t *buf = ptr;
293
294         atomic_store_64(&buf[0], 0);
295         sleep(0);
296         ATF_REQUIRE_MSG(atomic_load_64(&buf[0]) == 0,
297             "Records changed in blocked thread");
298
299         return (NULL);
300 }
301
302 static void
303 thread_test(u_int mode)
304 {
305         pthread_t thread;
306         uint64_t *buf;
307         int fd;
308
309         buf = common_head(&fd);
310
311         ATF_REQUIRE_MSG(ioctl(fd, KIOENABLE, mode) == 0,
312             "Unable to enable kcov %s",
313             mode < nitems(modes) ? modes[mode] : "unknown mode");
314
315         pthread_create(&thread, NULL, thread_test_helper, buf);
316         pthread_join(thread, NULL);
317
318         ATF_REQUIRE_MSG(ioctl(fd, KIODISABLE, 0) == 0,
319             "Unable to disable kcov");
320
321         common_tail(fd, buf);
322 }
323
324 ATF_TC_WITHOUT_HEAD(kcov_thread_pc);
325 ATF_TC_BODY(kcov_thread_pc, tc)
326 {
327         thread_test(KCOV_MODE_TRACE_PC);
328 }
329
330 ATF_TC_WITHOUT_HEAD(kcov_thread_cmp);
331 ATF_TC_BODY(kcov_thread_cmp, tc)
332 {
333         thread_test(KCOV_MODE_TRACE_CMP);
334 }
335
336 struct multi_thread_data {
337         char *buf;
338         int fd;
339         u_int mode;
340         int thread;
341 };
342
343 static void *
344 multi_thread_test_helper(void *ptr)
345 {
346         struct multi_thread_data *data = ptr;
347
348         ATF_REQUIRE_MSG(ioctl(data->fd, KIOENABLE, data->mode) == 0,
349             "Unable to enable kcov %s in thread %d",
350             data->mode < nitems(modes) ? modes[data->mode] : "unknown mode",
351             data->thread);
352
353         atomic_store_64(&data->buf[0], 0);
354         sleep(0);
355         ATF_REQUIRE_MSG(atomic_load_64(&data->buf[0]) != 0,
356             "No records found in thread %d", data->thread);
357
358         return (NULL);
359 }
360
361 ATF_TC_WITHOUT_HEAD(kcov_enable_multi_thread);
362 ATF_TC_BODY(kcov_enable_multi_thread, t)
363 {
364         struct multi_thread_data data;
365         pthread_t thread;
366
367         data.buf = common_head(&data.fd);
368
369         /* Run the thread to completion */
370         data.thread = 1;
371         data.mode = KCOV_MODE_TRACE_PC;
372         pthread_create(&thread, NULL, multi_thread_test_helper, &data);
373         pthread_join(thread, NULL);
374
375         /* Run it again to check enable works on the same fd */
376         data.thread = 2;
377         data.mode = KCOV_MODE_TRACE_CMP;
378         pthread_create(&thread, NULL, multi_thread_test_helper, &data);
379         pthread_join(thread, NULL);
380
381         common_tail(data.fd, data.buf);
382 }
383
384 ATF_TP_ADD_TCS(tp)
385 {
386
387         ATF_TP_ADD_TC(tp, kcov_bufsize);
388         ATF_TP_ADD_TC(tp, kcov_mmap);
389         ATF_TP_ADD_TC(tp, kcov_mmap_no_munmap);
390         ATF_TP_ADD_TC(tp, kcov_mmap_no_munmap_no_close);
391         ATF_TP_ADD_TC(tp, kcov_enable);
392         ATF_TP_ADD_TC(tp, kcov_enable_no_disable);
393         ATF_TP_ADD_TC(tp, kcov_enable_no_disable_no_close);
394         ATF_TP_ADD_TC(tp, kcov_mmap_enable_thread_close);
395         ATF_TP_ADD_TC(tp, kcov_basic_pc);
396         ATF_TP_ADD_TC(tp, kcov_basic_cmp);
397         ATF_TP_ADD_TC(tp, kcov_thread_pc);
398         ATF_TP_ADD_TC(tp, kcov_thread_cmp);
399         ATF_TP_ADD_TC(tp, kcov_enable_multi_thread);
400         return (atf_no_error());
401 }