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