1*0e2965f9Santon /* $OpenBSD: kcov.c,v 1.5 2018/12/27 19:38:01 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 33*0e2965f9Santon static int test_close(int, int); 34*0e2965f9Santon static int test_coverage(int, int); 35*0e2965f9Santon static int test_dying(int, int); 36*0e2965f9Santon static int test_exec(int, int); 37*0e2965f9Santon static int test_fork(int, int); 38*0e2965f9Santon static int test_open(int, int); 39*0e2965f9Santon static int test_state(int, int); 4045297697Santon 4145297697Santon static void do_syscall(void); 4245297697Santon static void dump(const unsigned long *); 4345297697Santon static void kcov_disable(int); 44*0e2965f9Santon static void kcov_enable(int, 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; 56*0e2965f9Santon int (*fn)(int, int); 5745297697Santon int coverage; /* test must produce coverage */ 5845297697Santon } tests[] = { 5945297697Santon { "close", test_close, 0 }, 60e3865369Santon { "coverage", test_coverage, 1 }, 61aad1a0fbSanton { "dying", test_dying, 1 }, 62e3865369Santon { "exec", test_exec, 1 }, 63e3865369Santon { "fork", test_fork, 1 }, 64e3865369Santon { "open", test_open, 0 }, 65e3865369Santon { "state", test_state, 1 }, 6645297697Santon { NULL, NULL, 0 }, 6745297697Santon }; 6845297697Santon unsigned long *cover; 6945297697Santon int c, fd, i; 709257d67bSanton int error = 0; 71*0e2965f9Santon int mode = 0; 7245297697Santon int prereq = 0; 7345297697Santon int reexec = 0; 7445297697Santon int verbose = 0; 7545297697Santon 7645297697Santon self = argv[0]; 7745297697Santon 78*0e2965f9Santon while ((c = getopt(argc, argv, "Em:pv")) != -1) 7945297697Santon switch (c) { 8045297697Santon case 'E': 8145297697Santon reexec = 1; 8245297697Santon break; 83*0e2965f9Santon case 'm': 84*0e2965f9Santon if (strcmp(optarg, "pc") == 0) 85*0e2965f9Santon mode = KCOV_MODE_TRACE_PC; 86*0e2965f9Santon else 87*0e2965f9Santon errx(1, "unknown mode %s", optarg); 88*0e2965f9Santon break; 8945297697Santon case 'p': 9045297697Santon prereq = 1; 9145297697Santon break; 9245297697Santon case 'v': 9345297697Santon verbose = 1; 9445297697Santon break; 9545297697Santon default: 9645297697Santon usage(); 9745297697Santon } 9845297697Santon argc -= optind; 9945297697Santon argv += optind; 10045297697Santon 10145297697Santon if (prereq) { 10245297697Santon fd = kcov_open(); 10345297697Santon close(fd); 10445297697Santon return 0; 10545297697Santon } 10645297697Santon 10745297697Santon if (reexec) { 10845297697Santon do_syscall(); 10945297697Santon return 0; 11045297697Santon } 11145297697Santon 112*0e2965f9Santon if (mode == 0 || argc != 1) 1139257d67bSanton usage(); 1149257d67bSanton for (i = 0; tests[i].name != NULL; i++) 1159257d67bSanton if (strcmp(argv[0], tests[i].name) == 0) 1169257d67bSanton break; 1179257d67bSanton if (tests[i].name == NULL) 1189257d67bSanton errx(1, "%s: no such test", argv[0]); 1199257d67bSanton 12045297697Santon fd = kcov_open(); 12145297697Santon if (ioctl(fd, KIOSETBUFSIZE, &bufsize) == -1) 12245297697Santon err(1, "ioctl: KIOSETBUFSIZE"); 12345297697Santon cover = mmap(NULL, bufsize * sizeof(unsigned long), 12445297697Santon PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 12545297697Santon if (cover == MAP_FAILED) 12645297697Santon err(1, "mmap"); 12745297697Santon 12845297697Santon *cover = 0; 129*0e2965f9Santon error = tests[i].fn(fd, mode); 13045297697Santon if (verbose) 13145297697Santon dump(cover); 13245297697Santon if (tests[i].coverage && *cover == 0) { 1339257d67bSanton warnx("coverage empty (count=%lu, fd=%d)\n", *cover, fd); 1349257d67bSanton error = 1; 13545297697Santon } else if (!tests[i].coverage && *cover != 0) { 1369257d67bSanton warnx("coverage is not empty (count=%lu, fd=%d)\n", *cover, fd); 1379257d67bSanton error = 1; 13845297697Santon } 13945297697Santon 14045297697Santon if (munmap(cover, bufsize * sizeof(unsigned long)) == -1) 14145297697Santon err(1, "munmap"); 14245297697Santon close(fd); 14345297697Santon 1449257d67bSanton return error; 14545297697Santon } 14645297697Santon 14745297697Santon static __dead void 14845297697Santon usage(void) 14945297697Santon { 150*0e2965f9Santon fprintf(stderr, "usage: kcov [-Epv] -t mode test\n"); 15145297697Santon exit(1); 15245297697Santon } 15345297697Santon 15445297697Santon static void 15545297697Santon do_syscall(void) 15645297697Santon { 15745297697Santon getpid(); 15845297697Santon } 15945297697Santon 16045297697Santon static void 16145297697Santon dump(const unsigned long *cover) 16245297697Santon { 16345297697Santon unsigned long i; 16445297697Santon 16545297697Santon for (i = 0; i < cover[0]; i++) 16645297697Santon printf("%lu/%lu: %p\n", i + 1, cover[0], (void *)cover[i + 1]); 16745297697Santon } 16845297697Santon 16945297697Santon static int 17045297697Santon kcov_open(void) 17145297697Santon { 17245297697Santon int fd; 17345297697Santon 17445297697Santon fd = open("/dev/kcov", O_RDWR); 17545297697Santon if (fd == -1) 17645297697Santon err(1, "open: /dev/kcov"); 17745297697Santon return fd; 17845297697Santon } 17945297697Santon 18045297697Santon static void 181*0e2965f9Santon kcov_enable(int fd, int mode) 18245297697Santon { 183*0e2965f9Santon if (ioctl(fd, KIOENABLE, &mode) == -1) 18445297697Santon err(1, "ioctl: KIOENABLE"); 18545297697Santon } 18645297697Santon 18745297697Santon static void 18845297697Santon kcov_disable(int fd) 18945297697Santon { 19045297697Santon if (ioctl(fd, KIODISABLE) == -1) 19145297697Santon err(1, "ioctl: KIODISABLE"); 19245297697Santon } 19345297697Santon 19445297697Santon /* 19545297697Santon * Close before mmap. 19645297697Santon */ 19745297697Santon static int 198*0e2965f9Santon test_close(int oldfd, int mode) 19945297697Santon { 20045297697Santon int fd; 20145297697Santon 20245297697Santon fd = kcov_open(); 20345297697Santon close(fd); 20445297697Santon return 0; 20545297697Santon } 20645297697Santon 20745297697Santon /* 20845297697Santon * Coverage of current thread. 20945297697Santon */ 21045297697Santon static int 211*0e2965f9Santon test_coverage(int fd, int mode) 21245297697Santon { 213*0e2965f9Santon kcov_enable(fd, mode); 21445297697Santon do_syscall(); 21545297697Santon kcov_disable(fd); 21645297697Santon return 0; 21745297697Santon } 21845297697Santon 219aad1a0fbSanton static void * 220aad1a0fbSanton closer(void *arg) 221aad1a0fbSanton { 222aad1a0fbSanton int fd = *((int *)arg); 223aad1a0fbSanton 224aad1a0fbSanton close(fd); 225aad1a0fbSanton return NULL; 226aad1a0fbSanton } 227aad1a0fbSanton 228aad1a0fbSanton /* 229aad1a0fbSanton * Close kcov descriptor in another thread during tracing. 230aad1a0fbSanton */ 231aad1a0fbSanton static int 232*0e2965f9Santon test_dying(int fd, int mode) 233aad1a0fbSanton { 234aad1a0fbSanton pthread_t th; 235aad1a0fbSanton int error; 236aad1a0fbSanton 237*0e2965f9Santon kcov_enable(fd, mode); 238aad1a0fbSanton 239aad1a0fbSanton if ((error = pthread_create(&th, NULL, closer, &fd))) 240aad1a0fbSanton errc(1, error, "pthread_create"); 241aad1a0fbSanton if ((error = pthread_join(th, NULL))) 242aad1a0fbSanton errc(1, error, "pthread_join"); 243aad1a0fbSanton 244aad1a0fbSanton if (close(fd) == -1) { 245aad1a0fbSanton if (errno != EBADF) 246aad1a0fbSanton err(1, "close"); 247aad1a0fbSanton } else { 248aad1a0fbSanton warnx("expected kcov descriptor to be closed"); 249aad1a0fbSanton return 1; 250aad1a0fbSanton } 251aad1a0fbSanton 252aad1a0fbSanton return 0; 253aad1a0fbSanton } 254aad1a0fbSanton 25545297697Santon /* 25645297697Santon * Coverage of thread after exec. 25745297697Santon */ 25845297697Santon static int 259*0e2965f9Santon test_exec(int fd, int mode) 26045297697Santon { 26145297697Santon pid_t pid; 26245297697Santon int status; 26345297697Santon 26445297697Santon pid = fork(); 26545297697Santon if (pid == -1) 26645297697Santon err(1, "fork"); 26745297697Santon if (pid == 0) { 268*0e2965f9Santon kcov_enable(fd, mode); 26945297697Santon execlp(self, self, "-E", NULL); 27045297697Santon _exit(1); 27145297697Santon } 27245297697Santon 27345297697Santon if (waitpid(pid, &status, 0) == -1) 27445297697Santon err(1, "waitpid"); 27545297697Santon if (WIFSIGNALED(status)) { 27645297697Santon warnx("terminated by signal (%d)", WTERMSIG(status)); 27745297697Santon return 1; 27845297697Santon } else if (WEXITSTATUS(status) != 0) { 27945297697Santon warnx("non-zero exit (%d)", WEXITSTATUS(status)); 28045297697Santon return 1; 28145297697Santon } 28245297697Santon 28345297697Santon /* Upon exit, the kcov descriptor must be reusable again. */ 284*0e2965f9Santon kcov_enable(fd, mode); 28545297697Santon kcov_disable(fd); 28645297697Santon 28745297697Santon return 0; 28845297697Santon } 28945297697Santon 29045297697Santon /* 29145297697Santon * Coverage of thread after fork. 29245297697Santon */ 29345297697Santon static int 294*0e2965f9Santon test_fork(int fd, int mode) 29545297697Santon { 29645297697Santon pid_t pid; 29745297697Santon int status; 29845297697Santon 29945297697Santon pid = fork(); 30045297697Santon if (pid == -1) 30145297697Santon err(1, "fork"); 30245297697Santon if (pid == 0) { 303*0e2965f9Santon kcov_enable(fd, mode); 30445297697Santon do_syscall(); 30545297697Santon _exit(0); 30645297697Santon } 30745297697Santon 30845297697Santon if (waitpid(pid, &status, 0) == -1) 30945297697Santon err(1, "waitpid"); 31045297697Santon if (WIFSIGNALED(status)) { 31145297697Santon warnx("terminated by signal (%d)", WTERMSIG(status)); 31245297697Santon return 1; 31345297697Santon } else if (WEXITSTATUS(status) != 0) { 31445297697Santon warnx("non-zero exit (%d)", WEXITSTATUS(status)); 31545297697Santon return 1; 31645297697Santon } 31745297697Santon 31845297697Santon /* Upon exit, the kcov descriptor must be reusable again. */ 319*0e2965f9Santon kcov_enable(fd, mode); 32045297697Santon kcov_disable(fd); 32145297697Santon 32245297697Santon return 0; 32345297697Santon } 32445297697Santon 32545297697Santon /* 326e3865369Santon * Open /dev/kcov more than once. 32745297697Santon */ 32845297697Santon static int 329*0e2965f9Santon test_open(int oldfd, int mode) 330e3865369Santon { 331e3865369Santon unsigned long *cover; 332e3865369Santon int fd; 333e3865369Santon int ret = 0; 334e3865369Santon 335e3865369Santon fd = kcov_open(); 336e3865369Santon if (ioctl(fd, KIOSETBUFSIZE, &bufsize) == -1) 337e3865369Santon err(1, "ioctl: KIOSETBUFSIZE"); 338e3865369Santon cover = mmap(NULL, bufsize * sizeof(unsigned long), 339e3865369Santon PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 340e3865369Santon if (cover == MAP_FAILED) 341e3865369Santon err(1, "mmap"); 342e3865369Santon 343*0e2965f9Santon kcov_enable(fd, mode); 344e3865369Santon do_syscall(); 345e3865369Santon kcov_disable(fd); 346e3865369Santon 347e3865369Santon if (*cover == 0) { 348e3865369Santon warnx("coverage empty (count=0, fd=%d)\n", fd); 349e3865369Santon ret = 1; 350e3865369Santon } 351e3865369Santon if (munmap(cover, bufsize * sizeof(unsigned long))) 352e3865369Santon err(1, "munmap"); 353e3865369Santon close(fd); 354e3865369Santon return ret; 355e3865369Santon } 356e3865369Santon 357e3865369Santon /* 358e3865369Santon * State transitions. 359e3865369Santon */ 360e3865369Santon static int 361*0e2965f9Santon test_state(int fd, int mode) 36245297697Santon { 363*0e2965f9Santon if (ioctl(fd, KIOENABLE, &mode) == -1) { 364*0e2965f9Santon warn("KIOSETBUFSIZE -> KIOENABLE"); 36545297697Santon return 1; 36645297697Santon } 36745297697Santon if (ioctl(fd, KIODISABLE) == -1) { 368*0e2965f9Santon warn("KIOENABLE -> KIODISABLE"); 36945297697Santon return 1; 37045297697Santon } 37145297697Santon if (ioctl(fd, KIOSETBUFSIZE, 0) != -1) { 37245297697Santon warnx("KIOSETBUFSIZE -> KIOSETBUFSIZE"); 37345297697Santon return 1; 37445297697Santon } 37545297697Santon if (ioctl(fd, KIODISABLE) != -1) { 37645297697Santon warnx("KIOSETBUFSIZE -> KIODISABLE"); 37745297697Santon return 1; 37845297697Santon } 37945297697Santon 380*0e2965f9Santon kcov_enable(fd, mode); 381*0e2965f9Santon if (ioctl(fd, KIOENABLE, &mode) != -1) { 38245297697Santon warnx("KIOENABLE -> KIOENABLE"); 38345297697Santon return 1; 38445297697Santon } 38545297697Santon if (ioctl(fd, KIOSETBUFSIZE, 0) != -1) { 38645297697Santon warnx("KIOENABLE -> KIOSETBUFSIZE"); 38745297697Santon return 1; 38845297697Santon } 38945297697Santon kcov_disable(fd); 39045297697Santon 39145297697Santon return 0; 39245297697Santon } 393