Add kcov(4), a kernel code coverage tracing driver. It's used in conjunction
authoranton <anton@openbsd.org>
Sun, 19 Aug 2018 11:42:33 +0000 (11:42 +0000)
committeranton <anton@openbsd.org>
Sun, 19 Aug 2018 11:42:33 +0000 (11:42 +0000)
with the syzkaller kernel fuzzer. So far, 8 distinct panics have been found and
fixed. This effort will continue.

kcov is limited to architectures using Clang as their default compiler and is
not enabled by default.

With help from mpi@, thanks!

ok kettenis@ mpi@ visa@

16 files changed:
etc/MAKEDEV.common
etc/etc.amd64/MAKEDEV.md
etc/etc.i386/MAKEDEV.md
share/man/man4/Makefile
share/man/man4/kcov.4 [new file with mode: 0644]
sys/arch/amd64/amd64/conf.c
sys/arch/amd64/conf/GENERIC
sys/arch/amd64/conf/Makefile.amd64
sys/arch/amd64/conf/files.amd64
sys/arch/i386/conf/GENERIC
sys/arch/i386/conf/Makefile.i386
sys/arch/i386/conf/files.i386
sys/arch/i386/i386/conf.c
sys/dev/kcov.c [new file with mode: 0644]
sys/kern/kern_exit.c
sys/sys/kcov.h [new file with mode: 0644]

index db19b2d..1631f1b 100644 (file)
@@ -1,4 +1,4 @@
-vers(a, {-$OpenBSD: MAKEDEV.common,v 1.99 2018/07/28 08:09:50 ratchov Exp $-})dnl
+vers(a, {-$OpenBSD: MAKEDEV.common,v 1.100 2018/08/19 11:42:33 anton Exp $-})dnl
 dnl
 dnl Copyright (c) 2001-2006 Todd T. Fries <todd@OpenBSD.org>
 dnl
@@ -167,6 +167,7 @@ target(all, fuse)dnl
 target(all, vmm)dnl
 target(all, pvbus, 0, 1)dnl
 target(all, bpf)dnl
+target(all, kcov)dnl
 dnl
 _mkdev(all, {-all-}, {-dnl
 show_target(all)dnl
@@ -521,3 +522,5 @@ _mkdev(vmm, vmm, {-M vmm c major_vmm_c 0 600-})dnl
 __devitem(pvbus, pvbus*, paravirtual device tree root)dnl
 _mkdev(pvbus, {-pvbus*-}, {-M pvbus$U c major_pvbus_c $U 640-}, 640)dnl
 _mkdev(local, local, {-test -s $T.local && sh $T.local-})dnl
+__devitem(kcov, kcov, Kernel code coverage tracing)dnl
+_mkdev(kcov, kcov, {-M kcov c major_kcov_c 0 600-})dnl
index cd915ec..1aa4f67 100644 (file)
@@ -1,6 +1,6 @@
 define(MACHINE,amd64)dnl
 vers(__file__,
-       {-$OpenBSD: MAKEDEV.md,v 1.69 2016/09/11 19:59:53 deraadt Exp $-},
+       {-$OpenBSD: MAKEDEV.md,v 1.70 2018/08/19 11:42:33 anton Exp $-},
 etc.MACHINE)dnl
 dnl
 dnl Copyright (c) 2001-2006 Todd T. Fries <todd@OpenBSD.org>
@@ -77,6 +77,7 @@ _DEV(hotplug, 82)
 _DEV(ipmi, 96)
 dnl _DEV(joy, 26)
 _DEV(nvram, 85)
+_DEV(kcov, 19)
 _DEV(pci, 72)
 _DEV(pctr, 46)
 _DEV(pf, 73)
index c7f74ee..a06b503 100644 (file)
@@ -1,6 +1,6 @@
 define(MACHINE,i386)dnl
 vers(__file__,
-       {-$OpenBSD: MAKEDEV.md,v 1.83 2016/09/11 19:59:53 deraadt Exp $-},
+       {-$OpenBSD: MAKEDEV.md,v 1.84 2018/08/19 11:42:33 anton Exp $-},
 etc.MACHINE)dnl
 dnl
 dnl Copyright (c) 2001-2006 Todd T. Fries <todd@OpenBSD.org>
@@ -78,6 +78,7 @@ _DEV(gpr, 80)
 _DEV(hotplug, 82)
 _DEV(ipmi, 96)
 _DEV(joy, 26)
+_DEV(kcov, 19)
 _DEV(nvram, 84)
 _DEV(pci, 72)
 _DEV(pctr, 46)
index d4099ec..fdb3ca2 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: Makefile,v 1.689 2018/08/03 01:50:14 kevlo Exp $
+#      $OpenBSD: Makefile,v 1.690 2018/08/19 11:42:33 anton Exp $
 
 MAN=   aac.4 ac97.4 acphy.4 acrtc.4 \
        acpi.4 acpiac.4 acpials.4 acpiasus.4 acpibat.4 \
@@ -37,7 +37,7 @@ MAN=  aac.4 ac97.4 acphy.4 acrtc.4 \
        ip.4 ip6.4 ipcomp.4 ipgphy.4 ipmi.4 ips.4 ipsec.4 ipw.4 \
        isa.4 isagpio.4 isapnp.4 islrtc.4 it.4 itherm.4 iwi.4 iwn.4 iwm.4 \
        ix.4 ixgb.4 jmb.4 jme.4 jmphy.4 \
-       kate.4 km.4 ksyms.4 kue.4 lc.4 lge.4 lii.4 lisa.4 lm.4 \
+       kate.4 kcov.4 km.4 ksyms.4 kue.4 lc.4 lge.4 lii.4 lisa.4 lm.4 \
        lmenv.4 lmn.4 lmtemp.4 lo.4 lpt.4 lxtphy.4 luphy.4 \
        maestro.4 mainbus.4 malo.4 maxds.4 maxrtc.4 maxtmp.4 mbg.4 midi.4 \
        mii.4 mfi.4 \
diff --git a/share/man/man4/kcov.4 b/share/man/man4/kcov.4
new file mode 100644 (file)
index 0000000..582bc46
--- /dev/null
@@ -0,0 +1,137 @@
+.\"    $OpenBSD: kcov.4,v 1.1 2018/08/19 11:42:33 anton Exp $
+.\"
+.\" Copyright (c) 2018 Anton Lindqvist <anton@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 $Mdocdate: August 19 2018 $
+.Dt KCOV 4
+.Os
+.Sh NAME
+.Nm kcov
+.Nd kernel code coverage tracing
+.Sh SYNOPSIS
+.Cd option 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 option KCOV
+to be present,
+see
+.Xr options 4 .
+.Pp
+The following
+.Xr ioctl 2
+calls are provided:
+.Bl -tag -width 4n
+.It Dv KIOSETBUFSIZE Fa unsigned long *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 unsigned long
+entries.
+The first entry contains the number of entries in the array,
+excluding the first entry.
+.It Dv KIOENABLE Fa void
+Enable code coverage tracing for the current process.
+.It Dv KIODISABLE Fa void
+Disable code coverage tracing for the current process.
+.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 <sys/ioctl.h>
+#include <sys/kcov.h>
+#include <sys/mman.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int
+main(void)
+{
+       unsigned long *cover, i;
+       unsigned long size = 1024;
+       int fd;
+
+       fd = open("/dev/kcov", O_RDWR);
+       if (fd == -1)
+               err(1, "open");
+
+       if (ioctl(fd, KIOSETBUFSIZE, &size) == -1)
+               err(1, "ioctl: KIOSETBUFSIZE");
+       cover = mmap(NULL, size * sizeof(unsigned long),
+           PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+       if (cover == MAP_FAILED)
+               err(1, "mmap");
+
+       if (ioctl(fd, KIOENABLE) == -1)
+               err(1, "ioctl: KIOENABLE");
+       read(-1, NULL, 0);
+       if (ioctl(fd, KIODISABLE) == -1)
+               err(1, "ioctl: KIODISABLE");
+
+       for (i = 0; i < cover[0]; i++)
+               printf("%p\en", (void *)cover[i + 1]);
+
+       if (munmap(cover, size * sizeof(unsigned long)) == -1)
+               err(1, "munmap");
+       close(fd);
+
+       return 0;
+}
+.Ed
+.Sh SEE ALSO
+.Xr options 4
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Ox 6.4 .
+.Sh AUTHORS
+.An Anton Lindqvist Aq Mt anton@openbsd.org
+.Sh CAVEATS
+The
+.Nm
+driver is limited to architectures using
+.Xr clang 1
+as their default compiler.
index 731a1d8..b629a95 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: conf.c,v 1.60 2016/09/04 10:51:23 naddy Exp $ */
+/*     $OpenBSD: conf.c,v 1.61 2018/08/19 11:42:33 anton Exp $ */
 
 /*
  * Copyright (c) 1994, 1995 Charles M. Hannum.  All rights reserved.
@@ -112,6 +112,12 @@ int        nblkdev = nitems(bdevsw);
        (dev_type_stop((*))) enodev, 0, seltrue, \
        (dev_type_mmap((*))) enodev }
 
+/* open, close, ioctl, mmap */
+#define cdev_kcov_init(c,n) { \
+       dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \
+       (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \
+       (dev_type_stop((*))) enodev, 0, selfalse, \
+       (dev_init(c,n,mmap)), 0, D_CLONE }
 
 #define        mmread  mmrw
 #define        mmwrite mmrw
@@ -164,6 +170,7 @@ cdev_decl(nvram);
 cdev_decl(drm);
 #include "viocon.h"
 cdev_decl(viocon);
+cdev_decl(kcov);
 
 #include "wsdisplay.h"
 #include "wskbd.h"
@@ -207,7 +214,7 @@ struct cdevsw       cdevsw[] =
        cdev_lpt_init(NLPT,lpt),        /* 16: parallel printer */
        cdev_ch_init(NCH,ch),           /* 17: SCSI autochanger */
        cdev_notdef(),                  /* 18: was: concatenated disk driver */
-       cdev_notdef(),                  /* 19 */
+       cdev_kcov_init(1,kcov),         /* 19: kcov */
        cdev_uk_init(NUK,uk),           /* 20: unknown SCSI */
        cdev_notdef(),                  /* 21 */
        cdev_fd_init(1,filedesc),       /* 22: file descriptor pseudo-device */
index d07eb34..d3b593f 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: GENERIC,v 1.457 2018/08/03 01:50:14 kevlo Exp $
+#      $OpenBSD: GENERIC,v 1.458 2018/08/19 11:42:33 anton Exp $
 #
 # For further information on compiling OpenBSD kernels, see the config(8)
 # man page.
@@ -658,6 +658,9 @@ pseudo-device       hotplug         1       # devices hot plugging
 # mouse & keyboard multiplexor pseudo-devices
 pseudo-device  wsmux           2
 
+# kernel code coverage
+pseudo-device  kcov            1
+
 # Virtio devices
 virtio*                at pci?         # Virtio PCI device
 vioblk*                at virtio?      # Virtio block device
index 3950ac5..f6f6f28 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: Makefile.amd64,v 1.98 2018/07/13 08:10:56 deraadt Exp $
+#      $OpenBSD: Makefile.amd64,v 1.99 2018/08/19 11:42:33 anton Exp $
 
 # For instructions on building kernels consult the config(8) and options(4)
 # manual pages.
@@ -43,6 +43,10 @@ SORTR=               cat
 .else
 CMACHFLAGS+=   -mretpoline
 .endif
+.if ${IDENT:M-DKCOV} && ${COMPILER_VERSION:Mclang}
+CMACHFLAGS+=   -fno-ret-protector
+PROF=          -fsanitize-coverage=trace-pc
+.endif
 .if ${COMPILER_VERSION:Mclang}
 NO_INTEGR_AS=  -no-integrated-as
 .endif
@@ -135,6 +139,12 @@ vers.o: ${SYSTEM_DEP:Ngap.o}
        sh $S/conf/newvers.sh
        ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c vers.c
 
+.if ${IDENT:M-DKCOV} && ${COMPILER_VERSION:Mclang}
+kcov.o: $S/dev/kcov.c
+       ${NORMAL_C} -fno-sanitize-coverage=trace-pc
+.endif
+
+
 clean:
        rm -f *bsd *bsd.gdb *.[dio] [a-z]*.s assym.* \
            gap.link ld.script lorder makegap.sh param.c
index 6da1a7b..a4b89dd 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: files.amd64,v 1.97 2018/07/12 12:46:00 fcambus Exp $
+#      $OpenBSD: files.amd64,v 1.98 2018/08/19 11:42:33 anton Exp $
 
 maxpartitions 16
 maxusers 2 16 128
@@ -244,6 +244,12 @@ attach vmm at mainbus
 file   arch/amd64/amd64/vmm.c                  vmm             needs-flag
 file   arch/amd64/amd64/vmm_support.S          vmm
 
+#
+# KCOV
+#
+pseudo-device kcov
+file   dev/kcov.c                              kcov
+
 #
 # Machine-independent SD/MMC drivers
 #
index 5907f8f..494d6e0 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: GENERIC,v 1.833 2018/08/03 01:50:14 kevlo Exp $
+#      $OpenBSD: GENERIC,v 1.834 2018/08/19 11:42:33 anton Exp $
 #
 # For further information on compiling OpenBSD kernels, see the config(8)
 # man page.
@@ -764,6 +764,9 @@ pseudo-device       hotplug         1       # devices hot plugging
 # mouse & keyboard multiplexor pseudo-devices
 pseudo-device  wsmux           2
 
+# kernel code coverage
+pseudo-device  kcov            1
+
 # Virtio devices
 virtio*                at pci?         # Virtio PCI device
 vioblk*                at virtio?      # Virtio block device
index 45034af..7ca4991 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: Makefile.i386,v 1.124 2018/07/13 08:10:45 deraadt Exp $
+#      $OpenBSD: Makefile.i386,v 1.125 2018/08/19 11:42:33 anton Exp $
 
 # For instructions on building kernels consult the config(8) and options(4)
 # manual pages.
@@ -39,6 +39,9 @@ SORTR=                cat
 .else
 CMACHFLAGS+=   -mretpoline
 .endif
+.if ${IDENT:M-DKCOV} && ${COMPILER_VERSION:Mclang}
+PROF=          -fsanitize-coverage=trace-pc
+.endif
 .if ${COMPILER_VERSION:Mclang}
 NO_INTEGR_AS=  -no-integrated-as
 .endif
@@ -138,6 +141,11 @@ vers.o: ${SYSTEM_DEP:Ngap.o}
        sh $S/conf/newvers.sh
        ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c vers.c
 
+.if ${IDENT:M-DKCOV} && ${COMPILER_VERSION:Mclang}
+kcov.o: $S/dev/kcov.c
+       ${NORMAL_C} -fno-sanitize-coverage=trace-pc
+.endif
+
 clean:
        rm -f *bsd *bsd.gdb *.[dio] [a-z]*.s assym.* \
            gap.link ld.script lorder makegap.sh param.c
index 89017ce..0685b8e 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: files.i386,v 1.239 2018/07/09 19:20:29 guenther Exp $
+#      $OpenBSD: files.i386,v 1.240 2018/08/19 11:42:33 anton Exp $
 #
 # new style config file for i386 architecture
 #
@@ -398,6 +398,12 @@ attach vmm at mainbus
 file   arch/i386/i386/vmm.c                    vmm needs-flag
 file   arch/i386/i386/vmm_support.S            vmm
 
+#
+# KCOV
+#
+pseudo-device  kcov
+file           dev/kcov.c                      kcov
+
 #
 # IPMI
 #
index 1622e6a..891b3a3 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: conf.c,v 1.158 2016/10/21 06:20:58 mlarkin Exp $      */
+/*     $OpenBSD: conf.c,v 1.159 2018/08/19 11:42:33 anton Exp $        */
 /*     $NetBSD: conf.c,v 1.75 1996/05/03 19:40:20 christos Exp $       */
 
 /*
@@ -114,6 +114,13 @@ int        nblkdev = nitems(bdevsw);
        (dev_type_stop((*))) enodev, 0, seltrue, \
        (dev_type_mmap((*))) enodev }
 
+/* open, close, ioctl, mmap */
+#define cdev_kcov_init(c,n) { \
+       dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \
+       (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \
+       (dev_type_stop((*))) enodev, 0, selfalse, \
+       (dev_init(c,n,mmap)), 0, D_CLONE }
+
 #define        mmread  mmrw
 #define        mmwrite mmrw
 cdev_decl(mm);
@@ -165,6 +172,7 @@ cdev_decl(cztty);
 cdev_decl(nvram);
 #include "drm.h"
 cdev_decl(drm);
+cdev_decl(kcov);
 
 #include "wsdisplay.h"
 #include "wskbd.h"
@@ -211,7 +219,7 @@ struct cdevsw       cdevsw[] =
        cdev_lpt_init(NLPT,lpt),        /* 16: parallel printer */
        cdev_ch_init(NCH,ch),           /* 17: SCSI autochanger */
        cdev_notdef(),                  /* 18: was: concatenated disk driver */
-       cdev_notdef(),                  /* 19 */
+       cdev_kcov_init(1,kcov),         /* 19: kcov */
        cdev_uk_init(NUK,uk),           /* 20: unknown SCSI */
        cdev_acpiapm_init(1,acpiapm),   /* 21: Power Management stuff */
        cdev_fd_init(1,filedesc),       /* 22: file descriptor pseudo-device */
diff --git a/sys/dev/kcov.c b/sys/dev/kcov.c
new file mode 100644 (file)
index 0000000..cc8686a
--- /dev/null
@@ -0,0 +1,277 @@
+/*     $OpenBSD: kcov.c,v 1.1 2018/08/19 11:42:33 anton Exp $  */
+
+/*
+ * Copyright (c) 2018 Anton Lindqvist <anton@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.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/kcov.h>
+#include <sys/malloc.h>
+#include <sys/stdint.h>
+#include <sys/queue.h>
+
+#include <uvm/uvm_extern.h>
+
+/* #define KCOV_DEBUG */
+#ifdef KCOV_DEBUG
+#define DPRINTF(x...) do { if (kcov_debug) printf(x); } while (0)
+#else
+#define DPRINTF(x...)
+#endif
+
+/* kcov descriptor */
+struct kd {
+       enum {
+               KCOV_MODE_DISABLED,
+               KCOV_MODE_INIT,
+               KCOV_MODE_TRACE_PC,
+       }                kd_mode;
+       int              kd_unit;       /* device minor */
+       pid_t            kd_pid;        /* process being traced */
+       uintptr_t       *kd_buf;        /* traced coverage */
+       size_t           kd_nmemb;
+       size_t           kd_size;
+
+       TAILQ_ENTRY(kd)  kd_entry;
+};
+
+void kcovattach(int);
+
+int kd_alloc(struct kd *, unsigned long);
+struct kd *kd_lookup(int);
+
+static inline struct kd *kd_lookup_pid(pid_t);
+static inline int inintr(void);
+
+TAILQ_HEAD(, kd) kd_list = TAILQ_HEAD_INITIALIZER(kd_list);
+
+#ifdef KCOV_DEBUG
+int kcov_debug = 1;
+#endif
+
+/*
+ * Compiling the kernel with the `-fsanitize-coverage=trace-pc' option will
+ * cause the following function to be called upon function entry and before
+ * each block instructions that maps to a single line in the original source
+ * code.
+ *
+ * If kcov is enabled for the current process, the executed address will be
+ * stored in the corresponding coverage buffer.
+ * The first element in the coverage buffer holds the index of next available
+ * element.
+ */
+void
+__sanitizer_cov_trace_pc(void)
+{
+       extern int cold;
+       struct kd *kd;
+       uint64_t idx;
+
+       /* Do not trace during boot. */
+       if (cold)
+               return;
+
+       /* Do not trace in interrupts to prevent noisy coverage. */
+       if (inintr())
+               return;
+
+       kd = kd_lookup_pid(curproc->p_p->ps_pid);
+       if (kd == NULL)
+               return;
+
+       idx = kd->kd_buf[0];
+       if (idx < kd->kd_nmemb) {
+               kd->kd_buf[idx + 1] = (uintptr_t)__builtin_return_address(0);
+               kd->kd_buf[0] = idx + 1;
+       }
+}
+
+void
+kcovattach(int count)
+{
+}
+
+int
+kcovopen(dev_t dev, int flag, int mode, struct proc *p)
+{
+#ifdef KCOV
+       struct kd *kd;
+
+       if (kd_lookup(minor(dev)) != NULL)
+               return (EBUSY);
+
+       DPRINTF("%s: unit=%d\n", __func__, minor(dev));
+
+       kd = malloc(sizeof(*kd), M_SUBPROC, M_WAITOK | M_ZERO);
+       kd->kd_unit = minor(dev);
+       TAILQ_INSERT_TAIL(&kd_list, kd, kd_entry);
+       return (0);
+#else
+       return (ENXIO);
+#endif
+}
+
+int
+kcovclose(dev_t dev, int flag, int mode, struct proc *p)
+{
+       struct kd *kd;
+
+       kd = kd_lookup(minor(dev));
+       if (kd == NULL)
+               return (EINVAL);
+
+       DPRINTF("%s: unit=%d\n", __func__, minor(dev));
+
+       TAILQ_REMOVE(&kd_list, kd, kd_entry);
+       free(kd->kd_buf, M_SUBPROC, kd->kd_size);
+       free(kd, M_SUBPROC, sizeof(struct kd));
+       return (0);
+}
+
+int
+kcovioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
+{
+       struct kd *kd;
+       int error = 0;
+
+       kd = kd_lookup(minor(dev));
+       if (kd == NULL)
+               return (ENXIO);
+
+       switch (cmd) {
+       case KIOSETBUFSIZE:
+               if (kd->kd_mode != KCOV_MODE_DISABLED) {
+                       error = EBUSY;
+                       break;
+               }
+               error = kd_alloc(kd, *((unsigned long *)data));
+               if (error == 0)
+                       kd->kd_mode = KCOV_MODE_INIT;
+               break;
+       case KIOENABLE:
+               if (kd->kd_mode != KCOV_MODE_INIT) {
+                       error = EBUSY;
+                       break;
+               }
+               kd->kd_mode = KCOV_MODE_TRACE_PC;
+               kd->kd_pid = p->p_p->ps_pid;
+               break;
+       case KIODISABLE:
+               /* Only the enabled process may disable itself. */
+               if (kd->kd_pid != p->p_p->ps_pid ||
+                   kd->kd_mode != KCOV_MODE_TRACE_PC) {
+                       error = EBUSY;
+                       break;
+               }
+               kd->kd_mode = KCOV_MODE_INIT;
+               kd->kd_pid = 0;
+               break;
+       default:
+               error = EINVAL;
+               DPRINTF("%s: %lu: unknown command\n", __func__, cmd);
+       }
+
+       DPRINTF("%s: unit=%d, mode=%d, pid=%d, error=%d\n",
+                   __func__, kd->kd_unit, kd->kd_mode, kd->kd_pid, error);
+
+       return (error);
+}
+
+paddr_t
+kcovmmap(dev_t dev, off_t offset, int prot)
+{
+       struct kd *kd;
+       paddr_t pa;
+       vaddr_t va;
+
+       kd = kd_lookup(minor(dev));
+       if (kd == NULL)
+               return (paddr_t)(-1);
+
+       if (offset < 0 || offset >= kd->kd_nmemb * sizeof(uintptr_t))
+               return (paddr_t)(-1);
+
+       va = (vaddr_t)kd->kd_buf + offset;
+       if (pmap_extract(pmap_kernel(), va, &pa) == FALSE)
+               return (paddr_t)(-1);
+       return (pa);
+}
+
+void
+kcov_exit(struct proc *p)
+{
+       struct kd *kd;
+
+       kd = kd_lookup_pid(p->p_p->ps_pid);
+       if (kd == NULL)
+               return;
+
+       kd->kd_mode = KCOV_MODE_INIT;
+       kd->kd_pid = 0;
+}
+
+struct kd *
+kd_lookup(int unit)
+{
+       struct kd *kd;
+
+       TAILQ_FOREACH(kd, &kd_list, kd_entry) {
+               if (kd->kd_unit == unit)
+                       return (kd);
+       }
+       return (NULL);
+}
+
+int
+kd_alloc(struct kd *kd, unsigned long nmemb)
+{
+       size_t size;
+
+       KASSERT(kd->kd_buf == NULL);
+
+       if (nmemb == 0 || nmemb > KCOV_BUF_MAX_NMEMB)
+               return (EINVAL);
+
+       size = roundup(nmemb * sizeof(uintptr_t), PAGE_SIZE);
+       kd->kd_buf = malloc(size, M_SUBPROC, M_WAITOK | M_ZERO);
+       /* The first element is reserved to hold the number of used elements. */
+       kd->kd_nmemb = nmemb - 1;
+       kd->kd_size = size;
+       return (0);
+}
+
+static inline struct kd *
+kd_lookup_pid(pid_t pid)
+{
+       struct kd *kd;
+
+       TAILQ_FOREACH(kd, &kd_list, kd_entry) {
+               if (kd->kd_pid == pid && kd->kd_mode == KCOV_MODE_TRACE_PC)
+                       return (kd);
+       }
+       return (NULL);
+}
+
+static inline int
+inintr(void)
+{
+#if defined(__amd64__) || defined(__i386__)
+       return (curcpu()->ci_idepth > 0);
+#else
+       return (0);
+#endif
+}
index 4e1f1de..4bacf19 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: kern_exit.c,v 1.166 2018/08/13 15:26:17 visa Exp $    */
+/*     $OpenBSD: kern_exit.c,v 1.167 2018/08/19 11:42:33 anton Exp $   */
 /*     $NetBSD: kern_exit.c,v 1.39 1996/04/22 01:38:25 christos Exp $  */
 
 /*
@@ -56,6 +56,7 @@
 #include <sys/filedesc.h>
 #include <sys/signalvar.h>
 #include <sys/sched.h>
+#include <sys/kcov.h>
 #include <sys/ktrace.h>
 #include <sys/pool.h>
 #include <sys/mutex.h>
@@ -189,6 +190,10 @@ exit1(struct proc *p, int rv, int flags)
                acct_process(p);
 #endif
 
+#ifdef KCOV
+               kcov_exit(p);
+#endif
+
 #ifdef KTRACE
                /* release trace file */
                if (pr->ps_tracevp)
diff --git a/sys/sys/kcov.h b/sys/sys/kcov.h
new file mode 100644 (file)
index 0000000..752b290
--- /dev/null
@@ -0,0 +1,36 @@
+/*     $OpenBSD: kcov.h,v 1.1 2018/08/19 11:42:33 anton Exp $  */
+
+/*
+ * Copyright (c) 2018 Anton Lindqvist <anton@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.
+ */
+
+#ifndef _SYS_KCOV_H_
+#define _SYS_KCOV_H_
+
+#include <sys/ioccom.h>
+
+#define KIOSETBUFSIZE  _IOW('K', 1, unsigned long)
+#define KIOENABLE      _IO('K', 2)
+#define KIODISABLE     _IO('K', 3)
+
+#ifdef _KERNEL
+
+#define KCOV_BUF_MAX_NMEMB     (256 << 10)
+
+void kcov_exit(struct proc *);
+
+#endif /* _KERNEL */
+
+#endif /* !_SYS_KCOV_H_ */