1*e3865369Santon /* $OpenBSD: kcov.c,v 1.4 2018/12/27 10:10:13 anton Exp $ */ 245297697Santon 345297697Santon /* 445297697Santon * Copyright (c) 2018 Anton Lindqvist <anton@openbsd.org> 545297697Santon * 645297697Santon * Permission to use, copy, modify, and distribute this software for any 745297697Santon * purpose with or without fee is hereby granted, provided that the above 845297697Santon * copyright notice and this permission notice appear in all copies. 945297697Santon * 1045297697Santon * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1145297697Santon * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1245297697Santon * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1345297697Santon * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1445297697Santon * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1545297697Santon * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1645297697Santon * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1745297697Santon */ 1845297697Santon 1945297697Santon #include <sys/ioctl.h> 2045297697Santon #include <sys/kcov.h> 2145297697Santon #include <sys/mman.h> 2245297697Santon #include <sys/wait.h> 2345297697Santon 2445297697Santon #include <err.h> 2545297697Santon #include <errno.h> 2645297697Santon #include <fcntl.h> 27aad1a0fbSanton #include <pthread.h> 2845297697Santon #include <stdio.h> 2945297697Santon #include <stdlib.h> 309257d67bSanton #include <string.h> 3145297697Santon #include <unistd.h> 3245297697Santon 3345297697Santon static int test_close(int); 3445297697Santon static int test_coverage(int); 35aad1a0fbSanton static int test_dying(int); 3645297697Santon static int test_exec(int); 3745297697Santon static int test_fork(int); 3845297697Santon static int test_open(int); 39*e3865369Santon static int test_state(int); 4045297697Santon 4145297697Santon static void do_syscall(void); 4245297697Santon static void dump(const unsigned long *); 4345297697Santon static void kcov_disable(int); 4445297697Santon static void kcov_enable(int); 4545297697Santon static int kcov_open(void); 4645297697Santon static __dead void usage(void); 4745297697Santon 4845297697Santon static const char *self; 4945297697Santon static unsigned long bufsize = 256 << 10; 5045297697Santon 5145297697Santon int 5245297697Santon main(int argc, char *argv[]) 5345297697Santon { 5445297697Santon struct { 5545297697Santon const char *name; 5645297697Santon int (*fn)(int); 5745297697Santon int coverage; /* test must produce coverage */ 5845297697Santon } tests[] = { 5945297697Santon { "close", test_close, 0 }, 60*e3865369Santon { "coverage", test_coverage, 1 }, 61aad1a0fbSanton { "dying", test_dying, 1 }, 62*e3865369Santon { "exec", test_exec, 1 }, 63*e3865369Santon { "fork", test_fork, 1 }, 64*e3865369Santon { "open", test_open, 0 }, 65*e3865369Santon { "state", test_state, 1 }, 6645297697Santon { NULL, NULL, 0 }, 6745297697Santon }; 6845297697Santon unsigned long *cover; 6945297697Santon int c, fd, i; 709257d67bSanton int error = 0; 7145297697Santon int prereq = 0; 7245297697Santon int reexec = 0; 7345297697Santon int verbose = 0; 7445297697Santon 7545297697Santon self = argv[0]; 7645297697Santon 7745297697Santon while ((c = getopt(argc, argv, "Epv")) != -1) 7845297697Santon switch (c) { 7945297697Santon case 'E': 8045297697Santon reexec = 1; 8145297697Santon break; 8245297697Santon case 'p': 8345297697Santon prereq = 1; 8445297697Santon break; 8545297697Santon case 'v': 8645297697Santon verbose = 1; 8745297697Santon break; 8845297697Santon default: 8945297697Santon usage(); 9045297697Santon } 9145297697Santon argc -= optind; 9245297697Santon argv += optind; 9345297697Santon 9445297697Santon if (prereq) { 9545297697Santon fd = kcov_open(); 9645297697Santon close(fd); 9745297697Santon return 0; 9845297697Santon } 9945297697Santon 10045297697Santon if (reexec) { 10145297697Santon do_syscall(); 10245297697Santon return 0; 10345297697Santon } 10445297697Santon 1059257d67bSanton if (argc != 1) 1069257d67bSanton usage(); 1079257d67bSanton for (i = 0; tests[i].name != NULL; i++) 1089257d67bSanton if (strcmp(argv[0], tests[i].name) == 0) 1099257d67bSanton break; 1109257d67bSanton if (tests[i].name == NULL) 1119257d67bSanton errx(1, "%s: no such test", argv[0]); 1129257d67bSanton 11345297697Santon fd = kcov_open(); 11445297697Santon if (ioctl(fd, KIOSETBUFSIZE, &bufsize) == -1) 11545297697Santon err(1, "ioctl: KIOSETBUFSIZE"); 11645297697Santon cover = mmap(NULL, bufsize * sizeof(unsigned long), 11745297697Santon PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 11845297697Santon if (cover == MAP_FAILED) 11945297697Santon err(1, "mmap"); 12045297697Santon 12145297697Santon *cover = 0; 1229257d67bSanton error = tests[i].fn(fd); 12345297697Santon if (verbose) 12445297697Santon dump(cover); 12545297697Santon if (tests[i].coverage && *cover == 0) { 1269257d67bSanton warnx("coverage empty (count=%lu, fd=%d)\n", *cover, fd); 1279257d67bSanton error = 1; 12845297697Santon } else if (!tests[i].coverage && *cover != 0) { 1299257d67bSanton warnx("coverage is not empty (count=%lu, fd=%d)\n", *cover, fd); 1309257d67bSanton error = 1; 13145297697Santon } 13245297697Santon 13345297697Santon if (munmap(cover, bufsize * sizeof(unsigned long)) == -1) 13445297697Santon err(1, "munmap"); 13545297697Santon close(fd); 13645297697Santon 1379257d67bSanton return error; 13845297697Santon } 13945297697Santon 14045297697Santon static __dead void 14145297697Santon usage(void) 14245297697Santon { 14345297697Santon fprintf(stderr, "usage: kcov [-Epv]\n"); 14445297697Santon exit(1); 14545297697Santon } 14645297697Santon 14745297697Santon static void 14845297697Santon do_syscall(void) 14945297697Santon { 15045297697Santon getpid(); 15145297697Santon } 15245297697Santon 15345297697Santon static void 15445297697Santon dump(const unsigned long *cover) 15545297697Santon { 15645297697Santon unsigned long i; 15745297697Santon 15845297697Santon for (i = 0; i < cover[0]; i++) 15945297697Santon printf("%lu/%lu: %p\n", i + 1, cover[0], (void *)cover[i + 1]); 16045297697Santon } 16145297697Santon 16245297697Santon static int 16345297697Santon kcov_open(void) 16445297697Santon { 16545297697Santon int fd; 16645297697Santon 16745297697Santon fd = open("/dev/kcov", O_RDWR); 16845297697Santon if (fd == -1) 16945297697Santon err(1, "open: /dev/kcov"); 17045297697Santon return fd; 17145297697Santon } 17245297697Santon 17345297697Santon static void 17445297697Santon kcov_enable(int fd) 17545297697Santon { 17645297697Santon if (ioctl(fd, KIOENABLE) == -1) 17745297697Santon err(1, "ioctl: KIOENABLE"); 17845297697Santon } 17945297697Santon 18045297697Santon static void 18145297697Santon kcov_disable(int fd) 18245297697Santon { 18345297697Santon if (ioctl(fd, KIODISABLE) == -1) 18445297697Santon err(1, "ioctl: KIODISABLE"); 18545297697Santon } 18645297697Santon 18745297697Santon /* 18845297697Santon * Close before mmap. 18945297697Santon */ 19045297697Santon static int 19145297697Santon test_close(int oldfd) 19245297697Santon { 19345297697Santon int fd; 19445297697Santon 19545297697Santon fd = kcov_open(); 19645297697Santon close(fd); 19745297697Santon return 0; 19845297697Santon } 19945297697Santon 20045297697Santon /* 20145297697Santon * Coverage of current thread. 20245297697Santon */ 20345297697Santon static int 20445297697Santon test_coverage(int fd) 20545297697Santon { 20645297697Santon kcov_enable(fd); 20745297697Santon do_syscall(); 20845297697Santon kcov_disable(fd); 20945297697Santon return 0; 21045297697Santon } 21145297697Santon 212aad1a0fbSanton static void * 213aad1a0fbSanton closer(void *arg) 214aad1a0fbSanton { 215aad1a0fbSanton int fd = *((int *)arg); 216aad1a0fbSanton 217aad1a0fbSanton close(fd); 218aad1a0fbSanton return NULL; 219aad1a0fbSanton } 220aad1a0fbSanton 221aad1a0fbSanton /* 222aad1a0fbSanton * Close kcov descriptor in another thread during tracing. 223aad1a0fbSanton */ 224aad1a0fbSanton static int 225aad1a0fbSanton test_dying(int fd) 226aad1a0fbSanton { 227aad1a0fbSanton pthread_t th; 228aad1a0fbSanton int error; 229aad1a0fbSanton 230aad1a0fbSanton kcov_enable(fd); 231aad1a0fbSanton 232aad1a0fbSanton if ((error = pthread_create(&th, NULL, closer, &fd))) 233aad1a0fbSanton errc(1, error, "pthread_create"); 234aad1a0fbSanton if ((error = pthread_join(th, NULL))) 235aad1a0fbSanton errc(1, error, "pthread_join"); 236aad1a0fbSanton 237aad1a0fbSanton if (close(fd) == -1) { 238aad1a0fbSanton if (errno != EBADF) 239aad1a0fbSanton err(1, "close"); 240aad1a0fbSanton } else { 241aad1a0fbSanton warnx("expected kcov descriptor to be closed"); 242aad1a0fbSanton return 1; 243aad1a0fbSanton } 244aad1a0fbSanton 245aad1a0fbSanton return 0; 246aad1a0fbSanton } 247aad1a0fbSanton 24845297697Santon /* 24945297697Santon * Coverage of thread after exec. 25045297697Santon */ 25145297697Santon static int 25245297697Santon test_exec(int fd) 25345297697Santon { 25445297697Santon pid_t pid; 25545297697Santon int status; 25645297697Santon 25745297697Santon pid = fork(); 25845297697Santon if (pid == -1) 25945297697Santon err(1, "fork"); 26045297697Santon if (pid == 0) { 26145297697Santon kcov_enable(fd); 26245297697Santon execlp(self, self, "-E", NULL); 26345297697Santon _exit(1); 26445297697Santon } 26545297697Santon 26645297697Santon if (waitpid(pid, &status, 0) == -1) 26745297697Santon err(1, "waitpid"); 26845297697Santon if (WIFSIGNALED(status)) { 26945297697Santon warnx("terminated by signal (%d)", WTERMSIG(status)); 27045297697Santon return 1; 27145297697Santon } else if (WEXITSTATUS(status) != 0) { 27245297697Santon warnx("non-zero exit (%d)", WEXITSTATUS(status)); 27345297697Santon return 1; 27445297697Santon } 27545297697Santon 27645297697Santon /* Upon exit, the kcov descriptor must be reusable again. */ 27745297697Santon kcov_enable(fd); 27845297697Santon kcov_disable(fd); 27945297697Santon 28045297697Santon return 0; 28145297697Santon } 28245297697Santon 28345297697Santon /* 28445297697Santon * Coverage of thread after fork. 28545297697Santon */ 28645297697Santon static int 28745297697Santon test_fork(int fd) 28845297697Santon { 28945297697Santon pid_t pid; 29045297697Santon int status; 29145297697Santon 29245297697Santon pid = fork(); 29345297697Santon if (pid == -1) 29445297697Santon err(1, "fork"); 29545297697Santon if (pid == 0) { 29645297697Santon kcov_enable(fd); 29745297697Santon do_syscall(); 29845297697Santon _exit(0); 29945297697Santon } 30045297697Santon 30145297697Santon if (waitpid(pid, &status, 0) == -1) 30245297697Santon err(1, "waitpid"); 30345297697Santon if (WIFSIGNALED(status)) { 30445297697Santon warnx("terminated by signal (%d)", WTERMSIG(status)); 30545297697Santon return 1; 30645297697Santon } else if (WEXITSTATUS(status) != 0) { 30745297697Santon warnx("non-zero exit (%d)", WEXITSTATUS(status)); 30845297697Santon return 1; 30945297697Santon } 31045297697Santon 31145297697Santon /* Upon exit, the kcov descriptor must be reusable again. */ 31245297697Santon kcov_enable(fd); 31345297697Santon kcov_disable(fd); 31445297697Santon 31545297697Santon return 0; 31645297697Santon } 31745297697Santon 31845297697Santon /* 319*e3865369Santon * Open /dev/kcov more than once. 32045297697Santon */ 32145297697Santon static int 322*e3865369Santon test_open(int oldfd) 323*e3865369Santon { 324*e3865369Santon unsigned long *cover; 325*e3865369Santon int fd; 326*e3865369Santon int ret = 0; 327*e3865369Santon 328*e3865369Santon fd = kcov_open(); 329*e3865369Santon if (ioctl(fd, KIOSETBUFSIZE, &bufsize) == -1) 330*e3865369Santon err(1, "ioctl: KIOSETBUFSIZE"); 331*e3865369Santon cover = mmap(NULL, bufsize * sizeof(unsigned long), 332*e3865369Santon PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 333*e3865369Santon if (cover == MAP_FAILED) 334*e3865369Santon err(1, "mmap"); 335*e3865369Santon 336*e3865369Santon kcov_enable(fd); 337*e3865369Santon do_syscall(); 338*e3865369Santon kcov_disable(fd); 339*e3865369Santon 340*e3865369Santon if (*cover == 0) { 341*e3865369Santon warnx("coverage empty (count=0, fd=%d)\n", fd); 342*e3865369Santon ret = 1; 343*e3865369Santon } 344*e3865369Santon if (munmap(cover, bufsize * sizeof(unsigned long))) 345*e3865369Santon err(1, "munmap"); 346*e3865369Santon close(fd); 347*e3865369Santon return ret; 348*e3865369Santon } 349*e3865369Santon 350*e3865369Santon /* 351*e3865369Santon * State transitions. 352*e3865369Santon */ 353*e3865369Santon static int 354*e3865369Santon test_state(int fd) 35545297697Santon { 35645297697Santon if (ioctl(fd, KIOENABLE) == -1) { 35745297697Santon warnx("KIOSETBUFSIZE -> KIOENABLE"); 35845297697Santon return 1; 35945297697Santon } 36045297697Santon if (ioctl(fd, KIODISABLE) == -1) { 36145297697Santon warnx("KIOENABLE -> KIODISABLE"); 36245297697Santon return 1; 36345297697Santon } 36445297697Santon if (ioctl(fd, KIOSETBUFSIZE, 0) != -1) { 36545297697Santon warnx("KIOSETBUFSIZE -> KIOSETBUFSIZE"); 36645297697Santon return 1; 36745297697Santon } 36845297697Santon if (ioctl(fd, KIODISABLE) != -1) { 36945297697Santon warnx("KIOSETBUFSIZE -> KIODISABLE"); 37045297697Santon return 1; 37145297697Santon } 37245297697Santon 37345297697Santon kcov_enable(fd); 37445297697Santon if (ioctl(fd, KIOENABLE) != -1) { 37545297697Santon warnx("KIOENABLE -> KIOENABLE"); 37645297697Santon return 1; 37745297697Santon } 37845297697Santon if (ioctl(fd, KIOSETBUFSIZE, 0) != -1) { 37945297697Santon warnx("KIOENABLE -> KIOSETBUFSIZE"); 38045297697Santon return 1; 38145297697Santon } 38245297697Santon kcov_disable(fd); 38345297697Santon 38445297697Santon return 0; 38545297697Santon } 386