Home | History | Annotate | Line # | Download | only in modules
t_kcov.c revision 1.5
      1 /*
      2  * SPDX-License-Identifier: BSD-2-Clause
      3  *
      4  * Copyright (c) 2018, 2019 Andrew Turner
      5  *
      6  * This software was developed by SRI International and the University of
      7  * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
      8  * ("CTSRD"), as part of the DARPA CRASH research programme.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 #include <sys/cdefs.h>
     32 
     33 #include <sys/param.h>
     34 #include <sys/ioctl.h>
     35 #include <sys/kcov.h>
     36 #include <sys/mman.h>
     37 
     38 #include <errno.h>
     39 #include <fcntl.h>
     40 #include <pthread.h>
     41 #include <semaphore.h>
     42 
     43 #include <atf-c.h>
     44 
     45 #define PAGE_SIZE sysconf(_SC_PAGESIZE)
     46 
     47 static int
     48 open_kcov(void)
     49 {
     50 	int fd;
     51 
     52 	fd = open("/dev/kcov", O_RDWR);
     53 	if (fd == -1)
     54 		atf_tc_skip("Failed to open /dev/kcov");
     55 
     56 	return fd;
     57 }
     58 
     59 ATF_TC_WITHOUT_HEAD(kcov_multiopen);
     60 ATF_TC_BODY(kcov_multiopen, tc)
     61 {
     62 	int fd1, fd2;
     63 	fd1 = open_kcov();
     64 
     65 	fd2 = open("/dev/kcov", O_RDWR);
     66 	ATF_REQUIRE(fd2 != -1);
     67 
     68 	close(fd1);
     69 	close(fd2);
     70 }
     71 
     72 ATF_TC_WITHOUT_HEAD(kcov_open_close_open);
     73 ATF_TC_BODY(kcov_open_close_open, tc)
     74 {
     75 	int fd;
     76 
     77 	fd = open_kcov();
     78 	close(fd);
     79 	fd = open("/dev/kcov", O_RDWR);
     80 	ATF_REQUIRE(fd != -1);
     81 
     82 	close(fd);
     83 }
     84 
     85 ATF_TC_WITHOUT_HEAD(kcov_bufsize);
     86 ATF_TC_BODY(kcov_bufsize, tc)
     87 {
     88 	int fd;
     89 	uint64_t size;
     90 	fd = open_kcov();
     91 
     92 	size = 0;
     93 	ATF_CHECK(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) == -1);
     94 	size = 2;
     95 	ATF_CHECK(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) == 0);
     96 
     97 	close(fd);
     98 }
     99 
    100 ATF_TC_WITHOUT_HEAD(kcov_mmap);
    101 ATF_TC_BODY(kcov_mmap, tc)
    102 {
    103 	void *data;
    104 	int fd;
    105 	uint64_t size = 2 * PAGE_SIZE / KCOV_ENTRY_SIZE;
    106 
    107 	fd = open_kcov();
    108 
    109 	ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
    110 	    fd, 0) == MAP_FAILED);
    111 
    112 	ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) == 0);
    113 
    114 	ATF_REQUIRE((data = mmap(NULL, 2 * PAGE_SIZE, PROT_READ | PROT_WRITE,
    115 	    MAP_SHARED, fd, 0)) != MAP_FAILED);
    116 
    117 	munmap(data, 2 * PAGE_SIZE);
    118 
    119 	close(fd);
    120 }
    121 
    122 /* This shouldn't panic */
    123 ATF_TC_WITHOUT_HEAD(kcov_mmap_no_munmap);
    124 ATF_TC_BODY(kcov_mmap_no_munmap, tc)
    125 {
    126 	int fd;
    127 	uint64_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
    128 
    129 	fd = open_kcov();
    130 
    131 	ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
    132 
    133 	ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
    134 	    fd, 0) != MAP_FAILED);
    135 
    136 	close(fd);
    137 }
    138 
    139 ATF_TC_WITHOUT_HEAD(kcov_mmap_no_munmap_no_close);
    140 ATF_TC_BODY(kcov_mmap_no_munmap_no_close, tc)
    141 {
    142 	int fd;
    143 	uint64_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
    144 
    145 	fd = open_kcov();
    146 
    147 	ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
    148 
    149 	ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
    150 	    fd, 0) != MAP_FAILED);
    151 }
    152 
    153 static sem_t sem1, sem2;
    154 
    155 static void *
    156 kcov_mmap_enable_thread(void *data)
    157 {
    158 	int fd;
    159 	uint64_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
    160 
    161 	fd = open_kcov();
    162 	*(int *)data = fd;
    163 
    164 	ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
    165 	ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
    166 	    fd, 0) != MAP_FAILED);
    167 	ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE) == 0);
    168 
    169 	sem_post(&sem1);
    170 	sem_wait(&sem2);
    171 
    172 	return NULL;
    173 }
    174 
    175 ATF_TC_WITHOUT_HEAD(kcov_mmap_enable_thread_close);
    176 ATF_TC_BODY(kcov_mmap_enable_thread_close, tc)
    177 {
    178 	pthread_t thread;
    179 	int fd;
    180 
    181 	sem_init(&sem1, 0, 0);
    182 	sem_init(&sem2, 0, 0);
    183 	pthread_create(&thread, NULL,
    184 	    kcov_mmap_enable_thread, &fd);
    185 	sem_wait(&sem1);
    186 	close(fd);
    187 	sem_post(&sem2);
    188 	pthread_join(thread, NULL);
    189 }
    190 
    191 ATF_TC_WITHOUT_HEAD(kcov_enable);
    192 ATF_TC_BODY(kcov_enable, tc)
    193 {
    194 	int fd;
    195 	uint64_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
    196 
    197 	fd = open_kcov();
    198 
    199 	ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE) == -1);
    200 
    201 	ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
    202 
    203 	/* We need to enable before disable */
    204 	ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == -1);
    205 
    206 	/* Check enabling works only with a valid trace method */
    207 	ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE) == 0);
    208 	ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE) == -1);
    209 
    210 	/* Disable should only be called once */
    211 	ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == 0);
    212 	ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == -1);
    213 
    214 	/* Re-enabling should also work */
    215 	ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE) == 0);
    216 	ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == 0);
    217 
    218 	close(fd);
    219 }
    220 
    221 ATF_TC_WITHOUT_HEAD(kcov_enable_no_disable);
    222 ATF_TC_BODY(kcov_enable_no_disable, tc)
    223 {
    224 	int fd;
    225 	uint64_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
    226 
    227 	fd = open_kcov();
    228 	ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
    229 	ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE) == 0);
    230 	close(fd);
    231 }
    232 
    233 ATF_TC_WITHOUT_HEAD(kcov_enable_no_disable_no_close);
    234 ATF_TC_BODY(kcov_enable_no_disable_no_close, tc)
    235 {
    236 	int fd;
    237 	uint64_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
    238 
    239 	fd = open_kcov();
    240 	ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
    241 	ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE) == 0);
    242 }
    243 
    244 static void *
    245 common_head(int *fdp)
    246 {
    247 	void *data;
    248 	int fd;
    249 	uint64_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
    250 
    251 	fd = open_kcov();
    252 
    253 	ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) == 0,
    254 	    "Unable to set the kcov buffer size");
    255 
    256 	data = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    257 	ATF_REQUIRE_MSG(data != MAP_FAILED, "Unable to mmap the kcov buffer");
    258 
    259 	*fdp = fd;
    260 	return data;
    261 }
    262 
    263 static void
    264 common_tail(int fd, kcov_int_t *data)
    265 {
    266 
    267 	ATF_REQUIRE_MSG(munmap(__UNVOLATILE(data), PAGE_SIZE) == 0,
    268 	    "Unable to unmap the kcov buffer");
    269 
    270 	close(fd);
    271 }
    272 
    273 ATF_TC_WITHOUT_HEAD(kcov_basic);
    274 ATF_TC_BODY(kcov_basic, tc)
    275 {
    276 	kcov_int_t *buf;
    277 	int fd;
    278 
    279 	buf = common_head(&fd);
    280 	ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_ENABLE) == 0,
    281 	    "Unable to enable kcov ");
    282 
    283 	KCOV_STORE(buf[0], 0);
    284 
    285 	sleep(0);
    286 	ATF_REQUIRE_MSG(KCOV_LOAD(buf[0]) != 0, "No records found");
    287 
    288 	ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_DISABLE) == 0,
    289 	    "Unable to disable kcov");
    290 
    291 	common_tail(fd, buf);
    292 }
    293 
    294 ATF_TC_WITHOUT_HEAD(kcov_multienable_on_the_same_thread);
    295 ATF_TC_BODY(kcov_multienable_on_the_same_thread, tc)
    296 {
    297 	kcov_int_t *buf1, *buf2;
    298 	int fd1, fd2;
    299 
    300 	buf1 = common_head(&fd1);
    301 	buf2 = common_head(&fd2);
    302 	ATF_REQUIRE_MSG(ioctl(fd1, KCOV_IOC_ENABLE) == 0,
    303 	    "Unable to enable kcov");
    304 	ATF_REQUIRE_ERRNO(EBUSY, ioctl(fd2, KCOV_IOC_ENABLE) != 0);
    305 
    306 	ATF_REQUIRE_MSG(ioctl(fd1, KCOV_IOC_DISABLE) == 0,
    307 	    "Unable to disable kcov");
    308 
    309 	common_tail(fd1, buf1);
    310 	common_tail(fd2, buf2);
    311 }
    312 
    313 static void *
    314 thread_buffer_access_test_helper(void *ptr)
    315 {
    316 	kcov_int_t *buf = ptr;
    317 
    318 	/* Test mapped buffer access from a custom thread */
    319 	KCOV_STORE(buf[0], KCOV_LOAD(buf[0]));
    320 
    321 	return NULL;
    322 }
    323 
    324 ATF_TC_WITHOUT_HEAD(kcov_buffer_access_from_custom_thread);
    325 ATF_TC_BODY(kcov_buffer_access_from_custom_thread, tc)
    326 {
    327 	pthread_t thread;
    328 	kcov_int_t *buf;
    329 	int fd;
    330 
    331 	buf = common_head(&fd);
    332 
    333 	ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_ENABLE) == 0,
    334 	    "Unable to enable kcov ");
    335 
    336 	pthread_create(&thread, NULL, thread_buffer_access_test_helper,
    337 	    __UNVOLATILE(buf));
    338 	pthread_join(thread, NULL);
    339 
    340 	ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_DISABLE) == 0,
    341 	    "Unable to disable kcov");
    342 
    343 	common_tail(fd, buf);
    344 }
    345 
    346 static void *
    347 thread_test_helper(void *ptr)
    348 {
    349 	volatile int i;
    350 
    351 	/* It does not matter what operation is in action. */
    352 	for (i = 0; i < 1000; i++) {
    353 		if (getpid() == 0)
    354 			break;
    355 	}
    356 
    357 	return NULL;
    358 }
    359 
    360 ATF_TC_WITHOUT_HEAD(kcov_thread);
    361 ATF_TC_BODY(kcov_thread, tc)
    362 {
    363 	pthread_t thread;
    364 	kcov_int_t *buf;
    365 	int fd;
    366 	volatile int i;
    367 
    368 	buf = common_head(&fd);
    369 
    370 	ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_ENABLE) == 0,
    371 	    "Unable to enable kcov ");
    372 
    373 	/* The thread does something, does not matter what exactly. */
    374 	pthread_create(&thread, NULL, thread_test_helper, __UNVOLATILE(buf));
    375 
    376 	KCOV_STORE(buf[0], 0);
    377 	for (i = 0; i < 10000; i++)
    378 		continue;
    379 	ATF_REQUIRE_EQ_MSG(KCOV_LOAD(buf[0]), 0,
    380 	    "Records changed in blocked thread");
    381 
    382 	pthread_join(thread, NULL);
    383 
    384 	ATF_REQUIRE_EQ_MSG(ioctl(fd, KCOV_IOC_DISABLE), 0,
    385 	    "Unable to disable kcov");
    386 
    387 	common_tail(fd, buf);
    388 }
    389 
    390 static void *
    391 multiple_threads_helper(void *ptr __unused)
    392 {
    393 	kcov_int_t *buf;
    394 	int fd;
    395 
    396 	buf = common_head(&fd);
    397 	ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_ENABLE) == 0,
    398 	    "Unable to enable kcov ");
    399 
    400 	KCOV_STORE(buf[0], 0);
    401 
    402 	sleep(0);
    403 	ATF_REQUIRE_MSG(KCOV_LOAD(buf[0]) != 0, "No records found");
    404 
    405 	ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_DISABLE) == 0,
    406 	    "Unable to disable kcov");
    407 
    408 	common_tail(fd, buf);
    409 
    410 	return NULL;
    411 }
    412 
    413 static void
    414 kcov_multiple_threads(size_t N)
    415 {
    416 	pthread_t thread[32];
    417 	size_t i;
    418 
    419 	ATF_REQUIRE(__arraycount(thread) >= N);
    420 
    421 	for (i = 0; i < __arraycount(thread); i++)
    422 		pthread_create(&thread[i], NULL, multiple_threads_helper, NULL);
    423 
    424 	for (i = 0; i < __arraycount(thread); i++)
    425 		pthread_join(thread[i], NULL);
    426 }
    427 
    428 #define KCOV_MULTIPLE_THREADS(n)		\
    429 ATF_TC_WITHOUT_HEAD(kcov_multiple_threads##n);	\
    430 ATF_TC_BODY(kcov_multiple_threads##n, tc)	\
    431 {						\
    432 						\
    433 	kcov_multiple_threads(n);		\
    434 }
    435 
    436 KCOV_MULTIPLE_THREADS(2)
    437 KCOV_MULTIPLE_THREADS(4)
    438 KCOV_MULTIPLE_THREADS(8)
    439 KCOV_MULTIPLE_THREADS(16)
    440 KCOV_MULTIPLE_THREADS(32)
    441 
    442 ATF_TP_ADD_TCS(tp)
    443 {
    444 
    445 	ATF_TP_ADD_TC(tp, kcov_multiopen);
    446 	ATF_TP_ADD_TC(tp, kcov_open_close_open);
    447 	ATF_TP_ADD_TC(tp, kcov_bufsize);
    448 	ATF_TP_ADD_TC(tp, kcov_mmap);
    449 	ATF_TP_ADD_TC(tp, kcov_mmap_no_munmap);
    450 	ATF_TP_ADD_TC(tp, kcov_mmap_no_munmap_no_close);
    451 	ATF_TP_ADD_TC(tp, kcov_enable);
    452 	ATF_TP_ADD_TC(tp, kcov_enable_no_disable);
    453 	ATF_TP_ADD_TC(tp, kcov_enable_no_disable_no_close);
    454 	ATF_TP_ADD_TC(tp, kcov_mmap_enable_thread_close);
    455 	ATF_TP_ADD_TC(tp, kcov_basic);
    456 	ATF_TP_ADD_TC(tp, kcov_multienable_on_the_same_thread);
    457 	ATF_TP_ADD_TC(tp, kcov_buffer_access_from_custom_thread);
    458 	ATF_TP_ADD_TC(tp, kcov_thread);
    459 	ATF_TP_ADD_TC(tp, kcov_multiple_threads2);
    460 	ATF_TP_ADD_TC(tp, kcov_multiple_threads4);
    461 	ATF_TP_ADD_TC(tp, kcov_multiple_threads8);
    462 	ATF_TP_ADD_TC(tp, kcov_multiple_threads16);
    463 	ATF_TP_ADD_TC(tp, kcov_multiple_threads32);
    464 	return atf_no_error();
    465 }
    466