1*7f9e6b6fSanton /* $OpenBSD: kcov.c,v 1.16 2021/12/29 07:16:30 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> 24*7f9e6b6fSanton #include <sys/socket.h> 25*7f9e6b6fSanton #include <sys/un.h> 2645297697Santon #include <sys/wait.h> 2745297697Santon 2845297697Santon #include <err.h> 2945297697Santon #include <errno.h> 3045297697Santon #include <fcntl.h> 31aad1a0fbSanton #include <pthread.h> 3245297697Santon #include <stdio.h> 3345297697Santon #include <stdlib.h> 349257d67bSanton #include <string.h> 3545297697Santon #include <unistd.h> 3645297697Santon 371c537871Santon struct context { 381c537871Santon int c_fd; 391c537871Santon int c_mode; 401c537871Santon unsigned long c_bufsize; 411c537871Santon }; 421c537871Santon 43e298ef25Santon static int test_close(struct context *); 44e298ef25Santon static int test_coverage(struct context *); 45e298ef25Santon static int test_dying(struct context *); 46e298ef25Santon static int test_exec(struct context *); 47*7f9e6b6fSanton static int test_fdsend(struct context *); 48e298ef25Santon static int test_fork(struct context *); 49e298ef25Santon static int test_open(struct context *); 50e298ef25Santon static int test_remote(struct context *); 51e298ef25Santon static int test_remote_close(struct context *); 52739cf936Santon static int test_remote_interrupt(struct context *); 53e298ef25Santon static int test_state(struct context *); 5445297697Santon 553bb8297cSanton static int check_coverage(const unsigned long *, int, unsigned long, int); 5645297697Santon static void do_syscall(void); 573bb8297cSanton static void dump(const unsigned long *, int mode); 5845297697Santon static void kcov_disable(int); 590e2965f9Santon static void kcov_enable(int, int); 6045297697Santon static int kcov_open(void); 6145297697Santon static __dead void usage(void); 6245297697Santon 6345297697Santon static const char *self; 6445297697Santon 6545297697Santon int 6645297697Santon main(int argc, char *argv[]) 6745297697Santon { 6845297697Santon struct { 6945297697Santon const char *name; 70e298ef25Santon int (*fn)(struct context *); 7145297697Santon int coverage; /* test must produce coverage */ 7245297697Santon } tests[] = { 7345297697Santon { "close", test_close, 0 }, 74e3865369Santon { "coverage", test_coverage, 1 }, 75aad1a0fbSanton { "dying", test_dying, 1 }, 76e3865369Santon { "exec", test_exec, 1 }, 77*7f9e6b6fSanton { "fdsend", test_fdsend, -1 }, 78e3865369Santon { "fork", test_fork, 1 }, 79e3865369Santon { "open", test_open, 0 }, 80e298ef25Santon { "remote", test_remote, 1 }, 81e298ef25Santon { "remote-close", test_remote_close, 0 }, 82739cf936Santon { "remote-interrupt", test_remote_interrupt, -1 }, 83e3865369Santon { "state", test_state, 1 }, 8445297697Santon { NULL, NULL, 0 }, 8545297697Santon }; 861c537871Santon struct context ctx; 87078ed3e5Santon const char *errstr; 88078ed3e5Santon unsigned long *cover, frac; 891c537871Santon int c, i; 909257d67bSanton int error = 0; 9145297697Santon int prereq = 0; 9245297697Santon int reexec = 0; 9345297697Santon int verbose = 0; 9445297697Santon 9545297697Santon self = argv[0]; 9645297697Santon 971c537871Santon memset(&ctx, 0, sizeof(ctx)); 981c537871Santon ctx.c_bufsize = 256 << 10; 991c537871Santon 100078ed3e5Santon while ((c = getopt(argc, argv, "b:Em:pv")) != -1) 10145297697Santon switch (c) { 102078ed3e5Santon case 'b': 103078ed3e5Santon frac = strtonum(optarg, 1, 100, &errstr); 104078ed3e5Santon if (frac == 0) 105078ed3e5Santon errx(1, "buffer size fraction %s", errstr); 1061c537871Santon else if (frac > ctx.c_bufsize) 107078ed3e5Santon errx(1, "buffer size fraction too large"); 1081c537871Santon ctx.c_bufsize /= frac; 109078ed3e5Santon break; 11045297697Santon case 'E': 11145297697Santon reexec = 1; 11245297697Santon break; 1130e2965f9Santon case 'm': 1140e2965f9Santon if (strcmp(optarg, "pc") == 0) 1151c537871Santon ctx.c_mode = KCOV_MODE_TRACE_PC; 116a4101078Santon else if (strcmp(optarg, "cmp") == 0) 1171c537871Santon ctx.c_mode = KCOV_MODE_TRACE_CMP; 1180e2965f9Santon else 1190e2965f9Santon errx(1, "unknown mode %s", optarg); 1200e2965f9Santon break; 12145297697Santon case 'p': 12245297697Santon prereq = 1; 12345297697Santon break; 12445297697Santon case 'v': 12545297697Santon verbose = 1; 12645297697Santon break; 12745297697Santon default: 12845297697Santon usage(); 12945297697Santon } 13045297697Santon argc -= optind; 13145297697Santon argv += optind; 13245297697Santon 13345297697Santon if (prereq) { 1341c537871Santon ctx.c_fd = kcov_open(); 1351c537871Santon close(ctx.c_fd); 13645297697Santon return 0; 13745297697Santon } 13845297697Santon 13945297697Santon if (reexec) { 14045297697Santon do_syscall(); 14145297697Santon return 0; 14245297697Santon } 14345297697Santon 1441c537871Santon if (ctx.c_mode == 0 || argc != 1) 1459257d67bSanton usage(); 1469257d67bSanton for (i = 0; tests[i].name != NULL; i++) 1479257d67bSanton if (strcmp(argv[0], tests[i].name) == 0) 1489257d67bSanton break; 1499257d67bSanton if (tests[i].name == NULL) 1509257d67bSanton errx(1, "%s: no such test", argv[0]); 1519257d67bSanton 1521c537871Santon ctx.c_fd = kcov_open(); 1531c537871Santon if (ioctl(ctx.c_fd, KIOSETBUFSIZE, &ctx.c_bufsize) == -1) 15445297697Santon err(1, "ioctl: KIOSETBUFSIZE"); 1551c537871Santon cover = mmap(NULL, ctx.c_bufsize * sizeof(unsigned long), 1561c537871Santon PROT_READ | PROT_WRITE, MAP_SHARED, ctx.c_fd, 0); 15745297697Santon if (cover == MAP_FAILED) 15845297697Santon err(1, "mmap"); 15945297697Santon 16045297697Santon *cover = 0; 1611c537871Santon error = tests[i].fn(&ctx); 16245297697Santon if (verbose) 1631c537871Santon dump(cover, ctx.c_mode); 1641c537871Santon if (check_coverage(cover, ctx.c_mode, ctx.c_bufsize, tests[i].coverage)) 1659257d67bSanton error = 1; 16645297697Santon 1671c537871Santon if (munmap(cover, ctx.c_bufsize * sizeof(unsigned long)) == -1) 16845297697Santon err(1, "munmap"); 169e298ef25Santon if (ctx.c_fd != -1) { 170e298ef25Santon if (close(ctx.c_fd) == -1) 171e298ef25Santon err(1, "close"); 172e298ef25Santon } 17345297697Santon 1749257d67bSanton return error; 17545297697Santon } 17645297697Santon 17745297697Santon static __dead void 17845297697Santon usage(void) 17945297697Santon { 180d9377ba7Santon fprintf(stderr, "usage: kcov [-Epv] [-b fraction] -m mode test\n"); 18145297697Santon exit(1); 18245297697Santon } 18345297697Santon 18445297697Santon static void 18545297697Santon do_syscall(void) 18645297697Santon { 18745297697Santon getpid(); 18845297697Santon } 18945297697Santon 1903bb8297cSanton static int 1913bb8297cSanton check_coverage(const unsigned long *cover, int mode, unsigned long maxsize, 1923bb8297cSanton int nonzero) 1933bb8297cSanton { 194a4101078Santon unsigned long arg1, arg2, exp, i, pc, type; 1953bb8297cSanton int error = 0; 1963bb8297cSanton 197739cf936Santon if (nonzero == -1) { 198739cf936Santon return 0; 199739cf936Santon } else if (nonzero && cover[0] == 0) { 2003bb8297cSanton warnx("coverage empty (count=0)\n"); 2013bb8297cSanton return 1; 2023bb8297cSanton } else if (!nonzero && cover[0] != 0) { 2033bb8297cSanton warnx("coverage not empty (count=%lu)\n", *cover); 2043bb8297cSanton return 1; 2053bb8297cSanton } else if (cover[0] >= maxsize) { 2061c537871Santon warnx("coverage overflow (count=%lu, max=%lu)\n", 2071c537871Santon *cover, maxsize); 2083bb8297cSanton return 1; 2093bb8297cSanton } 2103bb8297cSanton 211a4101078Santon if (mode == KCOV_MODE_TRACE_CMP) { 212a4101078Santon if (*cover * 4 >= maxsize) { 213a4101078Santon warnx("coverage cmp overflow (count=%lu, max=%lu)\n", 214a4101078Santon *cover * 4, maxsize); 215a4101078Santon return 1; 216a4101078Santon } 217a4101078Santon 218a4101078Santon for (i = 0; i < cover[0]; i++) { 219a4101078Santon type = cover[i * 4 + 1]; 220a4101078Santon arg1 = cover[i * 4 + 2]; 221a4101078Santon arg2 = cover[i * 4 + 3]; 222a4101078Santon pc = cover[i * 4 + 4]; 223a4101078Santon 224a4101078Santon exp = type >> 1; 225a4101078Santon if (exp <= 3) 226a4101078Santon continue; 227a4101078Santon 228a4101078Santon warnx("coverage cmp invalid size (i=%lu, exp=%lx, " 229a4101078Santon "const=%ld, arg1=%lu, arg2=%lu, pc=%p)\n", 230a4101078Santon i, exp, type & 0x1, arg1, arg2, (void *)pc); 231a4101078Santon error = 1; 232a4101078Santon } 233a4101078Santon } 234a4101078Santon 2353bb8297cSanton return error; 2363bb8297cSanton } 2373bb8297cSanton 23845297697Santon static void 2393bb8297cSanton dump(const unsigned long *cover, int mode) 24045297697Santon { 24145297697Santon unsigned long i; 2423bb8297cSanton int stride = 1; 24345297697Santon 244a4101078Santon if (mode == KCOV_MODE_TRACE_CMP) 245a4101078Santon stride = 4; 246a4101078Santon 24745297697Santon for (i = 0; i < cover[0]; i++) 248db9a2a8dSanton printf("%p\n", (void *)cover[i * stride + stride]); 24945297697Santon } 25045297697Santon 25145297697Santon static int 25245297697Santon kcov_open(void) 25345297697Santon { 25445297697Santon int fd; 25545297697Santon 25645297697Santon fd = open("/dev/kcov", O_RDWR); 25745297697Santon if (fd == -1) 25845297697Santon err(1, "open: /dev/kcov"); 25945297697Santon return fd; 26045297697Santon } 26145297697Santon 26245297697Santon static void 2630e2965f9Santon kcov_enable(int fd, int mode) 26445297697Santon { 2650e2965f9Santon if (ioctl(fd, KIOENABLE, &mode) == -1) 26645297697Santon err(1, "ioctl: KIOENABLE"); 26745297697Santon } 26845297697Santon 26945297697Santon static void 27045297697Santon kcov_disable(int fd) 27145297697Santon { 27245297697Santon if (ioctl(fd, KIODISABLE) == -1) 27345297697Santon err(1, "ioctl: KIODISABLE"); 27445297697Santon } 27545297697Santon 27645297697Santon /* 27745297697Santon * Close before mmap. 27845297697Santon */ 27945297697Santon static int 280e298ef25Santon test_close(struct context *ctx) 28145297697Santon { 28245297697Santon int fd; 28345297697Santon 28445297697Santon fd = kcov_open(); 28545297697Santon close(fd); 28645297697Santon return 0; 28745297697Santon } 28845297697Santon 28945297697Santon /* 29045297697Santon * Coverage of current thread. 29145297697Santon */ 29245297697Santon static int 293e298ef25Santon test_coverage(struct context *ctx) 29445297697Santon { 2951c537871Santon kcov_enable(ctx->c_fd, ctx->c_mode); 29645297697Santon do_syscall(); 2971c537871Santon kcov_disable(ctx->c_fd); 29845297697Santon return 0; 29945297697Santon } 30045297697Santon 301aad1a0fbSanton static void * 302aad1a0fbSanton closer(void *arg) 303aad1a0fbSanton { 304e298ef25Santon struct context *ctx = arg; 305aad1a0fbSanton 3061c537871Santon close(ctx->c_fd); 307aad1a0fbSanton return NULL; 308aad1a0fbSanton } 309aad1a0fbSanton 310aad1a0fbSanton /* 311aad1a0fbSanton * Close kcov descriptor in another thread during tracing. 312aad1a0fbSanton */ 313aad1a0fbSanton static int 314e298ef25Santon test_dying(struct context *ctx) 315aad1a0fbSanton { 316aad1a0fbSanton pthread_t th; 317aad1a0fbSanton int error; 318aad1a0fbSanton 3191c537871Santon kcov_enable(ctx->c_fd, ctx->c_mode); 320aad1a0fbSanton 3211c537871Santon if ((error = pthread_create(&th, NULL, closer, (void *)ctx))) 322aad1a0fbSanton errc(1, error, "pthread_create"); 323aad1a0fbSanton if ((error = pthread_join(th, NULL))) 324aad1a0fbSanton errc(1, error, "pthread_join"); 325aad1a0fbSanton 326e298ef25Santon error = 0; 3271c537871Santon if (close(ctx->c_fd) == -1) { 328aad1a0fbSanton if (errno != EBADF) 329aad1a0fbSanton err(1, "close"); 330aad1a0fbSanton } else { 331aad1a0fbSanton warnx("expected kcov descriptor to be closed"); 332e298ef25Santon error = 1; 333aad1a0fbSanton } 334e298ef25Santon ctx->c_fd = -1; 335aad1a0fbSanton 336e298ef25Santon return error; 337aad1a0fbSanton } 338aad1a0fbSanton 33945297697Santon /* 34045297697Santon * Coverage of thread after exec. 34145297697Santon */ 34245297697Santon static int 343e298ef25Santon test_exec(struct context *ctx) 34445297697Santon { 34545297697Santon pid_t pid; 34645297697Santon int status; 34745297697Santon 34845297697Santon pid = fork(); 34945297697Santon if (pid == -1) 35045297697Santon err(1, "fork"); 35145297697Santon if (pid == 0) { 3521c537871Santon kcov_enable(ctx->c_fd, ctx->c_mode); 35345297697Santon execlp(self, self, "-E", NULL); 35445297697Santon _exit(1); 35545297697Santon } 35645297697Santon 35745297697Santon if (waitpid(pid, &status, 0) == -1) 35845297697Santon err(1, "waitpid"); 35945297697Santon if (WIFSIGNALED(status)) { 36045297697Santon warnx("terminated by signal (%d)", WTERMSIG(status)); 36145297697Santon return 1; 36245297697Santon } else if (WEXITSTATUS(status) != 0) { 36345297697Santon warnx("non-zero exit (%d)", WEXITSTATUS(status)); 36445297697Santon return 1; 36545297697Santon } 36645297697Santon 36745297697Santon /* Upon exit, the kcov descriptor must be reusable again. */ 3681c537871Santon kcov_enable(ctx->c_fd, ctx->c_mode); 3691c537871Santon kcov_disable(ctx->c_fd); 37045297697Santon 37145297697Santon return 0; 37245297697Santon } 37345297697Santon 37445297697Santon /* 375*7f9e6b6fSanton * File descriptor send/receive is not allowed since remote coverage is tied to 376*7f9e6b6fSanton * the current process. 377*7f9e6b6fSanton */ 378*7f9e6b6fSanton static int 379*7f9e6b6fSanton test_fdsend(struct context *ctx) 380*7f9e6b6fSanton { 381*7f9e6b6fSanton struct msghdr msg; 382*7f9e6b6fSanton union { 383*7f9e6b6fSanton struct cmsghdr hdr; 384*7f9e6b6fSanton unsigned char buf[CMSG_SPACE(sizeof(int))]; 385*7f9e6b6fSanton } cmsgbuf; 386*7f9e6b6fSanton struct cmsghdr *cmsg; 387*7f9e6b6fSanton int pair[2]; 388*7f9e6b6fSanton 389*7f9e6b6fSanton if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) == -1) 390*7f9e6b6fSanton err(1, "socketpair"); 391*7f9e6b6fSanton 392*7f9e6b6fSanton memset(&msg, 0, sizeof(msg)); 393*7f9e6b6fSanton msg.msg_control = &cmsgbuf.buf; 394*7f9e6b6fSanton msg.msg_controllen = sizeof(cmsgbuf.buf); 395*7f9e6b6fSanton cmsg = CMSG_FIRSTHDR(&msg); 396*7f9e6b6fSanton cmsg->cmsg_len = CMSG_LEN(sizeof(int)); 397*7f9e6b6fSanton cmsg->cmsg_level = SOL_SOCKET; 398*7f9e6b6fSanton cmsg->cmsg_type = SCM_RIGHTS; 399*7f9e6b6fSanton *(int *)CMSG_DATA(cmsg) = ctx->c_fd; 400*7f9e6b6fSanton if (sendmsg(pair[1], &msg, 0) != -1) 401*7f9e6b6fSanton errx(1, "sendmsg: expected error"); 402*7f9e6b6fSanton 403*7f9e6b6fSanton close(pair[0]); 404*7f9e6b6fSanton close(pair[1]); 405*7f9e6b6fSanton return 0; 406*7f9e6b6fSanton } 407*7f9e6b6fSanton 408*7f9e6b6fSanton /* 40945297697Santon * Coverage of thread after fork. 41045297697Santon */ 41145297697Santon static int 412e298ef25Santon test_fork(struct context *ctx) 41345297697Santon { 41445297697Santon pid_t pid; 41545297697Santon int status; 41645297697Santon 41745297697Santon pid = fork(); 41845297697Santon if (pid == -1) 41945297697Santon err(1, "fork"); 42045297697Santon if (pid == 0) { 4211c537871Santon kcov_enable(ctx->c_fd, ctx->c_mode); 42245297697Santon do_syscall(); 42345297697Santon _exit(0); 42445297697Santon } 42545297697Santon 42645297697Santon if (waitpid(pid, &status, 0) == -1) 42745297697Santon err(1, "waitpid"); 42845297697Santon if (WIFSIGNALED(status)) { 42945297697Santon warnx("terminated by signal (%d)", WTERMSIG(status)); 43045297697Santon return 1; 43145297697Santon } else if (WEXITSTATUS(status) != 0) { 43245297697Santon warnx("non-zero exit (%d)", WEXITSTATUS(status)); 43345297697Santon return 1; 43445297697Santon } 43545297697Santon 43645297697Santon /* Upon exit, the kcov descriptor must be reusable again. */ 4371c537871Santon kcov_enable(ctx->c_fd, ctx->c_mode); 4381c537871Santon kcov_disable(ctx->c_fd); 43945297697Santon 44045297697Santon return 0; 44145297697Santon } 44245297697Santon 44345297697Santon /* 444e3865369Santon * Open /dev/kcov more than once. 44545297697Santon */ 44645297697Santon static int 447e298ef25Santon test_open(struct context *ctx) 448e3865369Santon { 449e3865369Santon unsigned long *cover; 450e3865369Santon int fd; 4513bb8297cSanton int error = 0; 452e3865369Santon 453e3865369Santon fd = kcov_open(); 4541c537871Santon if (ioctl(fd, KIOSETBUFSIZE, &ctx->c_bufsize) == -1) 455e3865369Santon err(1, "ioctl: KIOSETBUFSIZE"); 4561c537871Santon cover = mmap(NULL, ctx->c_bufsize * sizeof(unsigned long), 457e3865369Santon PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 458e3865369Santon if (cover == MAP_FAILED) 459e3865369Santon err(1, "mmap"); 460e3865369Santon 4611c537871Santon kcov_enable(fd, ctx->c_mode); 462e3865369Santon do_syscall(); 463e3865369Santon kcov_disable(fd); 464e3865369Santon 4651c537871Santon error = check_coverage(cover, ctx->c_mode, ctx->c_bufsize, 1); 4663bb8297cSanton 4671c537871Santon if (munmap(cover, ctx->c_bufsize * sizeof(unsigned long))) 468e3865369Santon err(1, "munmap"); 469e3865369Santon close(fd); 4703bb8297cSanton 4713bb8297cSanton return error; 472e3865369Santon } 473e3865369Santon 474e3865369Santon /* 475e298ef25Santon * Remote taskq coverage. One reliable way to trigger a task on behalf of the 476e298ef25Santon * running process is to monitor a kqueue file descriptor using kqueue. 477e298ef25Santon */ 478e298ef25Santon static int 479e298ef25Santon test_remote(struct context *ctx) 480e298ef25Santon { 481e298ef25Santon struct kio_remote_attach remote = { 482e298ef25Santon .subsystem = KCOV_REMOTE_COMMON, 483e298ef25Santon .id = 0, 484e298ef25Santon }; 485e298ef25Santon struct kevent kev; 486e298ef25Santon int kq1, kq2, pip[2]; 487e298ef25Santon int x = 0; 488e298ef25Santon 489e298ef25Santon if (ioctl(ctx->c_fd, KIOREMOTEATTACH, &remote) == -1) 490e298ef25Santon err(1, "ioctl: KIOREMOTEATTACH"); 491e298ef25Santon kcov_enable(ctx->c_fd, ctx->c_mode); 492e298ef25Santon 493e298ef25Santon kq1 = kqueue(); 494e298ef25Santon if (kq1 == -1) 495e298ef25Santon err(1, "kqueue"); 496e298ef25Santon kq2 = kqueue(); 497e298ef25Santon if (kq1 == -1) 498e298ef25Santon err(1, "kqueue"); 499e298ef25Santon EV_SET(&kev, kq2, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL); 500e298ef25Santon if (kevent(kq1, &kev, 1, NULL, 0, NULL) == -1) 501e298ef25Santon err(1, "kqueue"); 502e298ef25Santon 503e298ef25Santon if (pipe(pip) == -1) 504e298ef25Santon err(1, "pipe"); 505e298ef25Santon 506e298ef25Santon EV_SET(&kev, pip[0], EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL); 507e298ef25Santon if (kevent(kq2, &kev, 1, NULL, 0, NULL) == -1) 508e298ef25Santon err(1, "kqueue"); 509e298ef25Santon (void)write(pip[1], &x, sizeof(x)); 510e298ef25Santon 511e298ef25Santon if (kevent(kq1, NULL, 0, &kev, 1, NULL) == -1) 512e298ef25Santon err(1, "kevent"); 513e298ef25Santon 514e298ef25Santon kcov_disable(ctx->c_fd); 515e298ef25Santon 516e298ef25Santon return 0; 517e298ef25Santon } 518e298ef25Santon 519e298ef25Santon /* 520e298ef25Santon * Close with remote coverage enabled. 521e298ef25Santon */ 522e298ef25Santon static int 523e298ef25Santon test_remote_close(struct context *ctx) 524e298ef25Santon { 525e298ef25Santon struct kio_remote_attach remote = { 526e298ef25Santon .subsystem = KCOV_REMOTE_COMMON, 527e298ef25Santon .id = 0, 528e298ef25Santon }; 529e298ef25Santon 530e298ef25Santon if (ioctl(ctx->c_fd, KIOREMOTEATTACH, &remote) == -1) 531e298ef25Santon err(1, "ioctl: KIOREMOTEATTACH"); 532e298ef25Santon kcov_enable(ctx->c_fd, ctx->c_mode); 533e298ef25Santon if (close(ctx->c_fd) == -1) 534e298ef25Santon err(1, "close"); 535e298ef25Santon ctx->c_fd = kcov_open(); 536e298ef25Santon return 0; 537e298ef25Santon } 538e298ef25Santon 539e298ef25Santon /* 540739cf936Santon * Remote interrupt coverage. There's no reliable way to enter a remote section 541739cf936Santon * in interrupt context. This test can however by used to examine the coverage 542739cf936Santon * collected in interrupt context: 543739cf936Santon * 544739cf936Santon * $ until [ -s cov ]; do kcov -v -m pc remote-interrupt >cov; done 545739cf936Santon */ 546739cf936Santon static int 547739cf936Santon test_remote_interrupt(struct context *ctx) 548739cf936Santon { 549739cf936Santon struct kio_remote_attach remote = { 550739cf936Santon .subsystem = KCOV_REMOTE_COMMON, 551739cf936Santon .id = 0, 552739cf936Santon }; 553739cf936Santon int i; 554739cf936Santon 555739cf936Santon if (ioctl(ctx->c_fd, KIOREMOTEATTACH, &remote) == -1) 556739cf936Santon err(1, "ioctl: KIOREMOTEATTACH"); 557739cf936Santon kcov_enable(ctx->c_fd, ctx->c_mode); 558739cf936Santon 559739cf936Santon for (i = 0; i < 100; i++) 560739cf936Santon (void)getpid(); 561739cf936Santon 562739cf936Santon kcov_disable(ctx->c_fd); 563739cf936Santon 564739cf936Santon return 0; 565739cf936Santon } 566739cf936Santon 567739cf936Santon /* 568e3865369Santon * State transitions. 569e3865369Santon */ 570e3865369Santon static int 571e298ef25Santon test_state(struct context *ctx) 57245297697Santon { 5731c537871Santon if (ioctl(ctx->c_fd, KIOENABLE, &ctx->c_mode) == -1) { 5740e2965f9Santon warn("KIOSETBUFSIZE -> KIOENABLE"); 57545297697Santon return 1; 57645297697Santon } 5771c537871Santon if (ioctl(ctx->c_fd, KIODISABLE) == -1) { 5780e2965f9Santon warn("KIOENABLE -> KIODISABLE"); 57945297697Santon return 1; 58045297697Santon } 5811c537871Santon if (ioctl(ctx->c_fd, KIOSETBUFSIZE, 0) != -1) { 58245297697Santon warnx("KIOSETBUFSIZE -> KIOSETBUFSIZE"); 58345297697Santon return 1; 58445297697Santon } 5851c537871Santon if (ioctl(ctx->c_fd, KIODISABLE) != -1) { 58645297697Santon warnx("KIOSETBUFSIZE -> KIODISABLE"); 58745297697Santon return 1; 58845297697Santon } 58945297697Santon 5901c537871Santon kcov_enable(ctx->c_fd, ctx->c_mode); 5911c537871Santon if (ioctl(ctx->c_fd, KIOENABLE, &ctx->c_mode) != -1) { 59245297697Santon warnx("KIOENABLE -> KIOENABLE"); 59345297697Santon return 1; 59445297697Santon } 5951c537871Santon if (ioctl(ctx->c_fd, KIOSETBUFSIZE, 0) != -1) { 59645297697Santon warnx("KIOENABLE -> KIOSETBUFSIZE"); 59745297697Santon return 1; 59845297697Santon } 5991c537871Santon kcov_disable(ctx->c_fd); 60045297697Santon 60145297697Santon return 0; 60245297697Santon } 603