2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2018, 2019 Andrew Turner
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.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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
32 #include <sys/cdefs.h>
33 #include <sys/param.h>
34 #include <sys/ioctl.h>
38 #include <machine/atomic.h>
42 #include <semaphore.h>
46 static const char *modes[] = {
51 static size_t page_size;
56 page_size = getpagesize();
64 fd = open("/dev/kcov", O_RDWR);
66 atf_tc_skip("Failed to open /dev/kcov");
72 ATF_TC_HEAD(kcov_bufsize, tc)
77 ATF_TC_BODY(kcov_bufsize, tc)
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);
92 ATF_TC_HEAD(kcov_mmap, tc)
97 ATF_TC_BODY(kcov_mmap, tc)
104 ATF_CHECK(mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED,
105 fd, 0) == MAP_FAILED);
107 ATF_REQUIRE(ioctl(fd, KIOSETBUFSIZE,
108 2 * page_size / KCOV_ENTRY_SIZE) == 0);
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);
119 *(uint64_t *)data1 = 0x123456789abcdeful;
120 ATF_REQUIRE(*(uint64_t *)data2 == 0x123456789abcdefull);
121 *(uint64_t *)data2 = 0xfedcba9876543210ul;
122 ATF_REQUIRE(*(uint64_t *)data1 == 0xfedcba9876543210ull);
124 munmap(data1, 2 * page_size);
125 munmap(data2, 2 * page_size);
130 /* This shouldn't panic */
131 ATF_TC(kcov_mmap_no_munmap);
132 ATF_TC_HEAD(kcov_mmap_no_munmap, tc)
137 ATF_TC_BODY(kcov_mmap_no_munmap, tc)
143 ATF_REQUIRE(ioctl(fd, KIOSETBUFSIZE, page_size / KCOV_ENTRY_SIZE) == 0);
145 ATF_CHECK(mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED,
146 fd, 0) != MAP_FAILED);
151 ATF_TC(kcov_mmap_no_munmap_no_close);
152 ATF_TC_HEAD(kcov_mmap_no_munmap_no_close, tc)
157 ATF_TC_BODY(kcov_mmap_no_munmap_no_close, tc)
163 ATF_REQUIRE(ioctl(fd, KIOSETBUFSIZE, page_size / KCOV_ENTRY_SIZE) == 0);
165 ATF_CHECK(mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED,
166 fd, 0) != MAP_FAILED);
169 static sem_t sem1, sem2;
172 kcov_mmap_enable_thread(void *data)
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);
190 ATF_TC(kcov_mmap_enable_thread_close);
191 ATF_TC_HEAD(kcov_mmap_enable_thread_close, tc)
196 ATF_TC_BODY(kcov_mmap_enable_thread_close, tc)
201 sem_init(&sem1, 0, 0);
202 sem_init(&sem2, 0, 0);
203 pthread_create(&thread, NULL,
204 kcov_mmap_enable_thread, &fd);
208 pthread_join(thread, NULL);
212 ATF_TC_HEAD(kcov_enable, tc)
217 ATF_TC_BODY(kcov_enable, tc)
223 ATF_CHECK(ioctl(fd, KIOENABLE, KCOV_MODE_TRACE_PC) == -1);
225 ATF_REQUIRE(ioctl(fd, KIOSETBUFSIZE, page_size / KCOV_ENTRY_SIZE) == 0);
227 /* We need to enable before disable */
228 ATF_CHECK(ioctl(fd, KIODISABLE, 0) == -1);
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);
236 /* Disable should only be called once */
237 ATF_CHECK(ioctl(fd, KIODISABLE, 0) == 0);
238 ATF_CHECK(ioctl(fd, KIODISABLE, 0) == -1);
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);
247 ATF_TC(kcov_enable_no_disable);
248 ATF_TC_HEAD(kcov_enable_no_disable, tc)
253 ATF_TC_BODY(kcov_enable_no_disable, tc)
258 ATF_REQUIRE(ioctl(fd, KIOSETBUFSIZE, page_size / KCOV_ENTRY_SIZE) == 0);
259 ATF_CHECK(ioctl(fd, KIOENABLE, KCOV_MODE_TRACE_PC) == 0);
263 ATF_TC(kcov_enable_no_disable_no_close);
264 ATF_TC_HEAD(kcov_enable_no_disable_no_close, tc)
269 ATF_TC_BODY(kcov_enable_no_disable_no_close, tc)
274 ATF_REQUIRE(ioctl(fd, KIOSETBUFSIZE, page_size / KCOV_ENTRY_SIZE) == 0);
275 ATF_CHECK(ioctl(fd, KIOENABLE, KCOV_MODE_TRACE_PC) == 0);
279 common_head(int *fdp)
286 ATF_REQUIRE_MSG(ioctl(fd, KIOSETBUFSIZE,
287 page_size / KCOV_ENTRY_SIZE) == 0,
288 "Unable to set the kcov buffer size");
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");
298 common_tail(int fd, void *data)
301 ATF_REQUIRE_MSG(munmap(data, page_size) == 0,
302 "Unable to unmap the kcov buffer");
308 basic_test(u_int mode)
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");
318 atomic_store_64(&buf[0], 0);
321 ATF_REQUIRE_MSG(atomic_load_64(&buf[0]) != 0, "No records found");
323 ATF_REQUIRE_MSG(ioctl(fd, KIODISABLE, 0) == 0,
324 "Unable to disable kcov");
326 common_tail(fd, buf);
329 ATF_TC(kcov_basic_pc);
330 ATF_TC_HEAD(kcov_basic_pc, tc)
335 ATF_TC_BODY(kcov_basic_pc, tc)
337 basic_test(KCOV_MODE_TRACE_PC);
340 ATF_TC(kcov_basic_cmp);
341 ATF_TC_HEAD(kcov_basic_cmp, tc)
346 ATF_TC_BODY(kcov_basic_cmp, tc)
348 basic_test(KCOV_MODE_TRACE_CMP);
352 thread_test_helper(void *ptr)
356 atomic_store_64(&buf[0], 0);
358 ATF_REQUIRE_MSG(atomic_load_64(&buf[0]) == 0,
359 "Records changed in blocked thread");
365 thread_test(u_int mode)
371 buf = common_head(&fd);
373 ATF_REQUIRE_MSG(ioctl(fd, KIOENABLE, mode) == 0,
374 "Unable to enable kcov %s",
375 mode < nitems(modes) ? modes[mode] : "unknown mode");
377 pthread_create(&thread, NULL, thread_test_helper, buf);
378 pthread_join(thread, NULL);
380 ATF_REQUIRE_MSG(ioctl(fd, KIODISABLE, 0) == 0,
381 "Unable to disable kcov");
383 common_tail(fd, buf);
386 ATF_TC(kcov_thread_pc);
387 ATF_TC_HEAD(kcov_thread_pc, tc)
392 ATF_TC_BODY(kcov_thread_pc, tc)
394 thread_test(KCOV_MODE_TRACE_PC);
397 ATF_TC(kcov_thread_cmp);
398 ATF_TC_HEAD(kcov_thread_cmp, tc)
403 ATF_TC_BODY(kcov_thread_cmp, tc)
405 thread_test(KCOV_MODE_TRACE_CMP);
408 struct multi_thread_data {
416 multi_thread_test_helper(void *ptr)
418 struct multi_thread_data *data = ptr;
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",
425 atomic_store_64(&data->buf[0], 0);
427 ATF_REQUIRE_MSG(atomic_load_64(&data->buf[0]) != 0,
428 "No records found in thread %d", data->thread);
433 ATF_TC(kcov_enable_multi_thread);
434 ATF_TC_HEAD(kcov_enable_multi_thread, t)
439 ATF_TC_BODY(kcov_enable_multi_thread, t)
441 struct multi_thread_data data;
444 data.buf = common_head(&data.fd);
446 /* Run the thread to completion */
448 data.mode = KCOV_MODE_TRACE_PC;
449 pthread_create(&thread, NULL, multi_thread_test_helper, &data);
450 pthread_join(thread, NULL);
452 /* Run it again to check enable works on the same fd */
454 data.mode = KCOV_MODE_TRACE_CMP;
455 pthread_create(&thread, NULL, multi_thread_test_helper, &data);
456 pthread_join(thread, NULL);
458 common_tail(data.fd, data.buf);
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());