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