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