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 __FBSDID("$FreeBSD$");
35 #include <sys/param.h>
36 #include <sys/ioctl.h>
40 #include <machine/atomic.h>
44 #include <semaphore.h>
48 static const char *modes[] = {
58 fd = open("/dev/kcov", O_RDWR);
60 atf_tc_skip("Failed to open /dev/kcov");
65 ATF_TC_WITHOUT_HEAD(kcov_bufsize);
66 ATF_TC_BODY(kcov_bufsize, tc)
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);
80 ATF_TC_WITHOUT_HEAD(kcov_mmap);
81 ATF_TC_BODY(kcov_mmap, tc)
88 ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
89 fd, 0) == MAP_FAILED);
91 ATF_REQUIRE(ioctl(fd, KIOSETBUFSIZE,
92 2 * PAGE_SIZE / sizeof(uint64_t)) == 0);
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);
103 munmap(data, 2 * PAGE_SIZE);
108 /* This shouldn't panic */
109 ATF_TC_WITHOUT_HEAD(kcov_mmap_no_munmap);
110 ATF_TC_BODY(kcov_mmap_no_munmap, tc)
116 ATF_REQUIRE(ioctl(fd, KIOSETBUFSIZE, PAGE_SIZE / sizeof(uint64_t)) ==0);
118 ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
119 fd, 0) != MAP_FAILED);
124 ATF_TC_WITHOUT_HEAD(kcov_mmap_no_munmap_no_close);
125 ATF_TC_BODY(kcov_mmap_no_munmap_no_close, tc)
131 ATF_REQUIRE(ioctl(fd, KIOSETBUFSIZE, PAGE_SIZE / sizeof(uint64_t)) ==0);
133 ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
134 fd, 0) != MAP_FAILED);
137 static sem_t sem1, sem2;
140 kcov_mmap_enable_thread(void *data)
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);
158 ATF_TC_WITHOUT_HEAD(kcov_mmap_enable_thread_close);
159 ATF_TC_BODY(kcov_mmap_enable_thread_close, tc)
164 sem_init(&sem1, 0, 0);
165 sem_init(&sem2, 0, 0);
166 pthread_create(&thread, NULL,
167 kcov_mmap_enable_thread, &fd);
171 pthread_join(thread, NULL);
174 ATF_TC_WITHOUT_HEAD(kcov_enable);
175 ATF_TC_BODY(kcov_enable, tc)
181 ATF_CHECK(ioctl(fd, KIOENABLE, KCOV_MODE_TRACE_PC) == -1);
183 ATF_REQUIRE(ioctl(fd, KIOSETBUFSIZE, PAGE_SIZE / sizeof(uint64_t)) ==0);
185 /* We need to enable before disable */
186 ATF_CHECK(ioctl(fd, KIODISABLE, 0) == -1);
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);
194 /* Disable should only be called once */
195 ATF_CHECK(ioctl(fd, KIODISABLE, 0) == 0);
196 ATF_CHECK(ioctl(fd, KIODISABLE, 0) == -1);
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);
205 ATF_TC_WITHOUT_HEAD(kcov_enable_no_disable);
206 ATF_TC_BODY(kcov_enable_no_disable, tc)
211 ATF_REQUIRE(ioctl(fd, KIOSETBUFSIZE, PAGE_SIZE / sizeof(uint64_t)) ==0);
212 ATF_CHECK(ioctl(fd, KIOENABLE, KCOV_MODE_TRACE_PC) == 0);
216 ATF_TC_WITHOUT_HEAD(kcov_enable_no_disable_no_close);
217 ATF_TC_BODY(kcov_enable_no_disable_no_close, tc)
222 ATF_REQUIRE(ioctl(fd, KIOSETBUFSIZE, PAGE_SIZE / sizeof(uint64_t)) ==0);
223 ATF_CHECK(ioctl(fd, KIOENABLE, KCOV_MODE_TRACE_PC) == 0);
227 common_head(int *fdp)
234 ATF_REQUIRE_MSG(ioctl(fd, KIOSETBUFSIZE,
235 PAGE_SIZE / sizeof(uint64_t)) == 0,
236 "Unable to set the kcov buffer size");
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");
246 common_tail(int fd, void *data)
249 ATF_REQUIRE_MSG(munmap(data, PAGE_SIZE) == 0,
250 "Unable to unmap the kcov buffer");
256 basic_test(u_int mode)
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");
266 atomic_store_64(&buf[0], 0);
269 ATF_REQUIRE_MSG(atomic_load_64(&buf[0]) != 0, "No records found");
271 ATF_REQUIRE_MSG(ioctl(fd, KIODISABLE, 0) == 0,
272 "Unable to disable kcov");
274 common_tail(fd, buf);
277 ATF_TC_WITHOUT_HEAD(kcov_basic_pc);
278 ATF_TC_BODY(kcov_basic_pc, tc)
280 basic_test(KCOV_MODE_TRACE_PC);
283 ATF_TC_WITHOUT_HEAD(kcov_basic_cmp);
284 ATF_TC_BODY(kcov_basic_cmp, tc)
286 basic_test(KCOV_MODE_TRACE_CMP);
290 thread_test_helper(void *ptr)
294 atomic_store_64(&buf[0], 0);
296 ATF_REQUIRE_MSG(atomic_load_64(&buf[0]) == 0,
297 "Records changed in blocked thread");
303 thread_test(u_int mode)
309 buf = common_head(&fd);
311 ATF_REQUIRE_MSG(ioctl(fd, KIOENABLE, mode) == 0,
312 "Unable to enable kcov %s",
313 mode < nitems(modes) ? modes[mode] : "unknown mode");
315 pthread_create(&thread, NULL, thread_test_helper, buf);
316 pthread_join(thread, NULL);
318 ATF_REQUIRE_MSG(ioctl(fd, KIODISABLE, 0) == 0,
319 "Unable to disable kcov");
321 common_tail(fd, buf);
324 ATF_TC_WITHOUT_HEAD(kcov_thread_pc);
325 ATF_TC_BODY(kcov_thread_pc, tc)
327 thread_test(KCOV_MODE_TRACE_PC);
330 ATF_TC_WITHOUT_HEAD(kcov_thread_cmp);
331 ATF_TC_BODY(kcov_thread_cmp, tc)
333 thread_test(KCOV_MODE_TRACE_CMP);
336 struct multi_thread_data {
344 multi_thread_test_helper(void *ptr)
346 struct multi_thread_data *data = ptr;
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",
353 atomic_store_64(&data->buf[0], 0);
355 ATF_REQUIRE_MSG(atomic_load_64(&data->buf[0]) != 0,
356 "No records found in thread %d", data->thread);
361 ATF_TC_WITHOUT_HEAD(kcov_enable_multi_thread);
362 ATF_TC_BODY(kcov_enable_multi_thread, t)
364 struct multi_thread_data data;
367 data.buf = common_head(&data.fd);
369 /* Run the thread to completion */
371 data.mode = KCOV_MODE_TRACE_PC;
372 pthread_create(&thread, NULL, multi_thread_test_helper, &data);
373 pthread_join(thread, NULL);
375 /* Run it again to check enable works on the same fd */
377 data.mode = KCOV_MODE_TRACE_CMP;
378 pthread_create(&thread, NULL, multi_thread_test_helper, &data);
379 pthread_join(thread, NULL);
381 common_tail(data.fd, data.buf);
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());