Module Name:    src
Committed By:   kamil
Date:           Sat Feb 23 03:10:06 UTC 2019

Modified Files:
        src/distrib/sets/lists/comp: mi
        src/distrib/sets/lists/man: mi
        src/distrib/sets/lists/tests: module.mi
        src/etc: MAKEDEV.tmpl
        src/share/man/man4: Makefile
        src/share/mk: bsd.sys.mk
        src/sys/arch/amd64/conf: GENERIC
        src/sys/conf: files majors ssp.mk
        src/sys/kern: files.kern
        src/sys/sys: Makefile
        src/tests/modules: Makefile
Added Files:
        src/share/man/man4: kcov.4
        src/sys/kern: subr_kcov.c
        src/sys/sys: kcov.h
        src/tests/modules: t_kcov.c

Log Message:
Add KCOV - kernel code coverage tracing device

The KCOV driver implements collection of code coverage inside the kernel.
It can be enabled on a per process basis from userland, allowing the kernel
program counter to be collected during syscalls triggered by the same
process.

The device is oriented towards kernel fuzzers, in particular syzkaller.

Currently the only supported coverage type is -fsanitize-coverage=trace-pc.

The KCOV driver was initially developed in Linux. A driver based on the
same concept was then implemented in FreeBSD and OpenBSD.

Documentation is borrowed from OpenBSD and ATF tests from FreeBSD.

This patch has been prepared by Siddharth Muralee, improved by <maxv>
and polished by myself before importing into the mainline tree.

All ATF tests pass.


To generate a diff of this commit:
cvs rdiff -u -r1.2258 -r1.2259 src/distrib/sets/lists/comp/mi
cvs rdiff -u -r1.1637 -r1.1638 src/distrib/sets/lists/man/mi
cvs rdiff -u -r1.16 -r1.17 src/distrib/sets/lists/tests/module.mi
cvs rdiff -u -r1.197 -r1.198 src/etc/MAKEDEV.tmpl
cvs rdiff -u -r1.677 -r1.678 src/share/man/man4/Makefile
cvs rdiff -u -r0 -r1.1 src/share/man/man4/kcov.4
cvs rdiff -u -r1.290 -r1.291 src/share/mk/bsd.sys.mk
cvs rdiff -u -r1.516 -r1.517 src/sys/arch/amd64/conf/GENERIC
cvs rdiff -u -r1.1229 -r1.1230 src/sys/conf/files
cvs rdiff -u -r1.80 -r1.81 src/sys/conf/majors
cvs rdiff -u -r1.3 -r1.4 src/sys/conf/ssp.mk
cvs rdiff -u -r1.32 -r1.33 src/sys/kern/files.kern
cvs rdiff -u -r0 -r1.1 src/sys/kern/subr_kcov.c
cvs rdiff -u -r1.168 -r1.169 src/sys/sys/Makefile
cvs rdiff -u -r0 -r1.1 src/sys/sys/kcov.h
cvs rdiff -u -r1.14 -r1.15 src/tests/modules/Makefile
cvs rdiff -u -r0 -r1.1 src/tests/modules/t_kcov.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/distrib/sets/lists/comp/mi
diff -u src/distrib/sets/lists/comp/mi:1.2258 src/distrib/sets/lists/comp/mi:1.2259
--- src/distrib/sets/lists/comp/mi:1.2258	Sun Feb 10 04:03:03 2019
+++ src/distrib/sets/lists/comp/mi	Sat Feb 23 03:10:05 2019
@@ -1,4 +1,4 @@
-#	$NetBSD: mi,v 1.2258 2019/02/10 04:03:03 mrg Exp $
+#	$NetBSD: mi,v 1.2259 2019/02/23 03:10:05 kamil Exp $
 #
 # Note: don't delete entries from here - mark them as "obsolete" instead.
 ./etc/mtree/set.comp				comp-sys-root
@@ -3017,6 +3017,7 @@
 ./usr/include/sys/ipc.h				comp-c-include
 ./usr/include/sys/joystick.h			comp-c-include
 ./usr/include/sys/kcore.h			comp-c-include
+./usr/include/sys/kcov.h			comp-c-include
 ./usr/include/sys/kcpuset.h			comp-c-include
 ./usr/include/sys/kernel.h			comp-obsolete		obsolete
 ./usr/include/sys/keylock.h			comp-obsolete		obsolete

Index: src/distrib/sets/lists/man/mi
diff -u src/distrib/sets/lists/man/mi:1.1637 src/distrib/sets/lists/man/mi:1.1638
--- src/distrib/sets/lists/man/mi:1.1637	Wed Feb  6 11:55:05 2019
+++ src/distrib/sets/lists/man/mi	Sat Feb 23 03:10:05 2019
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.1637 2019/02/06 11:55:05 rin Exp $
+# $NetBSD: mi,v 1.1638 2019/02/23 03:10:05 kamil Exp $
 #
 # Note: don't delete entries from here - mark them as "obsolete" instead.
 #
@@ -1373,6 +1373,7 @@
 ./usr/share/man/cat4/jmide.0			man-sys-catman		.cat
 ./usr/share/man/cat4/joy.0			man-sys-catman		.cat
 ./usr/share/man/cat4/kame_ipsec.0		man-obsolete		obsolete
+./usr/share/man/cat4/kcov.0			man-sys-catman		.cat
 ./usr/share/man/cat4/kloader.0			man-sys-catman		.cat
 ./usr/share/man/cat4/kse.0			man-sys-catman		.cat
 ./usr/share/man/cat4/ksyms.0			man-sys-catman		.cat
@@ -4496,6 +4497,7 @@
 ./usr/share/man/html4/jmide.html		man-sys-htmlman		html
 ./usr/share/man/html4/joy.html			man-sys-htmlman		html
 ./usr/share/man/html4/kame_ipsec.html		man-obsolete		obsolete
+./usr/share/man/html4/kcov.html		man-sys-htmlman		html
 ./usr/share/man/html4/kloader.html		man-sys-htmlman		html
 ./usr/share/man/html4/kse.html			man-sys-htmlman		html
 ./usr/share/man/html4/ksyms.html		man-sys-htmlman		html
@@ -7459,6 +7461,7 @@
 ./usr/share/man/man4/jmide.4			man-sys-man		.man
 ./usr/share/man/man4/joy.4			man-sys-man		.man
 ./usr/share/man/man4/kame_ipsec.4		man-obsolete		obsolete
+./usr/share/man/man4/kcov.4			man-sys-man		.man
 ./usr/share/man/man4/kloader.4			man-sys-man		.man
 ./usr/share/man/man4/kse.4			man-sys-man		.man
 ./usr/share/man/man4/ksyms.4			man-sys-man		.man

Index: src/distrib/sets/lists/tests/module.mi
diff -u src/distrib/sets/lists/tests/module.mi:1.16 src/distrib/sets/lists/tests/module.mi:1.17
--- src/distrib/sets/lists/tests/module.mi:1.16	Sun Jan 27 16:32:52 2019
+++ src/distrib/sets/lists/tests/module.mi	Sat Feb 23 03:10:05 2019
@@ -1,4 +1,4 @@
-# $NetBSD: module.mi,v 1.16 2019/01/27 16:32:52 christos Exp $
+# $NetBSD: module.mi,v 1.17 2019/02/23 03:10:05 kamil Exp $
 #
 # These are only made for ports doing modules.
 #
@@ -17,6 +17,7 @@
 ./usr/tests/modules/k_uvm/k_uvm.kmod		tests-sys-tests		atf,rump
 ./usr/tests/modules/t_abi_uvm			tests-sys-tests		atf,rump
 ./usr/tests/modules/t_builtin			tests-sys-tests		atf,rump
+./usr/tests/modules/t_kcov			tests-sys-tests		atf
 ./usr/tests/modules/t_klua_pr_52864 		tests-sys-tests		atf,rump
 ./usr/tests/modules/t_modctl			tests-sys-tests		atf,rump
 ./usr/tests/modules/t_modload			tests-sys-tests		atf,rump

Index: src/etc/MAKEDEV.tmpl
diff -u src/etc/MAKEDEV.tmpl:1.197 src/etc/MAKEDEV.tmpl:1.198
--- src/etc/MAKEDEV.tmpl:1.197	Sun Jan 27 08:53:28 2019
+++ src/etc/MAKEDEV.tmpl	Sat Feb 23 03:10:06 2019
@@ -1,5 +1,5 @@
 #!/bin/sh -
-#	$NetBSD: MAKEDEV.tmpl,v 1.197 2019/01/27 08:53:28 maxv Exp $
+#	$NetBSD: MAKEDEV.tmpl,v 1.198 2019/02/23 03:10:06 kamil Exp $
 #
 # Copyright (c) 2003,2007,2008 The NetBSD Foundation, Inc.
 # All rights reserved.
@@ -2208,6 +2208,10 @@ autofs)
 	mkdev autofs c %autofs_chr% 0 600
 	;;
 
+kcov)
+        mkdev kcov c %kcov_chr% 0
+        ;;
+
 midevend)
 %MI_DEVICES_END%
 local)

Index: src/share/man/man4/Makefile
diff -u src/share/man/man4/Makefile:1.677 src/share/man/man4/Makefile:1.678
--- src/share/man/man4/Makefile:1.677	Wed Feb  6 11:55:05 2019
+++ src/share/man/man4/Makefile	Sat Feb 23 03:10:06 2019
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile,v 1.677 2019/02/06 11:55:05 rin Exp $
+#	$NetBSD: Makefile,v 1.678 2019/02/23 03:10:06 kamil Exp $
 #	@(#)Makefile	8.1 (Berkeley) 6/18/93
 
 MAN=	aac.4 ac97.4 acardide.4 aceride.4 acphy.4 \
@@ -36,7 +36,7 @@ MAN=	aac.4 ac97.4 acardide.4 aceride.4 a
 	irmce.4 isp.4 ismt.4 isv.4 itesio.4 iteide.4 iwi.4 iwm.4 iwn.4 ixg.4 \
 	ixpide.4 ixv.4 \
 	jme.4 jmide.4 joy.4 \
-	kloader.4 kse.4 ksyms.4 kttcp.4 \
+	kcov.4 kloader.4 kse.4 ksyms.4 kttcp.4 \
 	l2tp.4 lc.4 ld.4 lii.4 lo.4 lua.4 lxtphy.4 \
 	mainbus.4 makphy.4 malo.4 mbe.4 mca.4 mcclock.4 md.4 mfb.4 \
 	mfi.4 mfii.4 mhzc.4 \

Index: src/share/mk/bsd.sys.mk
diff -u src/share/mk/bsd.sys.mk:1.290 src/share/mk/bsd.sys.mk:1.291
--- src/share/mk/bsd.sys.mk:1.290	Mon Jan 21 21:11:54 2019
+++ src/share/mk/bsd.sys.mk	Sat Feb 23 03:10:06 2019
@@ -1,4 +1,4 @@
-#	$NetBSD: bsd.sys.mk,v 1.290 2019/01/21 21:11:54 christos Exp $
+#	$NetBSD: bsd.sys.mk,v 1.291 2019/02/23 03:10:06 kamil Exp $
 #
 # Build definitions used for NetBSD source tree builds.
 
@@ -240,6 +240,14 @@ KLEAKFLAGS.${f}=	# empty
 CFLAGS+=	${KLEAKFLAGS.${.IMPSRC:T}:U${KLEAKFLAGS}}
 .endif
 
+.if ${KCOV:U0} > 0
+KCOVFLAGS=	-fsanitize-coverage=trace-pc
+.for f in subr_kcov.c subr_lwp_specificdata.c subr_specificdata.c
+KCOVFLAGS.${f}=		# empty
+.endfor
+CFLAGS+=	${KCOVFLAGS.${.IMPSRC:T}:U${KCOVFLAGS}}
+.endif
+
 .if !defined(NOPIE) && (!defined(LDSTATIC) || ${LDSTATIC} != "-static")
 # Position Independent Executable flags
 PIE_CFLAGS?=        -fPIE

Index: src/sys/arch/amd64/conf/GENERIC
diff -u src/sys/arch/amd64/conf/GENERIC:1.516 src/sys/arch/amd64/conf/GENERIC:1.517
--- src/sys/arch/amd64/conf/GENERIC:1.516	Fri Feb 15 08:54:01 2019
+++ src/sys/arch/amd64/conf/GENERIC	Sat Feb 23 03:10:06 2019
@@ -1,4 +1,4 @@
-# $NetBSD: GENERIC,v 1.516 2019/02/15 08:54:01 nonaka Exp $
+# $NetBSD: GENERIC,v 1.517 2019/02/23 03:10:06 kamil Exp $
 #
 # GENERIC machine description file
 #
@@ -22,7 +22,7 @@ include 	"arch/amd64/conf/std.amd64"
 
 options 	INCLUDE_CONFIG_FILE	# embed config file in kernel binary
 
-#ident		"GENERIC-$Revision: 1.516 $"
+#ident		"GENERIC-$Revision: 1.517 $"
 
 maxusers	64		# estimated number of users
 
@@ -130,6 +130,10 @@ options 	KDTRACE_HOOKS	# kernel DTrace h
 #makeoptions 	KLEAK=1
 #options 	KLEAK
 
+# Kernel Code Coverage Driver.
+#makeoptions	KCOV=1
+#options	KCOV
+
 # Compatibility options
 # x86_64 never shipped with a.out binaries; the two options below are
 # only relevant to 32-bit i386 binaries

Index: src/sys/conf/files
diff -u src/sys/conf/files:1.1229 src/sys/conf/files:1.1230
--- src/sys/conf/files:1.1229	Tue Feb 12 07:16:56 2019
+++ src/sys/conf/files	Sat Feb 23 03:10:06 2019
@@ -1,4 +1,4 @@
-#	$NetBSD: files,v 1.1229 2019/02/12 07:16:56 mrg Exp $
+#	$NetBSD: files,v 1.1230 2019/02/23 03:10:06 kamil Exp $
 #	@(#)files.newconf	7.5 (Berkeley) 5/10/93
 
 version 	20171118
@@ -31,6 +31,7 @@ defflag opt_diagnostic.h	_DIAGNOSTIC
 defflag				GPROF
 defflag				KASAN
 defflag				KLEAK
+defflag				KCOV
 
 defparam opt_copy_symtab.h	makeoptions_COPY_SYMTAB
 

Index: src/sys/conf/majors
diff -u src/sys/conf/majors:1.80 src/sys/conf/majors:1.81
--- src/sys/conf/majors:1.80	Wed Nov  7 07:43:07 2018
+++ src/sys/conf/majors	Sat Feb 23 03:10:06 2019
@@ -1,4 +1,4 @@
-# $NetBSD: majors,v 1.80 2018/11/07 07:43:07 maxv Exp $
+# $NetBSD: majors,v 1.81 2019/02/23 03:10:06 kamil Exp $
 #
 # Device majors for Machine-Independent drivers.
 #
@@ -79,3 +79,4 @@ device-major qemufwcfg char 342		   qemu
 device-major autofs    char 343		   autofs
 device-major gpiopps   char 344            gpiopps
 device-major nvmm      char 345            nvmm
+device-major kcov      char 346            kcov

Index: src/sys/conf/ssp.mk
diff -u src/sys/conf/ssp.mk:1.3 src/sys/conf/ssp.mk:1.4
--- src/sys/conf/ssp.mk:1.3	Sun Dec  2 21:00:13 2018
+++ src/sys/conf/ssp.mk	Sat Feb 23 03:10:06 2019
@@ -1,4 +1,4 @@
-# $NetBSD: ssp.mk,v 1.3 2018/12/02 21:00:13 maxv Exp $
+# $NetBSD: ssp.mk,v 1.4 2019/02/23 03:10:06 kamil Exp $
 
 .if ${USE_SSP:Uno} == "yes"
 COPTS.kern_ssp.c+=	-fno-stack-protector -D__SSP__
@@ -11,6 +11,7 @@ COPTS.cpu.c+=		-fno-stack-protector
 .endif
 
 COPTS.subr_kleak.c+=	-fno-stack-protector
+COPTS.subr_kcov.c+=		-fno-stack-protector
 
 # The following files use alloca(3) or variable array allocations.
 # Their full name is noted as documentation.

Index: src/sys/kern/files.kern
diff -u src/sys/kern/files.kern:1.32 src/sys/kern/files.kern:1.33
--- src/sys/kern/files.kern:1.32	Wed Feb 13 18:04:35 2019
+++ src/sys/kern/files.kern	Sat Feb 23 03:10:06 2019
@@ -1,4 +1,4 @@
-#	$NetBSD: files.kern,v 1.32 2019/02/13 18:04:35 kamil Exp $
+#	$NetBSD: files.kern,v 1.33 2019/02/23 03:10:06 kamil Exp $
 
 #
 # kernel sources
@@ -121,6 +121,7 @@ file	kern/subr_iostat.c		kern
 file	kern/subr_ipi.c			kern
 file	kern/subr_kcpuset.c		kern
 file	kern/subr_kleak.c		kleak
+file	kern/subr_kcov.c		kcov
 defflag	opt_kmem.h			KMEM_GUARD
 					KMEM_SIZE
 defparam opt_kmem.h			KMEM_GUARD_DEPTH

Index: src/sys/sys/Makefile
diff -u src/sys/sys/Makefile:1.168 src/sys/sys/Makefile:1.169
--- src/sys/sys/Makefile:1.168	Tue Aug 21 06:49:21 2018
+++ src/sys/sys/Makefile	Sat Feb 23 03:10:06 2019
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile,v 1.168 2018/08/21 06:49:21 kre Exp $
+#	$NetBSD: Makefile,v 1.169 2019/02/23 03:10:06 kamil Exp $
 
 .include <bsd.own.mk>
 
@@ -25,7 +25,7 @@ INCS=	acct.h agpio.h aio.h ansi.h aout_m
 	idtype.h ieee754.h intr.h intrio.h inttypes.h ioccom.h ioctl.h \
 	ioctl_compat.h iostat.h ipc.h \
 	joystick.h \
-	kcore.h kcpuset.h kgdb.h kmem.h ksem.h ksyms.h ktrace.h \
+	kcore.h kcov.h kcpuset.h kgdb.h kmem.h ksem.h ksyms.h ktrace.h \
 	localcount.h localedef.h lock.h lockf.h lua.h lwp.h lwpctl.h \
 	malloc.h mallocvar.h mbuf.h md4.h md5.h midiio.h \
 	mman.h module.h mount.h mqueue.h msg.h msgbuf.h mtio.h mutex.h \

Index: src/tests/modules/Makefile
diff -u src/tests/modules/Makefile:1.14 src/tests/modules/Makefile:1.15
--- src/tests/modules/Makefile:1.14	Fri Jan 25 18:33:59 2019
+++ src/tests/modules/Makefile	Sat Feb 23 03:10:06 2019
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.14 2019/01/25 18:33:59 christos Exp $
+# $NetBSD: Makefile,v 1.15 2019/02/23 03:10:06 kamil Exp $
 
 .include <bsd.own.mk>
 
@@ -12,6 +12,7 @@ CPPFLAGS+=	-D_KERNTYPES
 # Atffile into it.
 TESTS_C=	t_modctl
 TESTS_C+=	t_builtin
+TESTS_C+=	t_kcov
 LDADD=		-lprop
 LDADD+=		-lrumpfs_kernfs -lrumpvfs -lrump -lrumpuser -lrump -lpthread
 

Added files:

Index: src/share/man/man4/kcov.4
diff -u /dev/null src/share/man/man4/kcov.4:1.1
--- /dev/null	Sat Feb 23 03:10:07 2019
+++ src/share/man/man4/kcov.4	Sat Feb 23 03:10:06 2019
@@ -0,0 +1,133 @@
+.\"	$NetBSD: kcov.4,v 1.1 2019/02/23 03:10:06 kamil Exp $
+.\"
+.\" Copyright (c) 2018 Anton Lindqvist <an...@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd November 16, 2018
+.Dt KCOV 4
+.Os
+.Sh NAME
+.Nm kcov
+.Nd kernel code coverage tracing
+.Sh SYNOPSIS
+.Cd options KCOV
+.Pp
+.In sys/kcov.h
+.Sh DESCRIPTION
+The
+.Nm
+driver implements collection of code coverage inside the kernel.
+It can be enabled on a per process basis from userland,
+allowing the kernel program counter to be collected during syscalls triggered by
+the same process.
+The collected coverage can be accessed by mapping the device
+using
+.Xr mmap 2 .
+.Pp
+By default,
+.Nm
+is not enabled but requires the compile-time configuration
+.Cd makeoptions KCOV
+.Cd options KCOV
+to be present,
+see
+.Xr options 4 .
+.Pp
+The following
+.Xr ioctl 2
+calls are provided:
+.Bl -tag -width 4n
+.It Dv KCOV_IOC_SETBUFSIZE Fa uint64_t *nentries
+Allocate a coverage buffer with a capacity of
+.Fa nentries .
+The buffer can be accessed using
+.Xr mmap 2
+whereas the returned pointer must be interpreted as an array of
+.Vt kcov_int_t
+entries. Note that kcov_int_t is volatile.
+The first entry contains the number of entries in the array,
+excluding the first entry.
+.It Dv KCOV_IOC_ENABLE Fa void
+Enable code coverage tracing for the current thread.
+.It Dv KCOV_IOC_DISABLE Fa void
+Disable code coverage tracing for the current thread.
+.El
+.Sh FILES
+.Bl -tag -width /dev/kcov -compact
+.It Pa /dev/kcov
+Default device node.
+.El
+.Sh EXAMPLES
+In the following example,
+the
+.Xr read 2
+syscall is traced and the coverage displayed, which in turn can be passed to
+.Xr addr2line 1
+in order to translate the kernel program counter into the file name and line
+number it corresponds to.
+.Bd -literal
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <sys/ioccom.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include <sys/kcov.h>
+
+int
+main(void)
+{
+	kcov_int_t *cover, i, n;
+	kcov_int_t size = 1024 * 100;
+	int fd;
+
+	fd = open("/dev/kcov", O_RDWR);
+	if (fd == -1)
+		err(1, "open");
+	if (ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) == -1)
+		err(1, "ioctl: KCOV_IOC_SETBUFSIZE");
+	cover = mmap(NULL, size * KCOV_ENTRY_SIZE,
+	    PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+	if (cover == MAP_FAILED)
+		err(1, "mmap");
+	if (ioctl(fd, KCOV_IOC_ENABLE) == -1)
+		err(1, "ioctl: KCOV_IOC_ENABLE");
+	__atomic_store_n(&cover[0], 0, __ATOMIC_RELAXED);
+	read(-1, NULL, 0); /* syscall paths to be traced */
+	n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED);
+	if (ioctl(fd, KCOV_IOC_DISABLE) == -1)
+		err(1, "ioctl: KCOV_IOC_DISABLE");
+	for (i = 0; i < cover[0]; i++)
+		printf("%p\en", (void *)cover[i + 1]);
+	if (munmap(cover, size * KCOV_ENTRY_SIZE) == -1)
+		err(1, "munmap");
+	close(fd);
+
+	return 0;
+}
+.Ed
+.Sh SEE ALSO
+.Xr options 4
+.Sh HISTORY
+The
+.Nm
+driver was initially developed in Linux. A driver based on the same concept
+was then implemented in
+.Nx 9 .
+.Sh AUTHORS
+.An Siddharth Muralee Aq Mt siddharth.mura...@gmail.com

Index: src/sys/kern/subr_kcov.c
diff -u /dev/null src/sys/kern/subr_kcov.c:1.1
--- /dev/null	Sat Feb 23 03:10:07 2019
+++ src/sys/kern/subr_kcov.c	Sat Feb 23 03:10:06 2019
@@ -0,0 +1,340 @@
+/*	$NetBSD: subr_kcov.c,v 1.1 2019/02/23 03:10:06 kamil Exp $	*/
+
+/*
+ * Copyright (c) 2019 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Siddharth Muralee.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/module.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+
+#include <sys/atomic.h>
+#include <sys/conf.h>
+#include <sys/condvar.h>
+#include <sys/kmem.h>
+#include <sys/mutex.h>
+#include <sys/queue.h>
+
+#include <uvm/uvm_extern.h>
+#include <sys/kcov.h>
+
+#define KCOV_BUF_MAX_ENTRIES	(256 << 10)
+
+/*
+ * The KCOV descriptors are allocated during open(), and are associated with
+ * the calling proc. They are freed lazily when their refcount reaches zero,
+ * only when the process exits; this guarantees that kd->buf is not mmapped
+ * in a currently running LWP. A KCOV descriptor is active on only one LWP
+ * at the same time within the proc.
+ *
+ * In the refcount, one ref is for the proc, and one ref is for the LWP where
+ * the descriptor is active. In each case, the descriptor is pointed to in
+ * the proc's and LWP's specificdata.
+ */
+
+typedef struct kcov_desc {
+	kmutex_t lock;
+	int refcnt;
+	kcov_int_t *buf;
+	size_t bufnent;
+	size_t bufsize;
+	TAILQ_ENTRY(kcov_desc) entry;
+} kcov_t;
+
+static specificdata_key_t kcov_proc_key;
+static specificdata_key_t kcov_lwp_key;
+
+static void
+kcov_lock(kcov_t *kd)
+{
+
+	mutex_enter(&kd->lock);
+	KASSERT(kd->refcnt > 0);
+}
+
+static void
+kcov_unlock(kcov_t *kd)
+{
+
+	mutex_exit(&kd->lock);
+}
+
+static void
+kcov_lwp_take(kcov_t *kd)
+{
+
+	kd->refcnt++;
+	KASSERT(kd->refcnt == 2);
+	lwp_setspecific(kcov_lwp_key, kd);
+}
+
+static void
+kcov_lwp_release(kcov_t *kd)
+{
+
+	KASSERT(kd->refcnt == 2);
+	kd->refcnt--;
+	lwp_setspecific(kcov_lwp_key, NULL);
+}
+
+static inline bool
+kcov_is_owned(kcov_t *kd)
+{
+
+	return (kd->refcnt > 1);
+}
+
+static void
+kcov_free(void *arg)
+{
+	kcov_t *kd = (kcov_t *)arg;
+	bool dofree;
+
+	if (kd == NULL) {
+		return;
+	}
+
+	kcov_lock(kd);
+	kd->refcnt--;
+	kcov_unlock(kd);
+	dofree = (kd->refcnt == 0);
+
+	if (!dofree) {
+		return;
+	}
+	if (kd->buf != NULL) {
+		uvm_km_free(kernel_map, (vaddr_t)kd->buf, kd->bufsize,
+		    UVM_KMF_WIRED);
+	}
+	mutex_destroy(&kd->lock);
+	kmem_free(kd, sizeof(*kd));
+}
+
+static int
+kcov_allocbuf(kcov_t *kd, uint64_t nent)
+{
+	size_t size;
+
+	if (nent < 2 || nent > KCOV_BUF_MAX_ENTRIES)
+		return EINVAL;
+	if (kd->buf != NULL)
+		return EEXIST;
+
+	size = roundup(nent * KCOV_ENTRY_SIZE, PAGE_SIZE);
+	kd->buf = (kcov_int_t *)uvm_km_alloc(kernel_map, size, 0,
+	    UVM_KMF_WIRED|UVM_KMF_ZERO);
+	if (kd->buf == NULL)
+		return ENOMEM;
+
+	kd->bufnent = nent - 1;
+	kd->bufsize = size;
+
+	return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int
+kcov_open(dev_t dev, int flag, int mode, struct lwp *l)
+{
+	struct proc *p = l->l_proc;
+	kcov_t *kd;
+
+	kd = proc_getspecific(p, kcov_proc_key);
+	if (kd != NULL)
+		return EBUSY;
+
+	kd = kmem_zalloc(sizeof(*kd), KM_SLEEP);
+	mutex_init(&kd->lock, MUTEX_DEFAULT, IPL_NONE);
+	kd->refcnt = 1;
+	proc_setspecific(p, kcov_proc_key, kd);
+
+	return 0;
+}
+
+static int
+kcov_close(dev_t dev, int flag, int mode, struct lwp *l)
+{
+
+   	return 0;
+}
+
+static int
+kcov_ioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
+{
+	struct proc *p = l->l_proc;
+	int error = 0;
+	kcov_t *kd;
+
+	kd = proc_getspecific(p, kcov_proc_key);
+	if (kd == NULL)
+		return ENXIO;
+	kcov_lock(kd);
+
+	switch (cmd) {
+	case KCOV_IOC_SETBUFSIZE:
+		if (kcov_is_owned(kd)) {
+			error = EBUSY;
+			break;
+		}
+		error = kcov_allocbuf(kd, *((uint64_t *)addr));
+		break;
+	case KCOV_IOC_ENABLE:
+		if (kcov_is_owned(kd)) {
+			error = EBUSY;
+			break;
+		}
+		if (kd->buf == NULL) {
+			error = ENOBUFS;
+			break;
+		}
+		KASSERT(l == curlwp);
+		kcov_lwp_take(kd);
+		break;
+	case KCOV_IOC_DISABLE:
+		if (lwp_getspecific(kcov_lwp_key) == NULL) {
+			error = ENOENT;
+			break;
+		}
+		KASSERT(l == curlwp);
+		kcov_lwp_release(kd);
+		break;
+	default:
+		error = EINVAL;
+	}
+
+	kcov_unlock(kd);
+	return error;
+}
+
+static paddr_t
+kcov_mmap(dev_t dev, off_t offset, int prot)
+{
+	kcov_t *kd;
+	paddr_t pa;
+	vaddr_t va;
+
+	kd = proc_getspecific(curproc, kcov_proc_key);
+	KASSERT(kd != NULL);
+
+	if ((offset < 0) || (offset >= kd->bufnent * KCOV_ENTRY_SIZE)) {
+		return (paddr_t)-1;
+	}
+	if (offset & PAGE_MASK) {
+		return (paddr_t)-1;
+	}
+	va = (vaddr_t)kd->buf + offset;
+	if (!pmap_extract(pmap_kernel(), va, &pa)) {
+		return (paddr_t)-1;
+	}
+
+	return atop(pa);
+}
+
+static inline bool
+in_interrupt(void)
+{
+	return curcpu()->ci_idepth >= 0;
+}
+
+void __sanitizer_cov_trace_pc(void);
+
+void
+__sanitizer_cov_trace_pc(void)
+{
+	extern int cold;
+	uint64_t idx;
+	kcov_t *kd;
+
+	if (__predict_false(cold)) {
+		/* Do not trace during boot. */
+		return;
+	}
+
+	if (in_interrupt()) {
+		/* Do not trace in interrupts. */
+		return;
+	}
+
+	kd = lwp_getspecific(kcov_lwp_key);
+	if (__predict_true(kd == NULL)) {
+		/* Not traced. */
+		return;
+	}
+
+	idx = kd->buf[0];
+	if (idx < kd->bufnent) {
+		kd->buf[idx+1] = (kcov_int_t)__builtin_return_address(0);
+		kd->buf[0]++;
+	}
+}
+
+/* -------------------------------------------------------------------------- */
+
+const struct cdevsw kcov_cdevsw = {
+	.d_open = kcov_open,
+	.d_close = kcov_close,
+	.d_read = noread,
+	.d_write = nowrite,
+	.d_ioctl = kcov_ioctl,
+	.d_stop = nostop,
+	.d_tty = notty,
+	.d_poll = nopoll,
+	.d_mmap = kcov_mmap,
+	.d_kqfilter = nokqfilter,
+	.d_discard = nodiscard,
+	.d_flag = D_OTHER | D_MPSAFE
+};
+
+MODULE(MODULE_CLASS_ANY, kcov, NULL);
+
+static void
+kcov_init(void)
+{
+
+	proc_specific_key_create(&kcov_proc_key, kcov_free);
+	lwp_specific_key_create(&kcov_lwp_key, kcov_free);
+}
+
+static int
+kcov_modcmd(modcmd_t cmd, void *arg)
+{
+
+   	switch (cmd) {
+	case MODULE_CMD_INIT:
+		kcov_init();
+		return 0;
+	case MODULE_CMD_FINI:
+		return EINVAL;
+	default:
+		return ENOTTY;
+	}
+}

Index: src/sys/sys/kcov.h
diff -u /dev/null src/sys/sys/kcov.h:1.1
--- /dev/null	Sat Feb 23 03:10:07 2019
+++ src/sys/sys/kcov.h	Sat Feb 23 03:10:06 2019
@@ -0,0 +1,42 @@
+/*      $NetBSD: kcov.h,v 1.1 2019/02/23 03:10:06 kamil Exp $        */
+
+/*
+ * Copyright (c) 2019 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Siddharth Muralee.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SYS_KCOV_H_
+#define _SYS_KCOV_H_
+
+#define KCOV_IOC_SETBUFSIZE	_IOW('K', 1, uint64_t)
+#define KCOV_IOC_ENABLE		_IO('K', 2)
+#define KCOV_IOC_DISABLE	_IO('K', 3)
+
+typedef volatile uint64_t kcov_int_t;
+#define KCOV_ENTRY_SIZE sizeof(kcov_int_t)
+
+#endif /* !_SYS_KCOV_H_ */

Index: src/tests/modules/t_kcov.c
diff -u /dev/null src/tests/modules/t_kcov.c:1.1
--- /dev/null	Sat Feb 23 03:10:07 2019
+++ src/tests/modules/t_kcov.c	Sat Feb 23 03:10:06 2019
@@ -0,0 +1,315 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2018, 2019 Andrew Turner
+ *
+ * This software was developed by SRI International and the University of
+ * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
+ * ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/kcov.h>
+#include <sys/mman.h>
+
+#include <fcntl.h>
+#include <pthread.h>
+#include <semaphore.h>
+
+#include <atf-c.h>
+
+#define PAGE_SIZE sysconf(_SC_PAGESIZE)
+
+static int
+open_kcov(void)
+{
+	int fd;
+
+	fd = open("/dev/kcov", O_RDWR);
+	if (fd == -1)
+		atf_tc_skip("Failed to open /dev/kcov");
+
+	return fd;
+}
+
+ATF_TC_WITHOUT_HEAD(kcov_bufsize);
+ATF_TC_BODY(kcov_bufsize, tc)
+{
+	int fd;
+	kcov_int_t size;
+	fd = open_kcov();
+
+	size = 0;
+	ATF_CHECK(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) == -1);
+	size = 2;
+	ATF_CHECK(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) == 0);
+
+	close(fd);
+}
+
+ATF_TC_WITHOUT_HEAD(kcov_mmap);
+ATF_TC_BODY(kcov_mmap, tc)
+{
+	void *data;
+	int fd;
+	kcov_int_t size = 2 * PAGE_SIZE / KCOV_ENTRY_SIZE;
+
+	fd = open_kcov();
+
+	ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
+	    fd, 0) == MAP_FAILED);
+
+	ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) == 0);
+
+	ATF_REQUIRE((data = mmap(NULL, 2 * PAGE_SIZE, PROT_READ | PROT_WRITE,
+	    MAP_SHARED, fd, 0)) != MAP_FAILED);
+
+	munmap(data, 2 * PAGE_SIZE);
+
+	close(fd);
+}
+
+/* This shouldn't panic */
+ATF_TC_WITHOUT_HEAD(kcov_mmap_no_munmap);
+ATF_TC_BODY(kcov_mmap_no_munmap, tc)
+{
+	int fd;
+	kcov_int_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
+
+	fd = open_kcov();
+
+	ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
+
+	ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
+	    fd, 0) != MAP_FAILED);
+
+	close(fd);
+}
+
+ATF_TC_WITHOUT_HEAD(kcov_mmap_no_munmap_no_close);
+ATF_TC_BODY(kcov_mmap_no_munmap_no_close, tc)
+{
+	int fd;
+	kcov_int_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
+
+	fd = open_kcov();
+
+	ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
+
+	ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
+	    fd, 0) != MAP_FAILED);
+}
+
+static sem_t sem1, sem2;
+
+static void *
+kcov_mmap_enable_thread(void *data)
+{
+	int fd;
+	kcov_int_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
+
+	fd = open_kcov();
+	*(int *)data = fd;
+
+	ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
+	ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
+	    fd, 0) != MAP_FAILED);
+	ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE) == 0);
+
+	sem_post(&sem1);
+	sem_wait(&sem2);
+
+	return NULL;
+}
+
+ATF_TC_WITHOUT_HEAD(kcov_mmap_enable_thread_close);
+ATF_TC_BODY(kcov_mmap_enable_thread_close, tc)
+{
+	pthread_t thread;
+	int fd;
+
+	sem_init(&sem1, 0, 0);
+	sem_init(&sem2, 0, 0);
+	pthread_create(&thread, NULL,
+	    kcov_mmap_enable_thread, &fd);
+	sem_wait(&sem1);
+	close(fd);
+	sem_post(&sem2);
+	pthread_join(thread, NULL);
+}
+
+ATF_TC_WITHOUT_HEAD(kcov_enable);
+ATF_TC_BODY(kcov_enable, tc)
+{
+	int fd;
+	kcov_int_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
+
+	fd = open_kcov();
+
+	ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE) == -1);
+
+	ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
+
+	/* We need to enable before disable */
+	ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == -1);
+
+	/* Check enabling works only with a valid trace method */
+	ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE) == 0);
+	ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE) == -1);
+
+	/* Disable should only be called once */
+	ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == 0);
+	ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == -1);
+
+	/* Re-enabling should also work */
+	ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE) == 0);
+	ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == 0);
+
+	close(fd);
+}
+
+ATF_TC_WITHOUT_HEAD(kcov_enable_no_disable);
+ATF_TC_BODY(kcov_enable_no_disable, tc)
+{
+	int fd;
+	kcov_int_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
+
+	fd = open_kcov();
+	ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
+	ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE) == 0);
+	close(fd);
+}
+
+ATF_TC_WITHOUT_HEAD(kcov_enable_no_disable_no_close);
+ATF_TC_BODY(kcov_enable_no_disable_no_close, tc)
+{
+	int fd;
+	kcov_int_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
+
+	fd = open_kcov();
+	ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
+	ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE) == 0);
+}
+
+static void *
+common_head(int *fdp)
+{
+	void *data;
+	int fd;
+	kcov_int_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
+
+	fd = open_kcov();
+
+	ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) == 0,
+	    "Unable to set the kcov buffer size");
+
+	data = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+	ATF_REQUIRE_MSG(data != MAP_FAILED, "Unable to mmap the kcov buffer");
+
+	*fdp = fd;
+	return data;
+}
+
+static void
+common_tail(int fd, kcov_int_t *data)
+{
+
+	ATF_REQUIRE_MSG(munmap(__UNVOLATILE(data), PAGE_SIZE) == 0,
+	    "Unable to unmap the kcov buffer");
+
+	close(fd);
+}
+
+ATF_TC_WITHOUT_HEAD(kcov_basic);
+ATF_TC_BODY(kcov_basic, tc)
+{
+	kcov_int_t *buf;
+	int fd;
+
+	buf = common_head(&fd);
+	ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_ENABLE) == 0,
+	    "Unable to enable kcov ");
+
+	__atomic_store_n(&buf[0], 0 , __ATOMIC_RELAXED);
+
+	sleep(0);
+	ATF_REQUIRE_MSG(__atomic_load_n(&buf[0], __ATOMIC_RELAXED) != 0, "No records found");
+
+	ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_DISABLE) == 0,
+	    "Unable to disable kcov");
+
+	common_tail(fd, buf);
+}
+
+static void *
+thread_test_helper(void *ptr)
+{
+	kcov_int_t *buf = ptr;
+
+	__atomic_store_n(&buf[0], 0, __ATOMIC_RELAXED);
+	sleep(0);
+	ATF_REQUIRE_MSG(__atomic_load_n(&buf[0], __ATOMIC_RELAXED) == 0,
+	    "Records changed in blocked thread");
+
+	return NULL;
+}
+
+ATF_TC_WITHOUT_HEAD(kcov_thread);
+ATF_TC_BODY(kcov_thread, tc)
+{
+	pthread_t thread;
+	kcov_int_t *buf;
+	int fd;
+
+	buf = common_head(&fd);
+
+	ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_ENABLE) == 0,
+	    "Unable to enable kcov ");
+
+	pthread_create(&thread, NULL, thread_test_helper, __UNVOLATILE(buf));
+	pthread_join(thread, NULL);
+
+	ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_DISABLE) == 0,
+	    "Unable to disable kcov");
+
+	common_tail(fd, buf);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+	ATF_TP_ADD_TC(tp, kcov_bufsize);
+	ATF_TP_ADD_TC(tp, kcov_mmap);
+	ATF_TP_ADD_TC(tp, kcov_mmap_no_munmap);
+	ATF_TP_ADD_TC(tp, kcov_mmap_no_munmap_no_close);
+	ATF_TP_ADD_TC(tp, kcov_enable);
+	ATF_TP_ADD_TC(tp, kcov_enable_no_disable);
+	ATF_TP_ADD_TC(tp, kcov_enable_no_disable_no_close);
+	ATF_TP_ADD_TC(tp, kcov_mmap_enable_thread_close);
+	ATF_TP_ADD_TC(tp, kcov_basic);
+	ATF_TP_ADD_TC(tp, kcov_thread);
+	return atf_no_error();
+}

Reply via email to