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