1*739cf936Santon /* $OpenBSD: kcov.c,v 1.15 2020/10/03 07:35:07 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 19e298ef25Santon #include <sys/types.h> 20e298ef25Santon #include <sys/event.h> 2145297697Santon #include <sys/ioctl.h> 2245297697Santon #include <sys/kcov.h> 2345297697Santon #include <sys/mman.h> 2445297697Santon #include <sys/wait.h> 2545297697Santon 2645297697Santon #include <err.h> 2745297697Santon #include <errno.h> 2845297697Santon #include <fcntl.h> 29aad1a0fbSanton #include <pthread.h> 3045297697Santon #include <stdio.h> 3145297697Santon #include <stdlib.h> 329257d67bSanton #include <string.h> 3345297697Santon #include <unistd.h> 3445297697Santon 351c537871Santon struct context { 361c537871Santon int c_fd; 371c537871Santon int c_mode; 381c537871Santon unsigned long c_bufsize; 391c537871Santon }; 401c537871Santon 41e298ef25Santon static int test_close(struct context *); 42e298ef25Santon static int test_coverage(struct context *); 43e298ef25Santon static int test_dying(struct context *); 44e298ef25Santon static int test_exec(struct context *); 45e298ef25Santon static int test_fork(struct context *); 46e298ef25Santon static int test_open(struct context *); 47e298ef25Santon static int test_remote(struct context *); 48e298ef25Santon static int test_remote_close(struct context *); 49*739cf936Santon static int test_remote_interrupt(struct context *); 50e298ef25Santon static int test_state(struct context *); 5145297697Santon 523bb8297cSanton static int check_coverage(const unsigned long *, int, unsigned long, int); 5345297697Santon static void do_syscall(void); 543bb8297cSanton static void dump(const unsigned long *, int mode); 5545297697Santon static void kcov_disable(int); 560e2965f9Santon static void kcov_enable(int, int); 5745297697Santon static int kcov_open(void); 5845297697Santon static __dead void usage(void); 5945297697Santon 6045297697Santon static const char *self; 6145297697Santon 6245297697Santon int 6345297697Santon main(int argc, char *argv[]) 6445297697Santon { 6545297697Santon struct { 6645297697Santon const char *name; 67e298ef25Santon int (*fn)(struct context *); 6845297697Santon int coverage; /* test must produce coverage */ 6945297697Santon } tests[] = { 7045297697Santon { "close", test_close, 0 }, 71e3865369Santon { "coverage", test_coverage, 1 }, 72aad1a0fbSanton { "dying", test_dying, 1 }, 73e3865369Santon { "exec", test_exec, 1 }, 74e3865369Santon { "fork", test_fork, 1 }, 75e3865369Santon { "open", test_open, 0 }, 76e298ef25Santon { "remote", test_remote, 1 }, 77e298ef25Santon { "remote-close", test_remote_close, 0 }, 78*739cf936Santon { "remote-interrupt", test_remote_interrupt, -1 }, 79e3865369Santon { "state", test_state, 1 }, 8045297697Santon { NULL, NULL, 0 }, 8145297697Santon }; 821c537871Santon struct context ctx; 83078ed3e5Santon const char *errstr; 84078ed3e5Santon unsigned long *cover, frac; 851c537871Santon int c, i; 869257d67bSanton int error = 0; 8745297697Santon int prereq = 0; 8845297697Santon int reexec = 0; 8945297697Santon int verbose = 0; 9045297697Santon 9145297697Santon self = argv[0]; 9245297697Santon 931c537871Santon memset(&ctx, 0, sizeof(ctx)); 941c537871Santon ctx.c_bufsize = 256 << 10; 951c537871Santon 96078ed3e5Santon while ((c = getopt(argc, argv, "b:Em:pv")) != -1) 9745297697Santon switch (c) { 98078ed3e5Santon case 'b': 99078ed3e5Santon frac = strtonum(optarg, 1, 100, &errstr); 100078ed3e5Santon if (frac == 0) 101078ed3e5Santon errx(1, "buffer size fraction %s", errstr); 1021c537871Santon else if (frac > ctx.c_bufsize) 103078ed3e5Santon errx(1, "buffer size fraction too large"); 1041c537871Santon ctx.c_bufsize /= frac; 105078ed3e5Santon break; 10645297697Santon case 'E': 10745297697Santon reexec = 1; 10845297697Santon break; 1090e2965f9Santon case 'm': 1100e2965f9Santon if (strcmp(optarg, "pc") == 0) 1111c537871Santon ctx.c_mode = KCOV_MODE_TRACE_PC; 112a4101078Santon else if (strcmp(optarg, "cmp") == 0) 1131c537871Santon ctx.c_mode = KCOV_MODE_TRACE_CMP; 1140e2965f9Santon else 1150e2965f9Santon errx(1, "unknown mode %s", optarg); 1160e2965f9Santon break; 11745297697Santon case 'p': 11845297697Santon prereq = 1; 11945297697Santon break; 12045297697Santon case 'v': 12145297697Santon verbose = 1; 12245297697Santon break; 12345297697Santon default: 12445297697Santon usage(); 12545297697Santon } 12645297697Santon argc -= optind; 12745297697Santon argv += optind; 12845297697Santon 12945297697Santon if (prereq) { 1301c537871Santon ctx.c_fd = kcov_open(); 1311c537871Santon close(ctx.c_fd); 13245297697Santon return 0; 13345297697Santon } 13445297697Santon 13545297697Santon if (reexec) { 13645297697Santon do_syscall(); 13745297697Santon return 0; 13845297697Santon } 13945297697Santon 1401c537871Santon if (ctx.c_mode == 0 || argc != 1) 1419257d67bSanton usage(); 1429257d67bSanton for (i = 0; tests[i].name != NULL; i++) 1439257d67bSanton if (strcmp(argv[0], tests[i].name) == 0) 1449257d67bSanton break; 1459257d67bSanton if (tests[i].name == NULL) 1469257d67bSanton errx(1, "%s: no such test", argv[0]); 1479257d67bSanton 1481c537871Santon ctx.c_fd = kcov_open(); 1491c537871Santon if (ioctl(ctx.c_fd, KIOSETBUFSIZE, &ctx.c_bufsize) == -1) 15045297697Santon err(1, "ioctl: KIOSETBUFSIZE"); 1511c537871Santon cover = mmap(NULL, ctx.c_bufsize * sizeof(unsigned long), 1521c537871Santon PROT_READ | PROT_WRITE, MAP_SHARED, ctx.c_fd, 0); 15345297697Santon if (cover == MAP_FAILED) 15445297697Santon err(1, "mmap"); 15545297697Santon 15645297697Santon *cover = 0; 1571c537871Santon error = tests[i].fn(&ctx); 15845297697Santon if (verbose) 1591c537871Santon dump(cover, ctx.c_mode); 1601c537871Santon if (check_coverage(cover, ctx.c_mode, ctx.c_bufsize, tests[i].coverage)) 1619257d67bSanton error = 1; 16245297697Santon 1631c537871Santon if (munmap(cover, ctx.c_bufsize * sizeof(unsigned long)) == -1) 16445297697Santon err(1, "munmap"); 165e298ef25Santon if (ctx.c_fd != -1) { 166e298ef25Santon if (close(ctx.c_fd) == -1) 167e298ef25Santon err(1, "close"); 168e298ef25Santon } 16945297697Santon 1709257d67bSanton return error; 17145297697Santon } 17245297697Santon 17345297697Santon static __dead void 17445297697Santon usage(void) 17545297697Santon { 176d9377ba7Santon fprintf(stderr, "usage: kcov [-Epv] [-b fraction] -m mode test\n"); 17745297697Santon exit(1); 17845297697Santon } 17945297697Santon 18045297697Santon static void 18145297697Santon do_syscall(void) 18245297697Santon { 18345297697Santon getpid(); 18445297697Santon } 18545297697Santon 1863bb8297cSanton static int 1873bb8297cSanton check_coverage(const unsigned long *cover, int mode, unsigned long maxsize, 1883bb8297cSanton int nonzero) 1893bb8297cSanton { 190a4101078Santon unsigned long arg1, arg2, exp, i, pc, type; 1913bb8297cSanton int error = 0; 1923bb8297cSanton 193*739cf936Santon if (nonzero == -1) { 194*739cf936Santon return 0; 195*739cf936Santon } else if (nonzero && cover[0] == 0) { 1963bb8297cSanton warnx("coverage empty (count=0)\n"); 1973bb8297cSanton return 1; 1983bb8297cSanton } else if (!nonzero && cover[0] != 0) { 1993bb8297cSanton warnx("coverage not empty (count=%lu)\n", *cover); 2003bb8297cSanton return 1; 2013bb8297cSanton } else if (cover[0] >= maxsize) { 2021c537871Santon warnx("coverage overflow (count=%lu, max=%lu)\n", 2031c537871Santon *cover, maxsize); 2043bb8297cSanton return 1; 2053bb8297cSanton } 2063bb8297cSanton 207a4101078Santon if (mode == KCOV_MODE_TRACE_CMP) { 208a4101078Santon if (*cover * 4 >= maxsize) { 209a4101078Santon warnx("coverage cmp overflow (count=%lu, max=%lu)\n", 210a4101078Santon *cover * 4, maxsize); 211a4101078Santon return 1; 212a4101078Santon } 213a4101078Santon 214a4101078Santon for (i = 0; i < cover[0]; i++) { 215a4101078Santon type = cover[i * 4 + 1]; 216a4101078Santon arg1 = cover[i * 4 + 2]; 217a4101078Santon arg2 = cover[i * 4 + 3]; 218a4101078Santon pc = cover[i * 4 + 4]; 219a4101078Santon 220a4101078Santon exp = type >> 1; 221a4101078Santon if (exp <= 3) 222a4101078Santon continue; 223a4101078Santon 224a4101078Santon warnx("coverage cmp invalid size (i=%lu, exp=%lx, " 225a4101078Santon "const=%ld, arg1=%lu, arg2=%lu, pc=%p)\n", 226a4101078Santon i, exp, type & 0x1, arg1, arg2, (void *)pc); 227a4101078Santon error = 1; 228a4101078Santon } 229a4101078Santon } 230a4101078Santon 2313bb8297cSanton return error; 2323bb8297cSanton } 2333bb8297cSanton 23445297697Santon static void 2353bb8297cSanton dump(const unsigned long *cover, int mode) 23645297697Santon { 23745297697Santon unsigned long i; 2383bb8297cSanton int stride = 1; 23945297697Santon 240a4101078Santon if (mode == KCOV_MODE_TRACE_CMP) 241a4101078Santon stride = 4; 242a4101078Santon 24345297697Santon for (i = 0; i < cover[0]; i++) 244db9a2a8dSanton printf("%p\n", (void *)cover[i * stride + stride]); 24545297697Santon } 24645297697Santon 24745297697Santon static int 24845297697Santon kcov_open(void) 24945297697Santon { 25045297697Santon int fd; 25145297697Santon 25245297697Santon fd = open("/dev/kcov", O_RDWR); 25345297697Santon if (fd == -1) 25445297697Santon err(1, "open: /dev/kcov"); 25545297697Santon return fd; 25645297697Santon } 25745297697Santon 25845297697Santon static void 2590e2965f9Santon kcov_enable(int fd, int mode) 26045297697Santon { 2610e2965f9Santon if (ioctl(fd, KIOENABLE, &mode) == -1) 26245297697Santon err(1, "ioctl: KIOENABLE"); 26345297697Santon } 26445297697Santon 26545297697Santon static void 26645297697Santon kcov_disable(int fd) 26745297697Santon { 26845297697Santon if (ioctl(fd, KIODISABLE) == -1) 26945297697Santon err(1, "ioctl: KIODISABLE"); 27045297697Santon } 27145297697Santon 27245297697Santon /* 27345297697Santon * Close before mmap. 27445297697Santon */ 27545297697Santon static int 276e298ef25Santon test_close(struct context *ctx) 27745297697Santon { 27845297697Santon int fd; 27945297697Santon 28045297697Santon fd = kcov_open(); 28145297697Santon close(fd); 28245297697Santon return 0; 28345297697Santon } 28445297697Santon 28545297697Santon /* 28645297697Santon * Coverage of current thread. 28745297697Santon */ 28845297697Santon static int 289e298ef25Santon test_coverage(struct context *ctx) 29045297697Santon { 2911c537871Santon kcov_enable(ctx->c_fd, ctx->c_mode); 29245297697Santon do_syscall(); 2931c537871Santon kcov_disable(ctx->c_fd); 29445297697Santon return 0; 29545297697Santon } 29645297697Santon 297aad1a0fbSanton static void * 298aad1a0fbSanton closer(void *arg) 299aad1a0fbSanton { 300e298ef25Santon struct context *ctx = arg; 301aad1a0fbSanton 3021c537871Santon close(ctx->c_fd); 303aad1a0fbSanton return NULL; 304aad1a0fbSanton } 305aad1a0fbSanton 306aad1a0fbSanton /* 307aad1a0fbSanton * Close kcov descriptor in another thread during tracing. 308aad1a0fbSanton */ 309aad1a0fbSanton static int 310e298ef25Santon test_dying(struct context *ctx) 311aad1a0fbSanton { 312aad1a0fbSanton pthread_t th; 313aad1a0fbSanton int error; 314aad1a0fbSanton 3151c537871Santon kcov_enable(ctx->c_fd, ctx->c_mode); 316aad1a0fbSanton 3171c537871Santon if ((error = pthread_create(&th, NULL, closer, (void *)ctx))) 318aad1a0fbSanton errc(1, error, "pthread_create"); 319aad1a0fbSanton if ((error = pthread_join(th, NULL))) 320aad1a0fbSanton errc(1, error, "pthread_join"); 321aad1a0fbSanton 322e298ef25Santon error = 0; 3231c537871Santon if (close(ctx->c_fd) == -1) { 324aad1a0fbSanton if (errno != EBADF) 325aad1a0fbSanton err(1, "close"); 326aad1a0fbSanton } else { 327aad1a0fbSanton warnx("expected kcov descriptor to be closed"); 328e298ef25Santon error = 1; 329aad1a0fbSanton } 330e298ef25Santon ctx->c_fd = -1; 331aad1a0fbSanton 332e298ef25Santon return error; 333aad1a0fbSanton } 334aad1a0fbSanton 33545297697Santon /* 33645297697Santon * Coverage of thread after exec. 33745297697Santon */ 33845297697Santon static int 339e298ef25Santon test_exec(struct context *ctx) 34045297697Santon { 34145297697Santon pid_t pid; 34245297697Santon int status; 34345297697Santon 34445297697Santon pid = fork(); 34545297697Santon if (pid == -1) 34645297697Santon err(1, "fork"); 34745297697Santon if (pid == 0) { 3481c537871Santon kcov_enable(ctx->c_fd, ctx->c_mode); 34945297697Santon execlp(self, self, "-E", NULL); 35045297697Santon _exit(1); 35145297697Santon } 35245297697Santon 35345297697Santon if (waitpid(pid, &status, 0) == -1) 35445297697Santon err(1, "waitpid"); 35545297697Santon if (WIFSIGNALED(status)) { 35645297697Santon warnx("terminated by signal (%d)", WTERMSIG(status)); 35745297697Santon return 1; 35845297697Santon } else if (WEXITSTATUS(status) != 0) { 35945297697Santon warnx("non-zero exit (%d)", WEXITSTATUS(status)); 36045297697Santon return 1; 36145297697Santon } 36245297697Santon 36345297697Santon /* Upon exit, the kcov descriptor must be reusable again. */ 3641c537871Santon kcov_enable(ctx->c_fd, ctx->c_mode); 3651c537871Santon kcov_disable(ctx->c_fd); 36645297697Santon 36745297697Santon return 0; 36845297697Santon } 36945297697Santon 37045297697Santon /* 37145297697Santon * Coverage of thread after fork. 37245297697Santon */ 37345297697Santon static int 374e298ef25Santon test_fork(struct context *ctx) 37545297697Santon { 37645297697Santon pid_t pid; 37745297697Santon int status; 37845297697Santon 37945297697Santon pid = fork(); 38045297697Santon if (pid == -1) 38145297697Santon err(1, "fork"); 38245297697Santon if (pid == 0) { 3831c537871Santon kcov_enable(ctx->c_fd, ctx->c_mode); 38445297697Santon do_syscall(); 38545297697Santon _exit(0); 38645297697Santon } 38745297697Santon 38845297697Santon if (waitpid(pid, &status, 0) == -1) 38945297697Santon err(1, "waitpid"); 39045297697Santon if (WIFSIGNALED(status)) { 39145297697Santon warnx("terminated by signal (%d)", WTERMSIG(status)); 39245297697Santon return 1; 39345297697Santon } else if (WEXITSTATUS(status) != 0) { 39445297697Santon warnx("non-zero exit (%d)", WEXITSTATUS(status)); 39545297697Santon return 1; 39645297697Santon } 39745297697Santon 39845297697Santon /* Upon exit, the kcov descriptor must be reusable again. */ 3991c537871Santon kcov_enable(ctx->c_fd, ctx->c_mode); 4001c537871Santon kcov_disable(ctx->c_fd); 40145297697Santon 40245297697Santon return 0; 40345297697Santon } 40445297697Santon 40545297697Santon /* 406e3865369Santon * Open /dev/kcov more than once. 40745297697Santon */ 40845297697Santon static int 409e298ef25Santon test_open(struct context *ctx) 410e3865369Santon { 411e3865369Santon unsigned long *cover; 412e3865369Santon int fd; 4133bb8297cSanton int error = 0; 414e3865369Santon 415e3865369Santon fd = kcov_open(); 4161c537871Santon if (ioctl(fd, KIOSETBUFSIZE, &ctx->c_bufsize) == -1) 417e3865369Santon err(1, "ioctl: KIOSETBUFSIZE"); 4181c537871Santon cover = mmap(NULL, ctx->c_bufsize * sizeof(unsigned long), 419e3865369Santon PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 420e3865369Santon if (cover == MAP_FAILED) 421e3865369Santon err(1, "mmap"); 422e3865369Santon 4231c537871Santon kcov_enable(fd, ctx->c_mode); 424e3865369Santon do_syscall(); 425e3865369Santon kcov_disable(fd); 426e3865369Santon 4271c537871Santon error = check_coverage(cover, ctx->c_mode, ctx->c_bufsize, 1); 4283bb8297cSanton 4291c537871Santon if (munmap(cover, ctx->c_bufsize * sizeof(unsigned long))) 430e3865369Santon err(1, "munmap"); 431e3865369Santon close(fd); 4323bb8297cSanton 4333bb8297cSanton return error; 434e3865369Santon } 435e3865369Santon 436e3865369Santon /* 437e298ef25Santon * Remote taskq coverage. One reliable way to trigger a task on behalf of the 438e298ef25Santon * running process is to monitor a kqueue file descriptor using kqueue. 439e298ef25Santon */ 440e298ef25Santon static int 441e298ef25Santon test_remote(struct context *ctx) 442e298ef25Santon { 443e298ef25Santon struct kio_remote_attach remote = { 444e298ef25Santon .subsystem = KCOV_REMOTE_COMMON, 445e298ef25Santon .id = 0, 446e298ef25Santon }; 447e298ef25Santon struct kevent kev; 448e298ef25Santon int kq1, kq2, pip[2]; 449e298ef25Santon int x = 0; 450e298ef25Santon 451e298ef25Santon if (ioctl(ctx->c_fd, KIOREMOTEATTACH, &remote) == -1) 452e298ef25Santon err(1, "ioctl: KIOREMOTEATTACH"); 453e298ef25Santon kcov_enable(ctx->c_fd, ctx->c_mode); 454e298ef25Santon 455e298ef25Santon kq1 = kqueue(); 456e298ef25Santon if (kq1 == -1) 457e298ef25Santon err(1, "kqueue"); 458e298ef25Santon kq2 = kqueue(); 459e298ef25Santon if (kq1 == -1) 460e298ef25Santon err(1, "kqueue"); 461e298ef25Santon EV_SET(&kev, kq2, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL); 462e298ef25Santon if (kevent(kq1, &kev, 1, NULL, 0, NULL) == -1) 463e298ef25Santon err(1, "kqueue"); 464e298ef25Santon 465e298ef25Santon if (pipe(pip) == -1) 466e298ef25Santon err(1, "pipe"); 467e298ef25Santon 468e298ef25Santon EV_SET(&kev, pip[0], EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL); 469e298ef25Santon if (kevent(kq2, &kev, 1, NULL, 0, NULL) == -1) 470e298ef25Santon err(1, "kqueue"); 471e298ef25Santon (void)write(pip[1], &x, sizeof(x)); 472e298ef25Santon 473e298ef25Santon if (kevent(kq1, NULL, 0, &kev, 1, NULL) == -1) 474e298ef25Santon err(1, "kevent"); 475e298ef25Santon 476e298ef25Santon kcov_disable(ctx->c_fd); 477e298ef25Santon 478e298ef25Santon return 0; 479e298ef25Santon } 480e298ef25Santon 481e298ef25Santon /* 482e298ef25Santon * Close with remote coverage enabled. 483e298ef25Santon */ 484e298ef25Santon static int 485e298ef25Santon test_remote_close(struct context *ctx) 486e298ef25Santon { 487e298ef25Santon struct kio_remote_attach remote = { 488e298ef25Santon .subsystem = KCOV_REMOTE_COMMON, 489e298ef25Santon .id = 0, 490e298ef25Santon }; 491e298ef25Santon 492e298ef25Santon if (ioctl(ctx->c_fd, KIOREMOTEATTACH, &remote) == -1) 493e298ef25Santon err(1, "ioctl: KIOREMOTEATTACH"); 494e298ef25Santon kcov_enable(ctx->c_fd, ctx->c_mode); 495e298ef25Santon if (close(ctx->c_fd) == -1) 496e298ef25Santon err(1, "close"); 497e298ef25Santon ctx->c_fd = kcov_open(); 498e298ef25Santon return 0; 499e298ef25Santon } 500e298ef25Santon 501e298ef25Santon /* 502*739cf936Santon * Remote interrupt coverage. There's no reliable way to enter a remote section 503*739cf936Santon * in interrupt context. This test can however by used to examine the coverage 504*739cf936Santon * collected in interrupt context: 505*739cf936Santon * 506*739cf936Santon * $ until [ -s cov ]; do kcov -v -m pc remote-interrupt >cov; done 507*739cf936Santon */ 508*739cf936Santon static int 509*739cf936Santon test_remote_interrupt(struct context *ctx) 510*739cf936Santon { 511*739cf936Santon struct kio_remote_attach remote = { 512*739cf936Santon .subsystem = KCOV_REMOTE_COMMON, 513*739cf936Santon .id = 0, 514*739cf936Santon }; 515*739cf936Santon int i; 516*739cf936Santon 517*739cf936Santon if (ioctl(ctx->c_fd, KIOREMOTEATTACH, &remote) == -1) 518*739cf936Santon err(1, "ioctl: KIOREMOTEATTACH"); 519*739cf936Santon kcov_enable(ctx->c_fd, ctx->c_mode); 520*739cf936Santon 521*739cf936Santon for (i = 0; i < 100; i++) 522*739cf936Santon (void)getpid(); 523*739cf936Santon 524*739cf936Santon kcov_disable(ctx->c_fd); 525*739cf936Santon 526*739cf936Santon return 0; 527*739cf936Santon } 528*739cf936Santon 529*739cf936Santon /* 530e3865369Santon * State transitions. 531e3865369Santon */ 532e3865369Santon static int 533e298ef25Santon test_state(struct context *ctx) 53445297697Santon { 5351c537871Santon if (ioctl(ctx->c_fd, KIOENABLE, &ctx->c_mode) == -1) { 5360e2965f9Santon warn("KIOSETBUFSIZE -> KIOENABLE"); 53745297697Santon return 1; 53845297697Santon } 5391c537871Santon if (ioctl(ctx->c_fd, KIODISABLE) == -1) { 5400e2965f9Santon warn("KIOENABLE -> KIODISABLE"); 54145297697Santon return 1; 54245297697Santon } 5431c537871Santon if (ioctl(ctx->c_fd, KIOSETBUFSIZE, 0) != -1) { 54445297697Santon warnx("KIOSETBUFSIZE -> KIOSETBUFSIZE"); 54545297697Santon return 1; 54645297697Santon } 5471c537871Santon if (ioctl(ctx->c_fd, KIODISABLE) != -1) { 54845297697Santon warnx("KIOSETBUFSIZE -> KIODISABLE"); 54945297697Santon return 1; 55045297697Santon } 55145297697Santon 5521c537871Santon kcov_enable(ctx->c_fd, ctx->c_mode); 5531c537871Santon if (ioctl(ctx->c_fd, KIOENABLE, &ctx->c_mode) != -1) { 55445297697Santon warnx("KIOENABLE -> KIOENABLE"); 55545297697Santon return 1; 55645297697Santon } 5571c537871Santon if (ioctl(ctx->c_fd, KIOSETBUFSIZE, 0) != -1) { 55845297697Santon warnx("KIOENABLE -> KIOSETBUFSIZE"); 55945297697Santon return 1; 56045297697Santon } 5611c537871Santon kcov_disable(ctx->c_fd); 56245297697Santon 56345297697Santon return 0; 56445297697Santon } 565