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