1*dd54ee78Santon /* $OpenBSD: kcov.c,v 1.17 2022/01/11 06:01:15 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>
247f9e6b6fSanton #include <sys/socket.h>
257f9e6b6fSanton #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 *);
477f9e6b6fSanton 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
main(int argc,char * argv[])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 },
75*dd54ee78Santon { "dying", test_dying, -1 },
76e3865369Santon { "exec", test_exec, 1 },
777f9e6b6fSanton { "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
usage(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
do_syscall(void)18545297697Santon do_syscall(void)
18645297697Santon {
18745297697Santon getpid();
18845297697Santon }
18945297697Santon
1903bb8297cSanton static int
check_coverage(const unsigned long * cover,int mode,unsigned long maxsize,int nonzero)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
dump(const unsigned long * cover,int mode)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
kcov_open(void)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
kcov_enable(int fd,int mode)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
kcov_disable(int fd)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
test_close(struct context * ctx)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
test_coverage(struct context * ctx)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 *
closer(void * arg)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
test_dying(struct context * ctx)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
test_exec(struct context * ctx)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 /*
3757f9e6b6fSanton * File descriptor send/receive is not allowed since remote coverage is tied to
3767f9e6b6fSanton * the current process.
3777f9e6b6fSanton */
3787f9e6b6fSanton static int
test_fdsend(struct context * ctx)3797f9e6b6fSanton test_fdsend(struct context *ctx)
3807f9e6b6fSanton {
3817f9e6b6fSanton struct msghdr msg;
3827f9e6b6fSanton union {
3837f9e6b6fSanton struct cmsghdr hdr;
3847f9e6b6fSanton unsigned char buf[CMSG_SPACE(sizeof(int))];
3857f9e6b6fSanton } cmsgbuf;
3867f9e6b6fSanton struct cmsghdr *cmsg;
3877f9e6b6fSanton int pair[2];
3887f9e6b6fSanton
3897f9e6b6fSanton if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) == -1)
3907f9e6b6fSanton err(1, "socketpair");
3917f9e6b6fSanton
3927f9e6b6fSanton memset(&msg, 0, sizeof(msg));
3937f9e6b6fSanton msg.msg_control = &cmsgbuf.buf;
3947f9e6b6fSanton msg.msg_controllen = sizeof(cmsgbuf.buf);
3957f9e6b6fSanton cmsg = CMSG_FIRSTHDR(&msg);
3967f9e6b6fSanton cmsg->cmsg_len = CMSG_LEN(sizeof(int));
3977f9e6b6fSanton cmsg->cmsg_level = SOL_SOCKET;
3987f9e6b6fSanton cmsg->cmsg_type = SCM_RIGHTS;
3997f9e6b6fSanton *(int *)CMSG_DATA(cmsg) = ctx->c_fd;
4007f9e6b6fSanton if (sendmsg(pair[1], &msg, 0) != -1)
4017f9e6b6fSanton errx(1, "sendmsg: expected error");
4027f9e6b6fSanton
4037f9e6b6fSanton close(pair[0]);
4047f9e6b6fSanton close(pair[1]);
4057f9e6b6fSanton return 0;
4067f9e6b6fSanton }
4077f9e6b6fSanton
4087f9e6b6fSanton /*
40945297697Santon * Coverage of thread after fork.
41045297697Santon */
41145297697Santon static int
test_fork(struct context * ctx)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
test_open(struct context * ctx)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
test_remote(struct context * ctx)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
test_remote_close(struct context * ctx)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
test_remote_interrupt(struct context * ctx)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
test_state(struct context * ctx)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