]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tests/sys/kern/kcov.c
ssh: Update to OpenSSH 9.5p1
[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 #include <sys/param.h>
34 #include <sys/ioctl.h>
35 #include <sys/kcov.h>
36 #include <sys/mman.h>
37
38 #include <machine/atomic.h>
39
40 #include <fcntl.h>
41 #include <pthread.h>
42 #include <semaphore.h>
43
44 #include <atf-c.h>
45
46 static const char *modes[] = {
47     "PC tracing",
48     "comparison tracing",
49 };
50
51 static size_t page_size;
52
53 static void
54 init_page_size(void)
55 {
56         page_size = getpagesize();
57 }
58
59 static int
60 open_kcov(void)
61 {
62         int fd;
63
64         fd = open("/dev/kcov", O_RDWR);
65         if (fd == -1)
66                 atf_tc_skip("Failed to open /dev/kcov");
67
68         return (fd);
69 }
70
71 ATF_TC(kcov_bufsize);
72 ATF_TC_HEAD(kcov_bufsize, tc)
73 {
74         init_page_size();
75 }
76
77 ATF_TC_BODY(kcov_bufsize, tc)
78 {
79         int fd;
80
81         fd = open_kcov();
82
83         ATF_CHECK(ioctl(fd, KIOSETBUFSIZE, 0) == -1);
84         ATF_CHECK(ioctl(fd, KIOSETBUFSIZE, 1) == -1);
85         ATF_CHECK(ioctl(fd, KIOSETBUFSIZE, 2) == 0);
86         ATF_CHECK(ioctl(fd, KIOSETBUFSIZE, 2) == -1);
87
88         close(fd);
89 }
90
91 ATF_TC(kcov_mmap);
92 ATF_TC_HEAD(kcov_mmap, tc)
93 {
94         init_page_size();
95 }
96
97 ATF_TC_BODY(kcov_mmap, tc)
98 {
99         void *data1, *data2;
100         int fd;
101
102         fd = open_kcov();
103
104         ATF_CHECK(mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED,
105             fd, 0) == MAP_FAILED);
106
107         ATF_REQUIRE(ioctl(fd, KIOSETBUFSIZE,
108             2 * page_size / KCOV_ENTRY_SIZE) == 0);
109
110         ATF_CHECK(mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED,
111             fd, 0) == MAP_FAILED);
112         ATF_CHECK(mmap(NULL, 3 * page_size, PROT_READ | PROT_WRITE, MAP_SHARED,
113             fd, 0) == MAP_FAILED);
114         ATF_REQUIRE((data1 = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
115             MAP_SHARED, fd, 0)) != MAP_FAILED);
116         ATF_REQUIRE((data2 = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
117             MAP_SHARED, fd, 0)) != MAP_FAILED);
118
119         *(uint64_t *)data1 = 0x123456789abcdeful;
120         ATF_REQUIRE(*(uint64_t *)data2 == 0x123456789abcdefull);
121         *(uint64_t *)data2 = 0xfedcba9876543210ul;
122         ATF_REQUIRE(*(uint64_t *)data1 == 0xfedcba9876543210ull);
123
124         munmap(data1, 2 * page_size);
125         munmap(data2, 2 * page_size);
126
127         close(fd);
128 }
129
130 /* This shouldn't panic */
131 ATF_TC(kcov_mmap_no_munmap);
132 ATF_TC_HEAD(kcov_mmap_no_munmap, tc)
133 {
134         init_page_size();
135 }
136
137 ATF_TC_BODY(kcov_mmap_no_munmap, tc)
138 {
139         int fd;
140
141         fd = open_kcov();
142
143         ATF_REQUIRE(ioctl(fd, KIOSETBUFSIZE, page_size / KCOV_ENTRY_SIZE) == 0);
144
145         ATF_CHECK(mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED,
146             fd, 0) != MAP_FAILED);
147
148         close(fd);
149 }
150
151 ATF_TC(kcov_mmap_no_munmap_no_close);
152 ATF_TC_HEAD(kcov_mmap_no_munmap_no_close, tc)
153 {
154         init_page_size();
155 }
156
157 ATF_TC_BODY(kcov_mmap_no_munmap_no_close, tc)
158 {
159         int fd;
160
161         fd = open_kcov();
162
163         ATF_REQUIRE(ioctl(fd, KIOSETBUFSIZE, page_size / KCOV_ENTRY_SIZE) == 0);
164
165         ATF_CHECK(mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED,
166             fd, 0) != MAP_FAILED);
167 }
168
169 static sem_t sem1, sem2;
170
171 static void *
172 kcov_mmap_enable_thread(void *data)
173 {
174         int fd;
175
176         fd = open_kcov();
177         *(int *)data = fd;
178
179         ATF_REQUIRE(ioctl(fd, KIOSETBUFSIZE, page_size / KCOV_ENTRY_SIZE) == 0);
180         ATF_CHECK(mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED,
181             fd, 0) != MAP_FAILED);
182         ATF_CHECK(ioctl(fd, KIOENABLE, KCOV_MODE_TRACE_PC) == 0);
183
184         sem_post(&sem1);
185         sem_wait(&sem2);
186
187         return (NULL);
188 }
189
190 ATF_TC(kcov_mmap_enable_thread_close);
191 ATF_TC_HEAD(kcov_mmap_enable_thread_close, tc)
192 {
193         init_page_size();
194 }
195
196 ATF_TC_BODY(kcov_mmap_enable_thread_close, tc)
197 {
198         pthread_t thread;
199         int fd;
200
201         sem_init(&sem1, 0, 0);
202         sem_init(&sem2, 0, 0);
203         pthread_create(&thread, NULL,
204             kcov_mmap_enable_thread, &fd);
205         sem_wait(&sem1);
206         close(fd);
207         sem_post(&sem2);
208         pthread_join(thread, NULL);
209 }
210
211 ATF_TC(kcov_enable);
212 ATF_TC_HEAD(kcov_enable, tc)
213 {
214         init_page_size();
215 }
216
217 ATF_TC_BODY(kcov_enable, tc)
218 {
219         int fd;
220
221         fd = open_kcov();
222
223         ATF_CHECK(ioctl(fd, KIOENABLE, KCOV_MODE_TRACE_PC) == -1);
224
225         ATF_REQUIRE(ioctl(fd, KIOSETBUFSIZE, page_size / KCOV_ENTRY_SIZE) == 0);
226
227         /* We need to enable before disable */
228         ATF_CHECK(ioctl(fd, KIODISABLE, 0) == -1);
229
230         /* Check enabling works only with a valid trace method */
231         ATF_CHECK(ioctl(fd, KIOENABLE, -1) == -1);
232         ATF_CHECK(ioctl(fd, KIOENABLE, KCOV_MODE_TRACE_PC) == 0);
233         ATF_CHECK(ioctl(fd, KIOENABLE, KCOV_MODE_TRACE_PC) == -1);
234         ATF_CHECK(ioctl(fd, KIOENABLE, KCOV_MODE_TRACE_CMP) == -1);
235
236         /* Disable should only be called once */
237         ATF_CHECK(ioctl(fd, KIODISABLE, 0) == 0);
238         ATF_CHECK(ioctl(fd, KIODISABLE, 0) == -1);
239
240         /* Re-enabling should also work */
241         ATF_CHECK(ioctl(fd, KIOENABLE, KCOV_MODE_TRACE_CMP) == 0);
242         ATF_CHECK(ioctl(fd, KIODISABLE, 0) == 0);
243
244         close(fd);
245 }
246
247 ATF_TC(kcov_enable_no_disable);
248 ATF_TC_HEAD(kcov_enable_no_disable, tc)
249 {
250         init_page_size();
251 }
252
253 ATF_TC_BODY(kcov_enable_no_disable, tc)
254 {
255         int fd;
256
257         fd = open_kcov();
258         ATF_REQUIRE(ioctl(fd, KIOSETBUFSIZE, page_size / KCOV_ENTRY_SIZE) == 0);
259         ATF_CHECK(ioctl(fd, KIOENABLE, KCOV_MODE_TRACE_PC) == 0);
260         close(fd);
261 }
262
263 ATF_TC(kcov_enable_no_disable_no_close);
264 ATF_TC_HEAD(kcov_enable_no_disable_no_close, tc)
265 {
266         init_page_size();
267 }
268
269 ATF_TC_BODY(kcov_enable_no_disable_no_close, tc)
270 {
271         int fd;
272
273         fd = open_kcov();
274         ATF_REQUIRE(ioctl(fd, KIOSETBUFSIZE, page_size / KCOV_ENTRY_SIZE) == 0);
275         ATF_CHECK(ioctl(fd, KIOENABLE, KCOV_MODE_TRACE_PC) == 0);
276 }
277
278 static void *
279 common_head(int *fdp)
280 {
281         void *data;
282         int fd;
283
284         fd = open_kcov();
285
286         ATF_REQUIRE_MSG(ioctl(fd, KIOSETBUFSIZE,
287             page_size / KCOV_ENTRY_SIZE) == 0,
288             "Unable to set the kcov buffer size");
289
290         data = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
291         ATF_REQUIRE_MSG(data != MAP_FAILED, "Unable to mmap the kcov buffer");
292
293         *fdp = fd;
294         return (data);
295 }
296
297 static void
298 common_tail(int fd, void *data)
299 {
300
301         ATF_REQUIRE_MSG(munmap(data, page_size) == 0,
302             "Unable to unmap the kcov buffer");
303
304         close(fd);
305 }
306
307 static void
308 basic_test(u_int mode)
309 {
310         uint64_t *buf;
311         int fd;
312
313         buf = common_head(&fd);
314         ATF_REQUIRE_MSG(ioctl(fd, KIOENABLE, mode) == 0,
315             "Unable to enable kcov %s",
316             mode < nitems(modes) ? modes[mode] : "unknown mode");
317
318         atomic_store_64(&buf[0], 0);
319
320         sleep(0);
321         ATF_REQUIRE_MSG(atomic_load_64(&buf[0]) != 0, "No records found");
322
323         ATF_REQUIRE_MSG(ioctl(fd, KIODISABLE, 0) == 0,
324             "Unable to disable kcov");
325
326         common_tail(fd, buf);
327 }
328
329 ATF_TC(kcov_basic_pc);
330 ATF_TC_HEAD(kcov_basic_pc, tc)
331 {
332         init_page_size();
333 }
334
335 ATF_TC_BODY(kcov_basic_pc, tc)
336 {
337         basic_test(KCOV_MODE_TRACE_PC);
338 }
339
340 ATF_TC(kcov_basic_cmp);
341 ATF_TC_HEAD(kcov_basic_cmp, tc)
342 {
343         init_page_size();
344 }
345
346 ATF_TC_BODY(kcov_basic_cmp, tc)
347 {
348         basic_test(KCOV_MODE_TRACE_CMP);
349 }
350
351 static void *
352 thread_test_helper(void *ptr)
353 {
354         uint64_t *buf = ptr;
355
356         atomic_store_64(&buf[0], 0);
357         sleep(0);
358         ATF_REQUIRE_MSG(atomic_load_64(&buf[0]) == 0,
359             "Records changed in blocked thread");
360
361         return (NULL);
362 }
363
364 static void
365 thread_test(u_int mode)
366 {
367         pthread_t thread;
368         uint64_t *buf;
369         int fd;
370
371         buf = common_head(&fd);
372
373         ATF_REQUIRE_MSG(ioctl(fd, KIOENABLE, mode) == 0,
374             "Unable to enable kcov %s",
375             mode < nitems(modes) ? modes[mode] : "unknown mode");
376
377         pthread_create(&thread, NULL, thread_test_helper, buf);
378         pthread_join(thread, NULL);
379
380         ATF_REQUIRE_MSG(ioctl(fd, KIODISABLE, 0) == 0,
381             "Unable to disable kcov");
382
383         common_tail(fd, buf);
384 }
385
386 ATF_TC(kcov_thread_pc);
387 ATF_TC_HEAD(kcov_thread_pc, tc)
388 {
389         init_page_size();
390 }
391
392 ATF_TC_BODY(kcov_thread_pc, tc)
393 {
394         thread_test(KCOV_MODE_TRACE_PC);
395 }
396
397 ATF_TC(kcov_thread_cmp);
398 ATF_TC_HEAD(kcov_thread_cmp, tc)
399 {
400         init_page_size();
401 }
402
403 ATF_TC_BODY(kcov_thread_cmp, tc)
404 {
405         thread_test(KCOV_MODE_TRACE_CMP);
406 }
407
408 struct multi_thread_data {
409         uint64_t *buf;
410         int fd;
411         u_int mode;
412         int thread;
413 };
414
415 static void *
416 multi_thread_test_helper(void *ptr)
417 {
418         struct multi_thread_data *data = ptr;
419
420         ATF_REQUIRE_MSG(ioctl(data->fd, KIOENABLE, data->mode) == 0,
421             "Unable to enable kcov %s in thread %d",
422             data->mode < nitems(modes) ? modes[data->mode] : "unknown mode",
423             data->thread);
424
425         atomic_store_64(&data->buf[0], 0);
426         sleep(0);
427         ATF_REQUIRE_MSG(atomic_load_64(&data->buf[0]) != 0,
428             "No records found in thread %d", data->thread);
429
430         return (NULL);
431 }
432
433 ATF_TC(kcov_enable_multi_thread);
434 ATF_TC_HEAD(kcov_enable_multi_thread, t)
435 {
436         init_page_size();
437 }
438
439 ATF_TC_BODY(kcov_enable_multi_thread, t)
440 {
441         struct multi_thread_data data;
442         pthread_t thread;
443
444         data.buf = common_head(&data.fd);
445
446         /* Run the thread to completion */
447         data.thread = 1;
448         data.mode = KCOV_MODE_TRACE_PC;
449         pthread_create(&thread, NULL, multi_thread_test_helper, &data);
450         pthread_join(thread, NULL);
451
452         /* Run it again to check enable works on the same fd */
453         data.thread = 2;
454         data.mode = KCOV_MODE_TRACE_CMP;
455         pthread_create(&thread, NULL, multi_thread_test_helper, &data);
456         pthread_join(thread, NULL);
457
458         common_tail(data.fd, data.buf);
459 }
460
461 ATF_TP_ADD_TCS(tp)
462 {
463
464         ATF_TP_ADD_TC(tp, kcov_bufsize);
465         ATF_TP_ADD_TC(tp, kcov_mmap);
466         ATF_TP_ADD_TC(tp, kcov_mmap_no_munmap);
467         ATF_TP_ADD_TC(tp, kcov_mmap_no_munmap_no_close);
468         ATF_TP_ADD_TC(tp, kcov_enable);
469         ATF_TP_ADD_TC(tp, kcov_enable_no_disable);
470         ATF_TP_ADD_TC(tp, kcov_enable_no_disable_no_close);
471         ATF_TP_ADD_TC(tp, kcov_mmap_enable_thread_close);
472         ATF_TP_ADD_TC(tp, kcov_basic_pc);
473         ATF_TP_ADD_TC(tp, kcov_basic_cmp);
474         ATF_TP_ADD_TC(tp, kcov_thread_pc);
475         ATF_TP_ADD_TC(tp, kcov_thread_cmp);
476         ATF_TP_ADD_TC(tp, kcov_enable_multi_thread);
477         return (atf_no_error());
478 }