1*45297697Santon /* $OpenBSD: kcov.c,v 1.1 2018/08/26 08:12:09 anton Exp $ */ 2*45297697Santon 3*45297697Santon /* 4*45297697Santon * Copyright (c) 2018 Anton Lindqvist <anton@openbsd.org> 5*45297697Santon * 6*45297697Santon * Permission to use, copy, modify, and distribute this software for any 7*45297697Santon * purpose with or without fee is hereby granted, provided that the above 8*45297697Santon * copyright notice and this permission notice appear in all copies. 9*45297697Santon * 10*45297697Santon * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11*45297697Santon * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12*45297697Santon * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13*45297697Santon * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14*45297697Santon * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15*45297697Santon * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16*45297697Santon * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17*45297697Santon */ 18*45297697Santon 19*45297697Santon #include <sys/ioctl.h> 20*45297697Santon #include <sys/kcov.h> 21*45297697Santon #include <sys/mman.h> 22*45297697Santon #include <sys/wait.h> 23*45297697Santon 24*45297697Santon #include <err.h> 25*45297697Santon #include <errno.h> 26*45297697Santon #include <fcntl.h> 27*45297697Santon #include <stdio.h> 28*45297697Santon #include <stdlib.h> 29*45297697Santon #include <unistd.h> 30*45297697Santon 31*45297697Santon static int test_close(int); 32*45297697Santon static int test_coverage(int); 33*45297697Santon static int test_exec(int); 34*45297697Santon static int test_fork(int); 35*45297697Santon static int test_mode(int); 36*45297697Santon static int test_open(int); 37*45297697Santon 38*45297697Santon static void do_syscall(void); 39*45297697Santon static void dump(const unsigned long *); 40*45297697Santon static void kcov_disable(int); 41*45297697Santon static void kcov_enable(int); 42*45297697Santon static int kcov_open(void); 43*45297697Santon static __dead void usage(void); 44*45297697Santon 45*45297697Santon static const char *self; 46*45297697Santon static unsigned long bufsize = 256 << 10; 47*45297697Santon 48*45297697Santon int 49*45297697Santon main(int argc, char *argv[]) 50*45297697Santon { 51*45297697Santon struct { 52*45297697Santon const char *name; 53*45297697Santon int (*fn)(int); 54*45297697Santon int coverage; /* test must produce coverage */ 55*45297697Santon } tests[] = { 56*45297697Santon { "coverage", test_coverage, 1 }, 57*45297697Santon { "fork", test_fork, 1 }, 58*45297697Santon { "exec", test_exec, 1 }, 59*45297697Santon { "mode", test_mode, 1 }, 60*45297697Santon { "open", test_open, 0 }, 61*45297697Santon { "close", test_close, 0 }, 62*45297697Santon { NULL, NULL, 0 }, 63*45297697Santon }; 64*45297697Santon unsigned long *cover; 65*45297697Santon int c, fd, i; 66*45297697Santon int nfail = 0; 67*45297697Santon int prereq = 0; 68*45297697Santon int reexec = 0; 69*45297697Santon int verbose = 0; 70*45297697Santon 71*45297697Santon self = argv[0]; 72*45297697Santon 73*45297697Santon while ((c = getopt(argc, argv, "Epv")) != -1) 74*45297697Santon switch (c) { 75*45297697Santon case 'E': 76*45297697Santon reexec = 1; 77*45297697Santon break; 78*45297697Santon case 'p': 79*45297697Santon prereq = 1; 80*45297697Santon break; 81*45297697Santon case 'v': 82*45297697Santon verbose = 1; 83*45297697Santon break; 84*45297697Santon default: 85*45297697Santon usage(); 86*45297697Santon } 87*45297697Santon argc -= optind; 88*45297697Santon argv += optind; 89*45297697Santon if (argc > 0) 90*45297697Santon usage(); 91*45297697Santon 92*45297697Santon if (prereq) { 93*45297697Santon fd = kcov_open(); 94*45297697Santon close(fd); 95*45297697Santon return 0; 96*45297697Santon } 97*45297697Santon 98*45297697Santon if (reexec) { 99*45297697Santon do_syscall(); 100*45297697Santon return 0; 101*45297697Santon } 102*45297697Santon 103*45297697Santon fd = kcov_open(); 104*45297697Santon if (ioctl(fd, KIOSETBUFSIZE, &bufsize) == -1) 105*45297697Santon err(1, "ioctl: KIOSETBUFSIZE"); 106*45297697Santon cover = mmap(NULL, bufsize * sizeof(unsigned long), 107*45297697Santon PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 108*45297697Santon if (cover == MAP_FAILED) 109*45297697Santon err(1, "mmap"); 110*45297697Santon 111*45297697Santon for (i = 0; tests[i].name != NULL; i++) { 112*45297697Santon printf("===> %s\n", tests[i].name); 113*45297697Santon *cover = 0; 114*45297697Santon nfail += tests[i].fn(fd); 115*45297697Santon if (verbose) 116*45297697Santon dump(cover); 117*45297697Santon if (tests[i].coverage && *cover == 0) { 118*45297697Santon warnx("coverage empty (count=%lu, fd=%d)\n", 119*45297697Santon *cover, fd); 120*45297697Santon nfail++; 121*45297697Santon } else if (!tests[i].coverage && *cover != 0) { 122*45297697Santon warnx("coverage is not empty (count=%lu, fd=%d)\n", 123*45297697Santon *cover, fd); 124*45297697Santon nfail++; 125*45297697Santon } 126*45297697Santon } 127*45297697Santon 128*45297697Santon if (munmap(cover, bufsize * sizeof(unsigned long)) == -1) 129*45297697Santon err(1, "munmap"); 130*45297697Santon close(fd); 131*45297697Santon 132*45297697Santon if (nfail > 0) 133*45297697Santon return 1; 134*45297697Santon return 0; 135*45297697Santon } 136*45297697Santon 137*45297697Santon static __dead void 138*45297697Santon usage(void) 139*45297697Santon { 140*45297697Santon fprintf(stderr, "usage: kcov [-Epv]\n"); 141*45297697Santon exit(1); 142*45297697Santon } 143*45297697Santon 144*45297697Santon static void 145*45297697Santon do_syscall(void) 146*45297697Santon { 147*45297697Santon getpid(); 148*45297697Santon } 149*45297697Santon 150*45297697Santon static void 151*45297697Santon dump(const unsigned long *cover) 152*45297697Santon { 153*45297697Santon unsigned long i; 154*45297697Santon 155*45297697Santon for (i = 0; i < cover[0]; i++) 156*45297697Santon printf("%lu/%lu: %p\n", i + 1, cover[0], (void *)cover[i + 1]); 157*45297697Santon } 158*45297697Santon 159*45297697Santon static int 160*45297697Santon kcov_open(void) 161*45297697Santon { 162*45297697Santon int fd; 163*45297697Santon 164*45297697Santon fd = open("/dev/kcov", O_RDWR); 165*45297697Santon if (fd == -1) 166*45297697Santon err(1, "open: /dev/kcov"); 167*45297697Santon return fd; 168*45297697Santon } 169*45297697Santon 170*45297697Santon static void 171*45297697Santon kcov_enable(int fd) 172*45297697Santon { 173*45297697Santon if (ioctl(fd, KIOENABLE) == -1) 174*45297697Santon err(1, "ioctl: KIOENABLE"); 175*45297697Santon } 176*45297697Santon 177*45297697Santon static void 178*45297697Santon kcov_disable(int fd) 179*45297697Santon { 180*45297697Santon if (ioctl(fd, KIODISABLE) == -1) 181*45297697Santon err(1, "ioctl: KIODISABLE"); 182*45297697Santon } 183*45297697Santon 184*45297697Santon /* 185*45297697Santon * Close before mmap. 186*45297697Santon */ 187*45297697Santon static int 188*45297697Santon test_close(int oldfd) 189*45297697Santon { 190*45297697Santon int fd; 191*45297697Santon 192*45297697Santon fd = kcov_open(); 193*45297697Santon close(fd); 194*45297697Santon return 0; 195*45297697Santon } 196*45297697Santon 197*45297697Santon /* 198*45297697Santon * Coverage of current thread. 199*45297697Santon */ 200*45297697Santon static int 201*45297697Santon test_coverage(int fd) 202*45297697Santon { 203*45297697Santon kcov_enable(fd); 204*45297697Santon do_syscall(); 205*45297697Santon kcov_disable(fd); 206*45297697Santon return 0; 207*45297697Santon } 208*45297697Santon 209*45297697Santon /* 210*45297697Santon * Coverage of thread after exec. 211*45297697Santon */ 212*45297697Santon static int 213*45297697Santon test_exec(int fd) 214*45297697Santon { 215*45297697Santon pid_t pid; 216*45297697Santon int status; 217*45297697Santon 218*45297697Santon pid = fork(); 219*45297697Santon if (pid == -1) 220*45297697Santon err(1, "fork"); 221*45297697Santon if (pid == 0) { 222*45297697Santon kcov_enable(fd); 223*45297697Santon execlp(self, self, "-E", NULL); 224*45297697Santon _exit(1); 225*45297697Santon } 226*45297697Santon 227*45297697Santon if (waitpid(pid, &status, 0) == -1) 228*45297697Santon err(1, "waitpid"); 229*45297697Santon if (WIFSIGNALED(status)) { 230*45297697Santon warnx("terminated by signal (%d)", WTERMSIG(status)); 231*45297697Santon return 1; 232*45297697Santon } else if (WEXITSTATUS(status) != 0) { 233*45297697Santon warnx("non-zero exit (%d)", WEXITSTATUS(status)); 234*45297697Santon return 1; 235*45297697Santon } 236*45297697Santon 237*45297697Santon /* Upon exit, the kcov descriptor must be reusable again. */ 238*45297697Santon kcov_enable(fd); 239*45297697Santon kcov_disable(fd); 240*45297697Santon 241*45297697Santon return 0; 242*45297697Santon } 243*45297697Santon 244*45297697Santon /* 245*45297697Santon * Coverage of thread after fork. 246*45297697Santon */ 247*45297697Santon static int 248*45297697Santon test_fork(int fd) 249*45297697Santon { 250*45297697Santon pid_t pid; 251*45297697Santon int status; 252*45297697Santon 253*45297697Santon pid = fork(); 254*45297697Santon if (pid == -1) 255*45297697Santon err(1, "fork"); 256*45297697Santon if (pid == 0) { 257*45297697Santon kcov_enable(fd); 258*45297697Santon do_syscall(); 259*45297697Santon _exit(0); 260*45297697Santon } 261*45297697Santon 262*45297697Santon if (waitpid(pid, &status, 0) == -1) 263*45297697Santon err(1, "waitpid"); 264*45297697Santon if (WIFSIGNALED(status)) { 265*45297697Santon warnx("terminated by signal (%d)", WTERMSIG(status)); 266*45297697Santon return 1; 267*45297697Santon } else if (WEXITSTATUS(status) != 0) { 268*45297697Santon warnx("non-zero exit (%d)", WEXITSTATUS(status)); 269*45297697Santon return 1; 270*45297697Santon } 271*45297697Santon 272*45297697Santon /* Upon exit, the kcov descriptor must be reusable again. */ 273*45297697Santon kcov_enable(fd); 274*45297697Santon kcov_disable(fd); 275*45297697Santon 276*45297697Santon return 0; 277*45297697Santon } 278*45297697Santon 279*45297697Santon /* 280*45297697Santon * Mode transitions. 281*45297697Santon */ 282*45297697Santon static int 283*45297697Santon test_mode(int fd) 284*45297697Santon { 285*45297697Santon if (ioctl(fd, KIOENABLE) == -1) { 286*45297697Santon warnx("KIOSETBUFSIZE -> KIOENABLE"); 287*45297697Santon return 1; 288*45297697Santon } 289*45297697Santon if (ioctl(fd, KIODISABLE) == -1) { 290*45297697Santon warnx("KIOENABLE -> KIODISABLE"); 291*45297697Santon return 1; 292*45297697Santon } 293*45297697Santon if (ioctl(fd, KIOSETBUFSIZE, 0) != -1) { 294*45297697Santon warnx("KIOSETBUFSIZE -> KIOSETBUFSIZE"); 295*45297697Santon return 1; 296*45297697Santon } 297*45297697Santon if (ioctl(fd, KIODISABLE) != -1) { 298*45297697Santon warnx("KIOSETBUFSIZE -> KIODISABLE"); 299*45297697Santon return 1; 300*45297697Santon } 301*45297697Santon 302*45297697Santon kcov_enable(fd); 303*45297697Santon if (ioctl(fd, KIOENABLE) != -1) { 304*45297697Santon warnx("KIOENABLE -> KIOENABLE"); 305*45297697Santon return 1; 306*45297697Santon } 307*45297697Santon if (ioctl(fd, KIOSETBUFSIZE, 0) != -1) { 308*45297697Santon warnx("KIOENABLE -> KIOSETBUFSIZE"); 309*45297697Santon return 1; 310*45297697Santon } 311*45297697Santon kcov_disable(fd); 312*45297697Santon 313*45297697Santon return 0; 314*45297697Santon } 315*45297697Santon 316*45297697Santon /* 317*45297697Santon * Open /dev/kcov more than once. 318*45297697Santon */ 319*45297697Santon static int 320*45297697Santon test_open(int oldfd) 321*45297697Santon { 322*45297697Santon unsigned long *cover; 323*45297697Santon int fd; 324*45297697Santon int ret = 0; 325*45297697Santon 326*45297697Santon fd = kcov_open(); 327*45297697Santon if (ioctl(fd, KIOSETBUFSIZE, &bufsize) == -1) 328*45297697Santon err(1, "ioctl: KIOSETBUFSIZE"); 329*45297697Santon cover = mmap(NULL, bufsize * sizeof(unsigned long), 330*45297697Santon PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 331*45297697Santon if (cover == MAP_FAILED) 332*45297697Santon err(1, "mmap"); 333*45297697Santon 334*45297697Santon kcov_enable(fd); 335*45297697Santon do_syscall(); 336*45297697Santon kcov_disable(fd); 337*45297697Santon 338*45297697Santon if (*cover == 0) { 339*45297697Santon warnx("coverage empty (count=0, fd=%d)\n", fd); 340*45297697Santon ret = 1; 341*45297697Santon } 342*45297697Santon if (munmap(cover, bufsize * sizeof(unsigned long))) 343*45297697Santon err(1, "munmap"); 344*45297697Santon close(fd); 345*45297697Santon return ret; 346*45297697Santon } 347