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