xref: /openbsd/regress/sys/dev/kcov/kcov.c (revision e298ef25)
1*e298ef25Santon /*	$OpenBSD: kcov.c,v 1.13 2020/08/01 08:44:57 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 
19*e298ef25Santon #include <sys/types.h>
20*e298ef25Santon #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 
41*e298ef25Santon static int test_close(struct context *);
42*e298ef25Santon static int test_coverage(struct context *);
43*e298ef25Santon static int test_dying(struct context *);
44*e298ef25Santon static int test_exec(struct context *);
45*e298ef25Santon static int test_fork(struct context *);
46*e298ef25Santon static int test_open(struct context *);
47*e298ef25Santon static int test_remote(struct context *);
48*e298ef25Santon static int test_remote_close(struct context *);
49*e298ef25Santon static int test_state(struct context *);
5045297697Santon 
513bb8297cSanton static int check_coverage(const unsigned long *, int, unsigned long, int);
5245297697Santon static void do_syscall(void);
533bb8297cSanton static void dump(const unsigned long *, int mode);
5445297697Santon static void kcov_disable(int);
550e2965f9Santon static void kcov_enable(int, int);
5645297697Santon static int kcov_open(void);
5745297697Santon static __dead void usage(void);
5845297697Santon 
5945297697Santon static const char *self;
6045297697Santon 
6145297697Santon int
6245297697Santon main(int argc, char *argv[])
6345297697Santon {
6445297697Santon 	struct {
6545297697Santon 		const char *name;
66*e298ef25Santon 		int (*fn)(struct context *);
6745297697Santon 		int coverage;		/* test must produce coverage */
6845297697Santon 	} tests[] = {
6945297697Santon 		{ "close",		test_close,		0 },
70e3865369Santon 		{ "coverage",		test_coverage,		1 },
71aad1a0fbSanton 		{ "dying",		test_dying,		1 },
72e3865369Santon 		{ "exec",		test_exec,		1 },
73e3865369Santon 		{ "fork",		test_fork,		1 },
74e3865369Santon 		{ "open",		test_open,		0 },
75*e298ef25Santon 		{ "remote",		test_remote,		1 },
76*e298ef25Santon 		{ "remote-close",	test_remote_close,	0 },
77e3865369Santon 		{ "state",		test_state,		1 },
7845297697Santon 		{ NULL,			NULL,			0 },
7945297697Santon 	};
801c537871Santon 	struct context ctx;
81078ed3e5Santon 	const char *errstr;
82078ed3e5Santon 	unsigned long *cover, frac;
831c537871Santon 	int c, i;
849257d67bSanton 	int error = 0;
8545297697Santon 	int prereq = 0;
8645297697Santon 	int reexec = 0;
8745297697Santon 	int verbose = 0;
8845297697Santon 
8945297697Santon 	self = argv[0];
9045297697Santon 
911c537871Santon 	memset(&ctx, 0, sizeof(ctx));
921c537871Santon 	ctx.c_bufsize = 256 << 10;
931c537871Santon 
94078ed3e5Santon 	while ((c = getopt(argc, argv, "b:Em:pv")) != -1)
9545297697Santon 		switch (c) {
96078ed3e5Santon 		case 'b':
97078ed3e5Santon 			frac = strtonum(optarg, 1, 100, &errstr);
98078ed3e5Santon 			if (frac == 0)
99078ed3e5Santon 				errx(1, "buffer size fraction %s", errstr);
1001c537871Santon 			else if (frac > ctx.c_bufsize)
101078ed3e5Santon 				errx(1, "buffer size fraction too large");
1021c537871Santon 			ctx.c_bufsize /= frac;
103078ed3e5Santon 			break;
10445297697Santon 		case 'E':
10545297697Santon 			reexec = 1;
10645297697Santon 			break;
1070e2965f9Santon 		case 'm':
1080e2965f9Santon 			if (strcmp(optarg, "pc") == 0)
1091c537871Santon 				ctx.c_mode = KCOV_MODE_TRACE_PC;
110a4101078Santon 			else if (strcmp(optarg, "cmp") == 0)
1111c537871Santon 				ctx.c_mode = KCOV_MODE_TRACE_CMP;
1120e2965f9Santon 			else
1130e2965f9Santon 				errx(1, "unknown mode %s", optarg);
1140e2965f9Santon 			break;
11545297697Santon 		case 'p':
11645297697Santon 			prereq = 1;
11745297697Santon 			break;
11845297697Santon 		case 'v':
11945297697Santon 			verbose = 1;
12045297697Santon 			break;
12145297697Santon 		default:
12245297697Santon 			usage();
12345297697Santon 		}
12445297697Santon 	argc -= optind;
12545297697Santon 	argv += optind;
12645297697Santon 
12745297697Santon 	if (prereq) {
1281c537871Santon 		ctx.c_fd = kcov_open();
1291c537871Santon 		close(ctx.c_fd);
13045297697Santon 		return 0;
13145297697Santon 	}
13245297697Santon 
13345297697Santon 	if (reexec) {
13445297697Santon 		do_syscall();
13545297697Santon 		return 0;
13645297697Santon 	}
13745297697Santon 
1381c537871Santon 	if (ctx.c_mode == 0 || argc != 1)
1399257d67bSanton 		usage();
1409257d67bSanton 	for (i = 0; tests[i].name != NULL; i++)
1419257d67bSanton 		if (strcmp(argv[0], tests[i].name) == 0)
1429257d67bSanton 			break;
1439257d67bSanton 	if (tests[i].name == NULL)
1449257d67bSanton 		errx(1, "%s: no such test", argv[0]);
1459257d67bSanton 
1461c537871Santon 	ctx.c_fd = kcov_open();
1471c537871Santon 	if (ioctl(ctx.c_fd, KIOSETBUFSIZE, &ctx.c_bufsize) == -1)
14845297697Santon 		err(1, "ioctl: KIOSETBUFSIZE");
1491c537871Santon 	cover = mmap(NULL, ctx.c_bufsize * sizeof(unsigned long),
1501c537871Santon 	    PROT_READ | PROT_WRITE, MAP_SHARED, ctx.c_fd, 0);
15145297697Santon 	if (cover == MAP_FAILED)
15245297697Santon 		err(1, "mmap");
15345297697Santon 
15445297697Santon 	*cover = 0;
1551c537871Santon 	error = tests[i].fn(&ctx);
15645297697Santon 	if (verbose)
1571c537871Santon 		dump(cover, ctx.c_mode);
1581c537871Santon 	if (check_coverage(cover, ctx.c_mode, ctx.c_bufsize, tests[i].coverage))
1599257d67bSanton 		error = 1;
16045297697Santon 
1611c537871Santon 	if (munmap(cover, ctx.c_bufsize * sizeof(unsigned long)) == -1)
16245297697Santon 		err(1, "munmap");
163*e298ef25Santon 	if (ctx.c_fd != -1) {
164*e298ef25Santon 		if (close(ctx.c_fd) == -1)
165*e298ef25Santon 			err(1, "close");
166*e298ef25Santon 	}
16745297697Santon 
1689257d67bSanton 	return error;
16945297697Santon }
17045297697Santon 
17145297697Santon static __dead void
17245297697Santon usage(void)
17345297697Santon {
174078ed3e5Santon 	fprintf(stderr, "usage: kcov [-Epv] [-b fraction] -t mode test\n");
17545297697Santon 	exit(1);
17645297697Santon }
17745297697Santon 
17845297697Santon static void
17945297697Santon do_syscall(void)
18045297697Santon {
18145297697Santon 	getpid();
18245297697Santon }
18345297697Santon 
1843bb8297cSanton static int
1853bb8297cSanton check_coverage(const unsigned long *cover, int mode, unsigned long maxsize,
1863bb8297cSanton     int nonzero)
1873bb8297cSanton {
188a4101078Santon 	unsigned long arg1, arg2, exp, i, pc, type;
1893bb8297cSanton 	int error = 0;
1903bb8297cSanton 
1913bb8297cSanton 	if (nonzero && cover[0] == 0) {
1923bb8297cSanton 		warnx("coverage empty (count=0)\n");
1933bb8297cSanton 		return 1;
1943bb8297cSanton 	} else if (!nonzero && cover[0] != 0) {
1953bb8297cSanton 		warnx("coverage not empty (count=%lu)\n", *cover);
1963bb8297cSanton 		return 1;
1973bb8297cSanton 	} else if (cover[0] >= maxsize) {
1981c537871Santon 		warnx("coverage overflow (count=%lu, max=%lu)\n",
1991c537871Santon 		    *cover, maxsize);
2003bb8297cSanton 		return 1;
2013bb8297cSanton 	}
2023bb8297cSanton 
203a4101078Santon 	if (mode == KCOV_MODE_TRACE_CMP) {
204a4101078Santon 		if (*cover * 4 >= maxsize) {
205a4101078Santon 			warnx("coverage cmp overflow (count=%lu, max=%lu)\n",
206a4101078Santon 			    *cover * 4, maxsize);
207a4101078Santon 			return 1;
208a4101078Santon 		}
209a4101078Santon 
210a4101078Santon 		for (i = 0; i < cover[0]; i++) {
211a4101078Santon 			type = cover[i * 4 + 1];
212a4101078Santon 			arg1 = cover[i * 4 + 2];
213a4101078Santon 			arg2 = cover[i * 4 + 3];
214a4101078Santon 			pc = cover[i * 4 + 4];
215a4101078Santon 
216a4101078Santon 			exp = type >> 1;
217a4101078Santon 			if (exp <= 3)
218a4101078Santon 				continue;
219a4101078Santon 
220a4101078Santon 			warnx("coverage cmp invalid size (i=%lu, exp=%lx, "
221a4101078Santon 			    "const=%ld, arg1=%lu, arg2=%lu, pc=%p)\n",
222a4101078Santon 			    i, exp, type & 0x1, arg1, arg2, (void *)pc);
223a4101078Santon 			error = 1;
224a4101078Santon 		}
225a4101078Santon 	}
226a4101078Santon 
2273bb8297cSanton 	return error;
2283bb8297cSanton }
2293bb8297cSanton 
23045297697Santon static void
2313bb8297cSanton dump(const unsigned long *cover, int mode)
23245297697Santon {
23345297697Santon 	unsigned long i;
2343bb8297cSanton 	int stride = 1;
23545297697Santon 
236a4101078Santon 	if (mode == KCOV_MODE_TRACE_CMP)
237a4101078Santon 		stride = 4;
238a4101078Santon 
23945297697Santon 	for (i = 0; i < cover[0]; i++)
240db9a2a8dSanton 		printf("%p\n", (void *)cover[i * stride + stride]);
24145297697Santon }
24245297697Santon 
24345297697Santon static int
24445297697Santon kcov_open(void)
24545297697Santon {
24645297697Santon 	int fd;
24745297697Santon 
24845297697Santon 	fd = open("/dev/kcov", O_RDWR);
24945297697Santon 	if (fd == -1)
25045297697Santon 		err(1, "open: /dev/kcov");
25145297697Santon 	return fd;
25245297697Santon }
25345297697Santon 
25445297697Santon static void
2550e2965f9Santon kcov_enable(int fd, int mode)
25645297697Santon {
2570e2965f9Santon 	if (ioctl(fd, KIOENABLE, &mode) == -1)
25845297697Santon 		err(1, "ioctl: KIOENABLE");
25945297697Santon }
26045297697Santon 
26145297697Santon static void
26245297697Santon kcov_disable(int fd)
26345297697Santon {
26445297697Santon 	if (ioctl(fd, KIODISABLE) == -1)
26545297697Santon 		err(1, "ioctl: KIODISABLE");
26645297697Santon }
26745297697Santon 
26845297697Santon /*
26945297697Santon  * Close before mmap.
27045297697Santon  */
27145297697Santon static int
272*e298ef25Santon test_close(struct context *ctx)
27345297697Santon {
27445297697Santon 	int fd;
27545297697Santon 
27645297697Santon 	fd = kcov_open();
27745297697Santon 	close(fd);
27845297697Santon 	return 0;
27945297697Santon }
28045297697Santon 
28145297697Santon /*
28245297697Santon  * Coverage of current thread.
28345297697Santon  */
28445297697Santon static int
285*e298ef25Santon test_coverage(struct context *ctx)
28645297697Santon {
2871c537871Santon 	kcov_enable(ctx->c_fd, ctx->c_mode);
28845297697Santon 	do_syscall();
2891c537871Santon 	kcov_disable(ctx->c_fd);
29045297697Santon 	return 0;
29145297697Santon }
29245297697Santon 
293aad1a0fbSanton static void *
294aad1a0fbSanton closer(void *arg)
295aad1a0fbSanton {
296*e298ef25Santon 	struct context *ctx = arg;
297aad1a0fbSanton 
2981c537871Santon 	close(ctx->c_fd);
299aad1a0fbSanton 	return NULL;
300aad1a0fbSanton }
301aad1a0fbSanton 
302aad1a0fbSanton /*
303aad1a0fbSanton  * Close kcov descriptor in another thread during tracing.
304aad1a0fbSanton  */
305aad1a0fbSanton static int
306*e298ef25Santon test_dying(struct context *ctx)
307aad1a0fbSanton {
308aad1a0fbSanton 	pthread_t th;
309aad1a0fbSanton 	int error;
310aad1a0fbSanton 
3111c537871Santon 	kcov_enable(ctx->c_fd, ctx->c_mode);
312aad1a0fbSanton 
3131c537871Santon 	if ((error = pthread_create(&th, NULL, closer, (void *)ctx)))
314aad1a0fbSanton 		errc(1, error, "pthread_create");
315aad1a0fbSanton 	if ((error = pthread_join(th, NULL)))
316aad1a0fbSanton 		errc(1, error, "pthread_join");
317aad1a0fbSanton 
318*e298ef25Santon 	error = 0;
3191c537871Santon 	if (close(ctx->c_fd) == -1) {
320aad1a0fbSanton 		if (errno != EBADF)
321aad1a0fbSanton 			err(1, "close");
322aad1a0fbSanton 	} else {
323aad1a0fbSanton 		warnx("expected kcov descriptor to be closed");
324*e298ef25Santon 		error = 1;
325aad1a0fbSanton 	}
326*e298ef25Santon 	ctx->c_fd = -1;
327aad1a0fbSanton 
328*e298ef25Santon 	return error;
329aad1a0fbSanton }
330aad1a0fbSanton 
33145297697Santon /*
33245297697Santon  * Coverage of thread after exec.
33345297697Santon  */
33445297697Santon static int
335*e298ef25Santon test_exec(struct context *ctx)
33645297697Santon {
33745297697Santon 	pid_t pid;
33845297697Santon 	int status;
33945297697Santon 
34045297697Santon 	pid = fork();
34145297697Santon 	if (pid == -1)
34245297697Santon 		err(1, "fork");
34345297697Santon 	if (pid == 0) {
3441c537871Santon 		kcov_enable(ctx->c_fd, ctx->c_mode);
34545297697Santon 		execlp(self, self, "-E", NULL);
34645297697Santon 		_exit(1);
34745297697Santon 	}
34845297697Santon 
34945297697Santon 	if (waitpid(pid, &status, 0) == -1)
35045297697Santon 		err(1, "waitpid");
35145297697Santon 	if (WIFSIGNALED(status)) {
35245297697Santon 		warnx("terminated by signal (%d)", WTERMSIG(status));
35345297697Santon 		return 1;
35445297697Santon 	} else if (WEXITSTATUS(status) != 0) {
35545297697Santon 		warnx("non-zero exit (%d)", WEXITSTATUS(status));
35645297697Santon 		return 1;
35745297697Santon 	}
35845297697Santon 
35945297697Santon 	/* Upon exit, the kcov descriptor must be reusable again. */
3601c537871Santon 	kcov_enable(ctx->c_fd, ctx->c_mode);
3611c537871Santon 	kcov_disable(ctx->c_fd);
36245297697Santon 
36345297697Santon 	return 0;
36445297697Santon }
36545297697Santon 
36645297697Santon /*
36745297697Santon  * Coverage of thread after fork.
36845297697Santon  */
36945297697Santon static int
370*e298ef25Santon test_fork(struct context *ctx)
37145297697Santon {
37245297697Santon 	pid_t pid;
37345297697Santon 	int status;
37445297697Santon 
37545297697Santon 	pid = fork();
37645297697Santon 	if (pid == -1)
37745297697Santon 		err(1, "fork");
37845297697Santon 	if (pid == 0) {
3791c537871Santon 		kcov_enable(ctx->c_fd, ctx->c_mode);
38045297697Santon 		do_syscall();
38145297697Santon 		_exit(0);
38245297697Santon 	}
38345297697Santon 
38445297697Santon 	if (waitpid(pid, &status, 0) == -1)
38545297697Santon 		err(1, "waitpid");
38645297697Santon 	if (WIFSIGNALED(status)) {
38745297697Santon 		warnx("terminated by signal (%d)", WTERMSIG(status));
38845297697Santon 		return 1;
38945297697Santon 	} else if (WEXITSTATUS(status) != 0) {
39045297697Santon 		warnx("non-zero exit (%d)", WEXITSTATUS(status));
39145297697Santon 		return 1;
39245297697Santon 	}
39345297697Santon 
39445297697Santon 	/* Upon exit, the kcov descriptor must be reusable again. */
3951c537871Santon 	kcov_enable(ctx->c_fd, ctx->c_mode);
3961c537871Santon 	kcov_disable(ctx->c_fd);
39745297697Santon 
39845297697Santon 	return 0;
39945297697Santon }
40045297697Santon 
40145297697Santon /*
402e3865369Santon  * Open /dev/kcov more than once.
40345297697Santon  */
40445297697Santon static int
405*e298ef25Santon test_open(struct context *ctx)
406e3865369Santon {
407e3865369Santon 	unsigned long *cover;
408e3865369Santon 	int fd;
4093bb8297cSanton 	int error = 0;
410e3865369Santon 
411e3865369Santon 	fd = kcov_open();
4121c537871Santon 	if (ioctl(fd, KIOSETBUFSIZE, &ctx->c_bufsize) == -1)
413e3865369Santon 		err(1, "ioctl: KIOSETBUFSIZE");
4141c537871Santon 	cover = mmap(NULL, ctx->c_bufsize * sizeof(unsigned long),
415e3865369Santon 	    PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
416e3865369Santon 	if (cover == MAP_FAILED)
417e3865369Santon 		err(1, "mmap");
418e3865369Santon 
4191c537871Santon 	kcov_enable(fd, ctx->c_mode);
420e3865369Santon 	do_syscall();
421e3865369Santon 	kcov_disable(fd);
422e3865369Santon 
4231c537871Santon 	error = check_coverage(cover, ctx->c_mode, ctx->c_bufsize, 1);
4243bb8297cSanton 
4251c537871Santon 	if (munmap(cover, ctx->c_bufsize * sizeof(unsigned long)))
426e3865369Santon 		err(1, "munmap");
427e3865369Santon 	close(fd);
4283bb8297cSanton 
4293bb8297cSanton 	return error;
430e3865369Santon }
431e3865369Santon 
432e3865369Santon /*
433*e298ef25Santon  * Remote taskq coverage. One reliable way to trigger a task on behalf of the
434*e298ef25Santon  * running process is to monitor a kqueue file descriptor using kqueue.
435*e298ef25Santon  */
436*e298ef25Santon static int
437*e298ef25Santon test_remote(struct context *ctx)
438*e298ef25Santon {
439*e298ef25Santon 	struct kio_remote_attach remote = {
440*e298ef25Santon 		.subsystem	= KCOV_REMOTE_COMMON,
441*e298ef25Santon 		.id		= 0,
442*e298ef25Santon 	};
443*e298ef25Santon 	struct kevent kev;
444*e298ef25Santon 	int kq1, kq2, pip[2];
445*e298ef25Santon 	int x = 0;
446*e298ef25Santon 
447*e298ef25Santon 	if (ioctl(ctx->c_fd, KIOREMOTEATTACH, &remote) == -1)
448*e298ef25Santon 		err(1, "ioctl: KIOREMOTEATTACH");
449*e298ef25Santon 	kcov_enable(ctx->c_fd, ctx->c_mode);
450*e298ef25Santon 
451*e298ef25Santon 	kq1 = kqueue();
452*e298ef25Santon 	if (kq1 == -1)
453*e298ef25Santon 		err(1, "kqueue");
454*e298ef25Santon 	kq2 = kqueue();
455*e298ef25Santon 	if (kq1 == -1)
456*e298ef25Santon 		err(1, "kqueue");
457*e298ef25Santon 	EV_SET(&kev, kq2, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL);
458*e298ef25Santon 	if (kevent(kq1, &kev, 1, NULL, 0, NULL) == -1)
459*e298ef25Santon 		err(1, "kqueue");
460*e298ef25Santon 
461*e298ef25Santon 	if (pipe(pip) == -1)
462*e298ef25Santon 		err(1, "pipe");
463*e298ef25Santon 
464*e298ef25Santon 	EV_SET(&kev, pip[0], EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL);
465*e298ef25Santon 	if (kevent(kq2, &kev, 1, NULL, 0, NULL) == -1)
466*e298ef25Santon 		err(1, "kqueue");
467*e298ef25Santon 	(void)write(pip[1], &x, sizeof(x));
468*e298ef25Santon 
469*e298ef25Santon 	if (kevent(kq1, NULL, 0, &kev, 1, NULL) == -1)
470*e298ef25Santon 		err(1, "kevent");
471*e298ef25Santon 
472*e298ef25Santon 	kcov_disable(ctx->c_fd);
473*e298ef25Santon 
474*e298ef25Santon 	return 0;
475*e298ef25Santon }
476*e298ef25Santon 
477*e298ef25Santon /*
478*e298ef25Santon  * Close with remote coverage enabled.
479*e298ef25Santon  */
480*e298ef25Santon static int
481*e298ef25Santon test_remote_close(struct context *ctx)
482*e298ef25Santon {
483*e298ef25Santon 	struct kio_remote_attach remote = {
484*e298ef25Santon 		.subsystem	= KCOV_REMOTE_COMMON,
485*e298ef25Santon 		.id		= 0,
486*e298ef25Santon 	};
487*e298ef25Santon 
488*e298ef25Santon 	if (ioctl(ctx->c_fd, KIOREMOTEATTACH, &remote) == -1)
489*e298ef25Santon 		err(1, "ioctl: KIOREMOTEATTACH");
490*e298ef25Santon 	kcov_enable(ctx->c_fd, ctx->c_mode);
491*e298ef25Santon 	if (close(ctx->c_fd) == -1)
492*e298ef25Santon 		err(1, "close");
493*e298ef25Santon 	ctx->c_fd = kcov_open();
494*e298ef25Santon 	return 0;
495*e298ef25Santon }
496*e298ef25Santon 
497*e298ef25Santon /*
498e3865369Santon  * State transitions.
499e3865369Santon  */
500e3865369Santon static int
501*e298ef25Santon test_state(struct context *ctx)
50245297697Santon {
5031c537871Santon 	if (ioctl(ctx->c_fd, KIOENABLE, &ctx->c_mode) == -1) {
5040e2965f9Santon 		warn("KIOSETBUFSIZE -> KIOENABLE");
50545297697Santon 		return 1;
50645297697Santon 	}
5071c537871Santon 	if (ioctl(ctx->c_fd, KIODISABLE) == -1) {
5080e2965f9Santon 		warn("KIOENABLE -> KIODISABLE");
50945297697Santon 		return 1;
51045297697Santon 	}
5111c537871Santon 	if (ioctl(ctx->c_fd, KIOSETBUFSIZE, 0) != -1) {
51245297697Santon 		warnx("KIOSETBUFSIZE -> KIOSETBUFSIZE");
51345297697Santon 		return 1;
51445297697Santon 	}
5151c537871Santon 	if (ioctl(ctx->c_fd, KIODISABLE) != -1) {
51645297697Santon 		warnx("KIOSETBUFSIZE -> KIODISABLE");
51745297697Santon 		return 1;
51845297697Santon 	}
51945297697Santon 
5201c537871Santon 	kcov_enable(ctx->c_fd, ctx->c_mode);
5211c537871Santon 	if (ioctl(ctx->c_fd, KIOENABLE, &ctx->c_mode) != -1) {
52245297697Santon 		warnx("KIOENABLE -> KIOENABLE");
52345297697Santon 		return 1;
52445297697Santon 	}
5251c537871Santon 	if (ioctl(ctx->c_fd, KIOSETBUFSIZE, 0) != -1) {
52645297697Santon 		warnx("KIOENABLE -> KIOSETBUFSIZE");
52745297697Santon 		return 1;
52845297697Santon 	}
5291c537871Santon 	kcov_disable(ctx->c_fd);
53045297697Santon 
53145297697Santon 	return 0;
53245297697Santon }
533