diff --git a/distrib/sets/lists/comp/mi b/distrib/sets/lists/comp/mi index 1bfaf71382c7..16e99dbd7bce 100644 --- a/distrib/sets/lists/comp/mi +++ b/distrib/sets/lists/comp/mi @@ -3002,6 +3002,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 diff --git a/distrib/sets/lists/man/mi b/distrib/sets/lists/man/mi index 8833a276b893..9e61b37871a7 100644 --- a/distrib/sets/lists/man/mi +++ b/distrib/sets/lists/man/mi @@ -1371,6 +1371,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 @@ -4489,6 +4490,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 @@ -7447,6 +7449,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 diff --git a/distrib/sets/lists/modules/mi b/distrib/sets/lists/modules/mi index 977a172d141f..58115c7ea902 100644 --- a/distrib/sets/lists/modules/mi +++ b/distrib/sets/lists/modules/mi @@ -198,6 +198,8 @@ ./@MODULEDIR@/ipl/ipl.kmod base-kernel-modules kmod ./@MODULEDIR@/iscsi base-kernel-modules kmod,iscsi ./@MODULEDIR@/iscsi/iscsi.kmod base-kernel-modules kmod,iscsi +./@MODULEDIR@/kcov base-kernel-modules kmod +./@MODULEDIR@/kcov/kcov.kmod base-kernel-modules kmod ./@MODULEDIR@/kernfs base-kernel-modules kmod ./@MODULEDIR@/kernfs/kernfs.kmod base-kernel-modules kmod ./@MODULEDIR@/ksem base-obsolete obsolete diff --git a/distrib/sets/lists/tests/module.mi b/distrib/sets/lists/tests/module.mi index 79703a5d7b3c..c460abc9ad1a 100644 --- a/distrib/sets/lists/tests/module.mi +++ b/distrib/sets/lists/tests/module.mi @@ -14,6 +14,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,rump ./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 diff --git a/etc/MAKEDEV.tmpl b/etc/MAKEDEV.tmpl index 222a3c820248..408fc3f89f43 100644 --- a/etc/MAKEDEV.tmpl +++ b/etc/MAKEDEV.tmpl @@ -2213,7 +2213,9 @@ nvmm) autofs) mkdev autofs c %autofs_chr% 0 600 ;; - +kcov) + mkdev kcov c %kcov_chr% 0 + ;; midevend) %MI_DEVICES_END% local) diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index fee1a6aef87e..c0502e68e641 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -36,7 +36,7 @@ MAN= aac.4 ac97.4 acardide.4 aceride.4 acphy.4 \ 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 mhzc.4 \ diff --git a/share/man/man4/kcov.4 b/share/man/man4/kcov.4 new file mode 100644 index 000000000000..2c38a82f7380 --- /dev/null +++ b/share/man/man4/kcov.4 @@ -0,0 +1,134 @@ +.\" $NetBSD$ +.\" +.\" Copyright (c) 2018 Anton Lindqvist +.\" +.\" Ported to NetBSD by Siddharth Muralee +.\" +.\" 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 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 +#include +#include +#include +#include + +#include +#include +#include +#include + +int +main(void) +{ + unsigned long *cover, i, n; + unsigned long size = 1024 * 100; + 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_PRIVATE, fd, 0); + if (cover == MAP_FAILED) + err(1, "mmap"); + if (ioctl(fd, KIOENABLE) == -1) + err(1, "ioctl: KIOENABLE"); + __atomic_store_n(&cover[0], 0, __ATOMIC_RELAXED); + read(-1, NULL, 0); // syscall paths to be figured out + n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED); + 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 +It first appeared +.Ox 6.4. +The +.Nm +driver was ported to +.Nx 9. +.Sh AUTHORS +.An Siddharth Muralee Aq Mt siddharth.muralee@gmail.com diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC index 3957ed48b528..ec0d487c7780 100644 --- a/sys/arch/amd64/conf/GENERIC +++ b/sys/arch/amd64/conf/GENERIC @@ -125,6 +125,10 @@ options KDTRACE_HOOKS # kernel DTrace hooks #options KASAN #no options SVS +# kernel code coverage +#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 diff --git a/sys/arch/amd64/conf/Makefile.amd64 b/sys/arch/amd64/conf/Makefile.amd64 index 9a1785cf4e8c..dab259d4f5eb 100644 --- a/sys/arch/amd64/conf/Makefile.amd64 +++ b/sys/arch/amd64/conf/Makefile.amd64 @@ -59,6 +59,15 @@ KASANFLAGS.${f}= # empty CFLAGS+= ${KASANFLAGS.${.IMPSRC:T}:U${KASANFLAGS}} .endif +.if ${KCOV:U0} > 0 && ${HAVE_GCC:U0} > 0 +KCOVFLAGS= -fno-stack-protector -fsanitize-coverage=trace-pc +.for f in kcov.c +KCOVFLAGS.${f}= # empty +.endfor +CFLAGS+= ${KCOVFLAGS.${.IMPSRC:T}:U${KCOVFLAGS}} +.endif + + ## ## (3) libkern and compat ## diff --git a/sys/conf/majors b/sys/conf/majors index 7b1c169eaf11..fad325aa543e 100644 --- a/sys/conf/majors +++ b/sys/conf/majors @@ -79,3 +79,4 @@ device-major qemufwcfg char 342 qemufwcfg device-major autofs char 343 autofs device-major gpiopps char 344 gpiopps device-major nvmm char 345 nvmm +device-major kcov char 346 kcov diff --git a/sys/dev/files.dev b/sys/dev/files.dev index f187877d8938..dce28c65c925 100644 --- a/sys/dev/files.dev +++ b/sys/dev/files.dev @@ -16,6 +16,7 @@ file dev/dkwedge/dkwedge_rdb.c dkwedge_method_rdb file dev/firmload.c firmload file dev/fss.c fss file dev/keylock.c keylock +file dev/kcov.c kcov file dev/lockstat.c lockstat needs-flag file dev/md.c md file dev/mm.c kern # XXX diff --git a/sys/dev/kcov.c b/sys/dev/kcov.c new file mode 100644 index 000000000000..d6692a4d84b1 --- /dev/null +++ b/sys/dev/kcov.c @@ -0,0 +1,317 @@ +/* $NetBSD$ */ + +/* + * Copyright (c) 2018 Anton Lindqvist + * + * Ported to NetBSD by Siddharth Muralee + * + * 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* #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; +}; + + +int kd_alloc(struct kd *, unsigned long); +struct kd *kd_lookup(int); + +static inline struct kd *kd_lookup_pid(pid_t); +static inline int in_interrupt(void); + +TAILQ_HEAD(, kd) kd_list = TAILQ_HEAD_INITIALIZER(kd_list); + +#ifdef KCOV_DEBUG +int kcov_debug = 1; +#endif + +static dev_type_open(kcovopen); +static dev_type_close(kcovclose); +static dev_type_ioctl(kcovioctl); +static dev_type_mmap(kcovmmap); + +const struct cdevsw kcov_cdevsw = { + .d_open = kcovopen, + .d_close = kcovclose, + .d_read = noread, + .d_write = nowrite, + .d_ioctl = kcovioctl, + .d_stop = nostop, + .d_tty = notty, + .d_poll = nopoll, + .d_mmap = kcovmmap, + .d_kqfilter = nokqfilter, + .d_discard = nodiscard, + .d_flag = D_OTHER +}; + +/* + * 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 (in_interrupt()) + return; + + kd = kd_lookup_pid(curproc->p_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; + } +} + +int +kcovopen(dev_t dev, int flag, int mode, struct lwp *l) +{ + struct kd *kd; + + if (kd_lookup(minor(dev)) != NULL) + return EBUSY; + + DPRINTF("%s: unit=%d\n", __func__, minor(dev)); + + kd = kmem_zalloc(sizeof(*kd), M_WAITOK | M_ZERO); + kd->kd_unit = minor(dev); + TAILQ_INSERT_TAIL(&kd_list, kd, kd_entry); + return 0; +} + +int +kcovclose(dev_t dev, int flag, int mode, struct lwp *l) +{ + 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); + kmem_free(kd->kd_buf, kd->kd_size); + kmem_free(kd, sizeof(struct kd)); + return 0; +} + +int +kcovioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) +{ + 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 *)addr)); + 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 = l->l_proc->p_pid; + break; + case KIODISABLE: + /* Only the enabled process may disable itself. */ + if (kd->kd_pid != l->l_proc->p_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 atop(pa); +} + +void +kcov_exit(struct proc *p) +{ + struct kd *kd; + + kd = kd_lookup_pid(p->p_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(vaddr_t), PAGE_SIZE); + kd->kd_buf = kmem_zalloc(size, 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 int +in_interrupt(void) +{ + return curcpu()->ci_idepth >= 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; +} + +MODULE(MODULE_CLASS_MISC, kcov, NULL); + +static int +kcov_modcmd(modcmd_t cmd, void *arg __unused) +{ +#ifdef _MODULE + int bmajor = -1, cmajor = -1; +#endif + switch (cmd) { + case MODULE_CMD_INIT: +#ifdef _MODULE + if (devsw_attach("kcov", NULL, &bmajor, &kcov_cdevsw, + &cmajor)) + return ENXIO; +#endif + return 0; + case MODULE_CMD_FINI: +#ifdef _MODULE + devsw_detach(NULL, &kcov_cdevsw); + return 0; +#endif + default: + return ENOTTY; + } +} + diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index d5a9d3c1fc60..32d3cbd79b8e 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -106,6 +106,7 @@ __KERNEL_RCSID(0, "$NetBSD: kern_exit.c,v 1.272 2018/07/12 10:46:48 maxv Exp $") #include #include +#include #ifdef DEBUG_EXIT int debug_exit = 0; @@ -255,6 +256,9 @@ exit1(struct lwp *l, int exitcode, int signo) sigfillset(&p->p_sigctx.ps_sigignore); sigclearall(p, NULL, &kq); p->p_stat = SDYING; +#ifdef KCOV + kcov_exit(p); +#endif mutex_exit(p->p_lock); ksiginfo_queue_drain(&kq); diff --git a/sys/modules/Makefile b/sys/modules/Makefile index d02beb6636d7..0010835365eb 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.210 2018/11/07 07:43:08 maxv Exp $ +#$NetBSD: Makefile,v 1.210 2018/11/07 07:43:08 maxv Exp $ .include @@ -79,6 +79,7 @@ SUBDIR+= iic SUBDIR+= ip_ecn SUBDIR+= ipl SUBDIR+= kernfs +SUBDIR+= kcov SUBDIR+= layerfs SUBDIR+= lfs SUBDIR+= lua diff --git a/sys/modules/kcov/Makefile b/sys/modules/kcov/Makefile new file mode 100644 index 000000000000..50e5952531bb --- /dev/null +++ b/sys/modules/kcov/Makefile @@ -0,0 +1,11 @@ +#$NetBSD$ + +.include "../Makefile.inc" + +.PATH: ${S}/dev + +KMOD= kcov + +SRCS+= kcov.c + +.include diff --git a/sys/sys/Makefile b/sys/sys/Makefile index 0232e39170c1..bd741fbc55a8 100644 --- a/sys/sys/Makefile +++ b/sys/sys/Makefile @@ -25,7 +25,7 @@ INCS= acct.h agpio.h aio.h ansi.h aout_mids.h ataio.h atomic.h \ 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 \ diff --git a/sys/sys/kcov.h b/sys/sys/kcov.h new file mode 100644 index 000000000000..784f91971752 --- /dev/null +++ b/sys/sys/kcov.h @@ -0,0 +1,36 @@ +/* $NetBSD$ */ + +/* + * Copyright (c) 2018 Anton Lindqvist + * + * Ported to NetBSD by Siddharth Muralee + * + * 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 +#include + +#define KIOSETBUFSIZE _IOW('K', 1, unsigned long) +#define KIOENABLE _IO('K', 2) +#define KIODISABLE _IO('K', 3) + + +#define KCOV_BUF_MAX_NMEMB (256 << 10) +struct proc; +void kcov_exit(struct proc *); +void __sanitizer_cov_trace_pc(void); +#endif /* !_SYS_KCOV_H_ */ diff --git a/tests/modules/Makefile b/tests/modules/Makefile index 8ad317baa49c..f45312d5359d 100644 --- a/tests/modules/Makefile +++ b/tests/modules/Makefile @@ -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 diff --git a/tests/modules/t_kcov.c b/tests/modules/t_kcov.c new file mode 100644 index 000000000000..0985b67ec242 --- /dev/null +++ b/tests/modules/t_kcov.c @@ -0,0 +1,80 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2018 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 + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +ATF_TC(kcov1); + +ATF_TC_HEAD(kcov1, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checking if kcov properly"); +} + +ATF_TC_BODY(kcov1, tc) +{ + unsigned long *cover, n; + unsigned long size = 1024 * 100; + int fd; + + fd = open("/dev/kcov", O_RDWR); + ATF_REQUIRE(fd != -1); + ATF_REQUIRE(ioctl(fd, KIOSETBUFSIZE, &size) != -1); + cover = mmap(NULL, size * sizeof(unsigned long), + PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + ATF_REQUIRE(cover != MAP_FAILED); + ATF_REQUIRE(ioctl(fd, KIOENABLE) != -1); + __atomic_store_n(&cover[0], 0, __ATOMIC_RELAXED); + read(-1, NULL, 0); // syscall paths to be figured out + n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED); + ATF_REQUIRE(ioctl(fd, KIODISABLE) != -1); + ATF_CHECK(n > 0); + ATF_REQUIRE(munmap(cover, size * sizeof(unsigned long)) != -1); + close(fd); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, kcov1); + + return atf_no_error(); +} +