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