Home | History | Annotate | Line # | Download | only in modules
t_kcov.c revision 1.4
      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 <fcntl.h>
     39 #include <pthread.h>
     40 #include <semaphore.h>
     41 
     42 #include <atf-c.h>
     43 
     44 #define PAGE_SIZE sysconf(_SC_PAGESIZE)
     45 
     46 static int
     47 open_kcov(void)
     48 {
     49 	int fd;
     50 
     51 	fd = open("/dev/kcov", O_RDWR);
     52 	if (fd == -1)
     53 		atf_tc_skip("Failed to open /dev/kcov");
     54 
     55 	return fd;
     56 }
     57 
     58 ATF_TC_WITHOUT_HEAD(kcov_bufsize);
     59 ATF_TC_BODY(kcov_bufsize, tc)
     60 {
     61 	int fd;
     62 	kcov_int_t size;
     63 	fd = open_kcov();
     64 
     65 	size = 0;
     66 	ATF_CHECK(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) == -1);
     67 	size = 2;
     68 	ATF_CHECK(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) == 0);
     69 
     70 	close(fd);
     71 }
     72 
     73 ATF_TC_WITHOUT_HEAD(kcov_mmap);
     74 ATF_TC_BODY(kcov_mmap, tc)
     75 {
     76 	void *data;
     77 	int fd;
     78 	kcov_int_t size = 2 * PAGE_SIZE / KCOV_ENTRY_SIZE;
     79 
     80 	fd = open_kcov();
     81 
     82 	ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
     83 	    fd, 0) == MAP_FAILED);
     84 
     85 	ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) == 0);
     86 
     87 	ATF_REQUIRE((data = mmap(NULL, 2 * PAGE_SIZE, PROT_READ | PROT_WRITE,
     88 	    MAP_SHARED, fd, 0)) != MAP_FAILED);
     89 
     90 	munmap(data, 2 * PAGE_SIZE);
     91 
     92 	close(fd);
     93 }
     94 
     95 /* This shouldn't panic */
     96 ATF_TC_WITHOUT_HEAD(kcov_mmap_no_munmap);
     97 ATF_TC_BODY(kcov_mmap_no_munmap, tc)
     98 {
     99 	int fd;
    100 	kcov_int_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
    101 
    102 	fd = open_kcov();
    103 
    104 	ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
    105 
    106 	ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
    107 	    fd, 0) != MAP_FAILED);
    108 
    109 	close(fd);
    110 }
    111 
    112 ATF_TC_WITHOUT_HEAD(kcov_mmap_no_munmap_no_close);
    113 ATF_TC_BODY(kcov_mmap_no_munmap_no_close, tc)
    114 {
    115 	int fd;
    116 	kcov_int_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
    117 
    118 	fd = open_kcov();
    119 
    120 	ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
    121 
    122 	ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
    123 	    fd, 0) != MAP_FAILED);
    124 }
    125 
    126 static sem_t sem1, sem2;
    127 
    128 static void *
    129 kcov_mmap_enable_thread(void *data)
    130 {
    131 	int fd;
    132 	kcov_int_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
    133 
    134 	fd = open_kcov();
    135 	*(int *)data = fd;
    136 
    137 	ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
    138 	ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
    139 	    fd, 0) != MAP_FAILED);
    140 	ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE) == 0);
    141 
    142 	sem_post(&sem1);
    143 	sem_wait(&sem2);
    144 
    145 	return NULL;
    146 }
    147 
    148 ATF_TC_WITHOUT_HEAD(kcov_mmap_enable_thread_close);
    149 ATF_TC_BODY(kcov_mmap_enable_thread_close, tc)
    150 {
    151 	pthread_t thread;
    152 	int fd;
    153 
    154 	sem_init(&sem1, 0, 0);
    155 	sem_init(&sem2, 0, 0);
    156 	pthread_create(&thread, NULL,
    157 	    kcov_mmap_enable_thread, &fd);
    158 	sem_wait(&sem1);
    159 	close(fd);
    160 	sem_post(&sem2);
    161 	pthread_join(thread, NULL);
    162 }
    163 
    164 ATF_TC_WITHOUT_HEAD(kcov_enable);
    165 ATF_TC_BODY(kcov_enable, tc)
    166 {
    167 	int fd;
    168 	kcov_int_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
    169 
    170 	fd = open_kcov();
    171 
    172 	ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE) == -1);
    173 
    174 	ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
    175 
    176 	/* We need to enable before disable */
    177 	ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == -1);
    178 
    179 	/* Check enabling works only with a valid trace method */
    180 	ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE) == 0);
    181 	ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE) == -1);
    182 
    183 	/* Disable should only be called once */
    184 	ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == 0);
    185 	ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == -1);
    186 
    187 	/* Re-enabling should also work */
    188 	ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE) == 0);
    189 	ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == 0);
    190 
    191 	close(fd);
    192 }
    193 
    194 ATF_TC_WITHOUT_HEAD(kcov_enable_no_disable);
    195 ATF_TC_BODY(kcov_enable_no_disable, tc)
    196 {
    197 	int fd;
    198 	kcov_int_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
    199 
    200 	fd = open_kcov();
    201 	ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
    202 	ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE) == 0);
    203 	close(fd);
    204 }
    205 
    206 ATF_TC_WITHOUT_HEAD(kcov_enable_no_disable_no_close);
    207 ATF_TC_BODY(kcov_enable_no_disable_no_close, tc)
    208 {
    209 	int fd;
    210 	kcov_int_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
    211 
    212 	fd = open_kcov();
    213 	ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
    214 	ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE) == 0);
    215 }
    216 
    217 static void *
    218 common_head(int *fdp)
    219 {
    220 	void *data;
    221 	int fd;
    222 	kcov_int_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
    223 
    224 	fd = open_kcov();
    225 
    226 	ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) == 0,
    227 	    "Unable to set the kcov buffer size");
    228 
    229 	data = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    230 	ATF_REQUIRE_MSG(data != MAP_FAILED, "Unable to mmap the kcov buffer");
    231 
    232 	*fdp = fd;
    233 	return data;
    234 }
    235 
    236 static void
    237 common_tail(int fd, kcov_int_t *data)
    238 {
    239 
    240 	ATF_REQUIRE_MSG(munmap(__UNVOLATILE(data), PAGE_SIZE) == 0,
    241 	    "Unable to unmap the kcov buffer");
    242 
    243 	close(fd);
    244 }
    245 
    246 ATF_TC_WITHOUT_HEAD(kcov_basic);
    247 ATF_TC_BODY(kcov_basic, tc)
    248 {
    249 	kcov_int_t *buf;
    250 	int fd;
    251 
    252 	buf = common_head(&fd);
    253 	ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_ENABLE) == 0,
    254 	    "Unable to enable kcov ");
    255 
    256 	KCOV_STORE(buf[0], 0);
    257 
    258 	sleep(0);
    259 	ATF_REQUIRE_MSG(KCOV_LOAD(buf[0]) != 0, "No records found");
    260 
    261 	ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_DISABLE) == 0,
    262 	    "Unable to disable kcov");
    263 
    264 	common_tail(fd, buf);
    265 }
    266 
    267 static void *
    268 thread_test_helper(void *ptr)
    269 {
    270 	kcov_int_t *buf = ptr;
    271 
    272 	KCOV_STORE(buf[0], 0);
    273 	sleep(0);
    274 	ATF_REQUIRE_MSG(KCOV_LOAD(buf[0]) == 0,
    275 	    "Records changed in blocked thread");
    276 
    277 	return NULL;
    278 }
    279 
    280 ATF_TC_WITHOUT_HEAD(kcov_thread);
    281 ATF_TC_BODY(kcov_thread, tc)
    282 {
    283 	pthread_t thread;
    284 	kcov_int_t *buf;
    285 	int fd;
    286 
    287 	buf = common_head(&fd);
    288 
    289 	ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_ENABLE) == 0,
    290 	    "Unable to enable kcov ");
    291 
    292 	pthread_create(&thread, NULL, thread_test_helper, __UNVOLATILE(buf));
    293 	pthread_join(thread, NULL);
    294 
    295 	ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_DISABLE) == 0,
    296 	    "Unable to disable kcov");
    297 
    298 	common_tail(fd, buf);
    299 }
    300 
    301 ATF_TP_ADD_TCS(tp)
    302 {
    303 
    304 	ATF_TP_ADD_TC(tp, kcov_bufsize);
    305 	ATF_TP_ADD_TC(tp, kcov_mmap);
    306 	ATF_TP_ADD_TC(tp, kcov_mmap_no_munmap);
    307 	ATF_TP_ADD_TC(tp, kcov_mmap_no_munmap_no_close);
    308 	ATF_TP_ADD_TC(tp, kcov_enable);
    309 	ATF_TP_ADD_TC(tp, kcov_enable_no_disable);
    310 	ATF_TP_ADD_TC(tp, kcov_enable_no_disable_no_close);
    311 	ATF_TP_ADD_TC(tp, kcov_mmap_enable_thread_close);
    312 	ATF_TP_ADD_TC(tp, kcov_basic);
    313 	ATF_TP_ADD_TC(tp, kcov_thread);
    314 	return atf_no_error();
    315 }
    316