Home | History | Annotate | Line # | Download | only in kern
      1 /*	$NetBSD: subr_kcov.c,v 1.18 2022/10/26 23:24:21 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2019-2020 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Siddharth Muralee.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 
     34 #include <sys/module.h>
     35 #include <sys/param.h>
     36 #include <sys/systm.h>
     37 #include <sys/kernel.h>
     38 
     39 #include <sys/conf.h>
     40 #include <sys/condvar.h>
     41 #include <sys/file.h>
     42 #include <sys/filedesc.h>
     43 #include <sys/kmem.h>
     44 #include <sys/mman.h>
     45 #include <sys/mutex.h>
     46 #include <sys/queue.h>
     47 
     48 #include <uvm/uvm_extern.h>
     49 #include <sys/kcov.h>
     50 
     51 #define KCOV_BUF_MAX_ENTRIES	(256 << 10)
     52 
     53 #define KCOV_CMP_CONST		1
     54 #define KCOV_CMP_SIZE(x)	((x) << 1)
     55 
     56 static dev_type_open(kcov_open);
     57 
     58 const struct cdevsw kcov_cdevsw = {
     59 	.d_open = kcov_open,
     60 	.d_close = noclose,
     61 	.d_read = noread,
     62 	.d_write = nowrite,
     63 	.d_ioctl = noioctl,
     64 	.d_stop = nostop,
     65 	.d_tty = notty,
     66 	.d_poll = nopoll,
     67 	.d_mmap = nommap,
     68 	.d_kqfilter = nokqfilter,
     69 	.d_discard = nodiscard,
     70 	.d_flag = D_OTHER | D_MPSAFE
     71 };
     72 
     73 static int kcov_fops_ioctl(file_t *, u_long, void *);
     74 static int kcov_fops_close(file_t *);
     75 static int kcov_fops_mmap(file_t *, off_t *, size_t, int, int *, int *,
     76     struct uvm_object **, int *);
     77 
     78 const struct fileops kcov_fileops = {
     79 	.fo_read = fbadop_read,
     80 	.fo_write = fbadop_write,
     81 	.fo_ioctl = kcov_fops_ioctl,
     82 	.fo_fcntl = fnullop_fcntl,
     83 	.fo_poll = fnullop_poll,
     84 	.fo_stat = fbadop_stat,
     85 	.fo_close = kcov_fops_close,
     86 	.fo_kqfilter = fnullop_kqfilter,
     87 	.fo_restart = fnullop_restart,
     88 	.fo_mmap = kcov_fops_mmap,
     89 };
     90 
     91 /*
     92  * The KCOV descriptors (KD) are allocated during open(), and are associated
     93  * with a file descriptor.
     94  *
     95  * An LWP can 'enable' a KD. When this happens, this LWP becomes the owner of
     96  * the KD, and no LWP can 'disable' this KD except the owner.
     97  *
     98  * A KD is freed when its file descriptor is closed _iff_ the KD is not active
     99  * on an LWP. If it is, we ask the LWP to free it when it exits.
    100  *
    101  * The buffers mmapped are in a dedicated uobj, therefore there is no risk
    102  * that the kernel frees a buffer still mmapped in a process: the uobj
    103  * refcount will be non-zero, so the backing is not freed until an munmap
    104  * occurs on said process.
    105  */
    106 
    107 typedef struct kcov_desc {
    108 	/* Local only */
    109 	kmutex_t lock;
    110 	bool lwpfree;
    111 	bool silenced;
    112 
    113 	/* Pointer to the end of the structure, if any */
    114 	struct kcov_desc *remote;
    115 
    116 	/* Can be remote */
    117 	kcov_int_t *buf;
    118 	struct uvm_object *uobj;
    119 	size_t bufnent;
    120 	size_t bufsize;
    121 	int mode;
    122 	bool enabled;
    123 } kcov_t;
    124 
    125 /* -------------------------------------------------------------------------- */
    126 
    127 static void
    128 kcov_lock(kcov_t *kd)
    129 {
    130 
    131 	mutex_enter(&kd->lock);
    132 }
    133 
    134 static void
    135 kcov_unlock(kcov_t *kd)
    136 {
    137 
    138 	mutex_exit(&kd->lock);
    139 }
    140 
    141 static bool
    142 kcov_mode_is_valid(int mode)
    143 {
    144 	switch (mode) {
    145 	case KCOV_MODE_NONE:
    146 	case KCOV_MODE_TRACE_PC:
    147 	case KCOV_MODE_TRACE_CMP:
    148 		return true;
    149 	default:
    150 		return false;
    151 	}
    152 }
    153 
    154 /* -------------------------------------------------------------------------- */
    155 
    156 static void
    157 kcov_free(kcov_t *kd)
    158 {
    159 
    160 	KASSERT(kd != NULL);
    161 	if (kd->buf != NULL) {
    162 		uvm_deallocate(kernel_map, (vaddr_t)kd->buf, kd->bufsize);
    163 	}
    164 	mutex_destroy(&kd->lock);
    165 	kmem_free(kd, sizeof(*kd));
    166 }
    167 
    168 void
    169 kcov_lwp_free(struct lwp *l)
    170 {
    171 	kcov_t *kd = (kcov_t *)l->l_kcov;
    172 
    173 	if (kd == NULL) {
    174 		return;
    175 	}
    176 	kcov_lock(kd);
    177 	kd->enabled = false;
    178 	kcov_unlock(kd);
    179 	if (kd->lwpfree) {
    180 		kcov_free(kd);
    181 	}
    182 }
    183 
    184 static int
    185 kcov_allocbuf(kcov_t *kd, uint64_t nent)
    186 {
    187 	size_t size;
    188 	int error;
    189 
    190 	if (nent < 2 || nent > KCOV_BUF_MAX_ENTRIES)
    191 		return EINVAL;
    192 	if (kd->buf != NULL)
    193 		return EEXIST;
    194 
    195 	size = roundup(nent * KCOV_ENTRY_SIZE, PAGE_SIZE);
    196 	kd->bufnent = nent - 1;
    197 	kd->bufsize = size;
    198 	kd->uobj = uao_create(kd->bufsize, 0);
    199 
    200 	/* Map the uobj into the kernel address space, as wired. */
    201 	kd->buf = NULL;
    202 	error = uvm_map(kernel_map, (vaddr_t *)&kd->buf, kd->bufsize, kd->uobj,
    203 	    0, 0, UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW, UVM_INH_SHARE,
    204 	    UVM_ADV_RANDOM, 0));
    205 	if (error) {
    206 		uao_detach(kd->uobj);
    207 		return error;
    208 	}
    209 	error = uvm_map_pageable(kernel_map, (vaddr_t)kd->buf,
    210 	    (vaddr_t)kd->buf + size, false, 0);
    211 	if (error) {
    212 		uvm_deallocate(kernel_map, (vaddr_t)kd->buf, size);
    213 		return error;
    214 	}
    215 
    216 	return 0;
    217 }
    218 
    219 /* -------------------------------------------------------------------------- */
    220 
    221 typedef struct kcov_remote {
    222 	LIST_ENTRY(kcov_remote) list;
    223 	uint64_t subsystem;
    224 	uint64_t id;
    225 	u_int refcount;
    226 	kcov_t kd;
    227 } kcov_remote_t;
    228 
    229 typedef LIST_HEAD(, kcov_remote) kcov_remote_list_t;
    230 
    231 static kcov_remote_list_t kcov_remote_list;
    232 
    233 static kcov_remote_t *
    234 kcov_remote_find(uint64_t subsystem, uint64_t id)
    235 {
    236 	kcov_remote_t *kr;
    237 
    238 	LIST_FOREACH(kr, &kcov_remote_list, list) {
    239 		if (kr->subsystem == subsystem && kr->id == id)
    240 			return kr;
    241 	}
    242 
    243 	return NULL;
    244 }
    245 
    246 void
    247 kcov_remote_register(uint64_t subsystem, uint64_t id)
    248 {
    249 	kcov_remote_t *kr;
    250 	kcov_t *kd;
    251 	int error;
    252 
    253 	if (kcov_remote_find(subsystem, id) != NULL) {
    254 		panic("%s: kr already exists", __func__);
    255 	}
    256 
    257 	kr = kmem_zalloc(sizeof(*kr), KM_SLEEP);
    258 	kr->subsystem = subsystem;
    259 	kr->id = id;
    260 	kr->refcount = 0;
    261 	kd = &kr->kd;
    262 
    263 	mutex_init(&kd->lock, MUTEX_DEFAULT, IPL_NONE);
    264 	error = kcov_allocbuf(kd, KCOV_BUF_MAX_ENTRIES);
    265 	if (error != 0)
    266 		panic("%s: failed to allocate buffer", __func__);
    267 
    268 	LIST_INSERT_HEAD(&kcov_remote_list, kr, list);
    269 }
    270 
    271 void
    272 kcov_remote_enter(uint64_t subsystem, uint64_t id)
    273 {
    274 	struct lwp *l = curlwp;
    275 	kcov_remote_t *kr;
    276 	kcov_t *kd;
    277 	u_int refs __diagused;
    278 
    279 	kr = kcov_remote_find(subsystem, id);
    280 	if (__predict_false(kr == NULL)) {
    281 		panic("%s: unable to find kr", __func__);
    282 	}
    283 
    284 	refs = atomic_inc_uint_nv(&kr->refcount);
    285 	KASSERT(refs == 1);
    286 
    287 	KASSERT(l->l_kcov == NULL);
    288 	kd = &kr->kd;
    289 	if (atomic_load_relaxed(&kd->enabled)) {
    290 		l->l_kcov = kd;
    291 	}
    292 }
    293 
    294 void
    295 kcov_remote_leave(uint64_t subsystem, uint64_t id)
    296 {
    297 	struct lwp *l = curlwp;
    298 	kcov_remote_t *kr;
    299 	u_int refs __diagused;
    300 
    301 	kr = kcov_remote_find(subsystem, id);
    302 	if (__predict_false(kr == NULL)) {
    303 		panic("%s: unable to find kr", __func__);
    304 	}
    305 
    306 	refs = atomic_dec_uint_nv(&kr->refcount);
    307 	KASSERT(refs == 0);
    308 
    309 	l->l_kcov = NULL;
    310 }
    311 
    312 static int
    313 kcov_remote_enable(kcov_t *kd, int mode)
    314 {
    315 	kcov_lock(kd);
    316 	if (kd->enabled) {
    317 		kcov_unlock(kd);
    318 		return EBUSY;
    319 	}
    320 	kd->mode = mode;
    321 	atomic_store_relaxed(&kd->enabled, true);
    322 	kcov_unlock(kd);
    323 
    324 	return 0;
    325 }
    326 
    327 static int
    328 kcov_remote_disable(kcov_t *kd)
    329 {
    330 	kcov_lock(kd);
    331 	if (!kd->enabled) {
    332 		kcov_unlock(kd);
    333 		return ENOENT;
    334 	}
    335 	atomic_store_relaxed(&kd->enabled, false);
    336 	kcov_unlock(kd);
    337 
    338 	return 0;
    339 }
    340 
    341 static int
    342 kcov_remote_attach(kcov_t *kd, struct kcov_ioc_remote_attach *args)
    343 {
    344 	kcov_remote_t *kr;
    345 
    346 	if (kd->enabled)
    347 		return EEXIST;
    348 
    349 	kr = kcov_remote_find(args->subsystem, args->id);
    350 	if (kr == NULL)
    351 		return ENOENT;
    352 	kd->remote = &kr->kd;
    353 
    354 	return 0;
    355 }
    356 
    357 static int
    358 kcov_remote_detach(kcov_t *kd)
    359 {
    360 	if (kd->enabled)
    361 		return EEXIST;
    362 	if (kd->remote == NULL)
    363 		return ENOENT;
    364 	(void)kcov_remote_disable(kd->remote);
    365 	kd->remote = NULL;
    366 	return 0;
    367 }
    368 
    369 /* -------------------------------------------------------------------------- */
    370 
    371 static int
    372 kcov_setbufsize(kcov_t *kd, uint64_t *args)
    373 {
    374 	if (kd->remote != NULL)
    375 		return 0; /* buffer allocated remotely */
    376 	if (kd->enabled)
    377 		return EBUSY;
    378 	return kcov_allocbuf(kd, *((uint64_t *)args));
    379 }
    380 
    381 static int
    382 kcov_enable(kcov_t *kd, uint64_t *args)
    383 {
    384 	struct lwp *l = curlwp;
    385 	int mode;
    386 
    387 	mode = *((int *)args);
    388 	if (!kcov_mode_is_valid(mode))
    389 		return EINVAL;
    390 
    391 	if (kd->remote != NULL)
    392 		return kcov_remote_enable(kd->remote, mode);
    393 
    394 	if (kd->enabled)
    395 		return EBUSY;
    396 	if (l->l_kcov != NULL)
    397 		return EBUSY;
    398 	if (kd->buf == NULL)
    399 		return ENOBUFS;
    400 
    401 	l->l_kcov = kd;
    402 	kd->mode = mode;
    403 	kd->enabled = true;
    404 	return 0;
    405 }
    406 
    407 static int
    408 kcov_disable(kcov_t *kd)
    409 {
    410 	struct lwp *l = curlwp;
    411 
    412 	if (kd->remote != NULL)
    413 		return kcov_remote_disable(kd->remote);
    414 
    415 	if (!kd->enabled)
    416 		return ENOENT;
    417 	if (l->l_kcov != kd)
    418 		return ENOENT;
    419 
    420 	l->l_kcov = NULL;
    421 	kd->enabled = false;
    422 	return 0;
    423 }
    424 
    425 /* -------------------------------------------------------------------------- */
    426 
    427 void
    428 kcov_silence_enter(void)
    429 {
    430 	kcov_t *kd = curlwp->l_kcov;
    431 
    432 	if (kd != NULL)
    433 		kd->silenced = true;
    434 }
    435 
    436 void
    437 kcov_silence_leave(void)
    438 {
    439 	kcov_t *kd = curlwp->l_kcov;
    440 
    441 	if (kd != NULL)
    442 		kd->silenced = false;
    443 }
    444 
    445 /* -------------------------------------------------------------------------- */
    446 
    447 static int
    448 kcov_open(dev_t dev, int flag, int mode, struct lwp *l)
    449 {
    450 	struct file *fp;
    451 	int error, fd;
    452 	kcov_t *kd;
    453 
    454 	error = fd_allocfile(&fp, &fd);
    455 	if (error)
    456 		return error;
    457 
    458 	kd = kmem_zalloc(sizeof(*kd), KM_SLEEP);
    459 	mutex_init(&kd->lock, MUTEX_DEFAULT, IPL_NONE);
    460 
    461 	return fd_clone(fp, fd, flag, &kcov_fileops, kd);
    462 }
    463 
    464 static int
    465 kcov_fops_close(file_t *fp)
    466 {
    467 	kcov_t *kd = fp->f_data;
    468 
    469 	kcov_lock(kd);
    470 	if (kd->remote != NULL)
    471 		(void)kcov_remote_disable(kd->remote);
    472 	if (kd->enabled) {
    473 		kd->lwpfree = true;
    474 		kcov_unlock(kd);
    475 	} else {
    476 		kcov_unlock(kd);
    477 		kcov_free(kd);
    478 	}
    479 	fp->f_data = NULL;
    480 
    481    	return 0;
    482 }
    483 
    484 static int
    485 kcov_fops_ioctl(file_t *fp, u_long cmd, void *addr)
    486 {
    487 	kcov_t *kd;
    488 	int error;
    489 
    490 	kd = fp->f_data;
    491 	if (kd == NULL)
    492 		return ENXIO;
    493 	kcov_lock(kd);
    494 
    495 	switch (cmd) {
    496 	case KCOV_IOC_SETBUFSIZE:
    497 		error = kcov_setbufsize(kd, addr);
    498 		break;
    499 	case KCOV_IOC_ENABLE:
    500 		error = kcov_enable(kd, addr);
    501 		break;
    502 	case KCOV_IOC_DISABLE:
    503 		error = kcov_disable(kd);
    504 		break;
    505 	case KCOV_IOC_REMOTE_ATTACH:
    506 		error = kcov_remote_attach(kd, addr);
    507 		break;
    508 	case KCOV_IOC_REMOTE_DETACH:
    509 		error = kcov_remote_detach(kd);
    510 		break;
    511 	default:
    512 		error = EINVAL;
    513 	}
    514 
    515 	kcov_unlock(kd);
    516 	return error;
    517 }
    518 
    519 static int
    520 kcov_fops_mmap(file_t *fp, off_t *offp, size_t size, int prot, int *flagsp,
    521     int *advicep, struct uvm_object **uobjp, int *maxprotp)
    522 {
    523 	off_t off = *offp;
    524 	kcov_t *kd, *kdbuf;
    525 	int error = 0;
    526 
    527 	KASSERT(size > 0);
    528 
    529 	if (prot & PROT_EXEC)
    530 		return EACCES;
    531 	if (off < 0)
    532 		return EINVAL;
    533 	if (size > KCOV_BUF_MAX_ENTRIES * KCOV_ENTRY_SIZE)
    534 		return EINVAL;
    535 	if (off > KCOV_BUF_MAX_ENTRIES * KCOV_ENTRY_SIZE)
    536 		return EINVAL;
    537 
    538 	kd = fp->f_data;
    539 	if (kd == NULL)
    540 		return ENXIO;
    541 	kcov_lock(kd);
    542 
    543 	if (kd->remote != NULL)
    544 		kdbuf = kd->remote;
    545 	else
    546 		kdbuf = kd;
    547 
    548 	if ((size + off) > kdbuf->bufsize) {
    549 		error = ENOMEM;
    550 		goto out;
    551 	}
    552 
    553 	uao_reference(kdbuf->uobj);
    554 
    555 	*uobjp = kdbuf->uobj;
    556 	*maxprotp = prot;
    557 	*advicep = UVM_ADV_RANDOM;
    558 
    559 out:
    560 	kcov_unlock(kd);
    561 	return error;
    562 }
    563 
    564 /* -------------------------------------------------------------------------- */
    565 
    566 /*
    567  * Constraints on the functions here: they must be marked with __nomsan, and
    568  * must not make any external call.
    569  */
    570 
    571 static inline bool __nomsan
    572 in_interrupt(void)
    573 {
    574 	return curcpu()->ci_idepth >= 0;
    575 }
    576 
    577 void __sanitizer_cov_trace_pc(void);
    578 
    579 void __nomsan
    580 __sanitizer_cov_trace_pc(void)
    581 {
    582 	uint64_t idx;
    583 	kcov_t *kd;
    584 
    585 	if (__predict_false(cold)) {
    586 		/* Do not trace during boot. */
    587 		return;
    588 	}
    589 
    590 	if (in_interrupt()) {
    591 		/* Do not trace in interrupts. */
    592 		return;
    593 	}
    594 
    595 	kd = curlwp->l_kcov;
    596 	if (__predict_true(kd == NULL)) {
    597 		/* Not traced. */
    598 		return;
    599 	}
    600 
    601 	if (!kd->enabled) {
    602 		/* Tracing not enabled */
    603 		return;
    604 	}
    605 
    606 	if (__predict_false(kd->silenced)) {
    607 		/* Silenced. */
    608 		return;
    609 	}
    610 
    611 	if (kd->mode != KCOV_MODE_TRACE_PC) {
    612 		/* PC tracing mode not enabled */
    613 		return;
    614 	}
    615 	KASSERT(kd->remote == NULL);
    616 
    617 	idx = kd->buf[0];
    618 	if (idx < kd->bufnent) {
    619 		kd->buf[idx+1] =
    620 		    (intptr_t)__builtin_return_address(0);
    621 		kd->buf[0] = idx + 1;
    622 	}
    623 }
    624 
    625 static void __nomsan
    626 trace_cmp(uint64_t type, uint64_t arg1, uint64_t arg2, intptr_t pc)
    627 {
    628 	uint64_t idx;
    629 	kcov_t *kd;
    630 
    631 	if (__predict_false(cold)) {
    632 		/* Do not trace during boot. */
    633 		return;
    634 	}
    635 
    636 	if (in_interrupt()) {
    637 		/* Do not trace in interrupts. */
    638 		return;
    639 	}
    640 
    641 	kd = curlwp->l_kcov;
    642 	if (__predict_true(kd == NULL)) {
    643 		/* Not traced. */
    644 		return;
    645 	}
    646 
    647 	if (!kd->enabled) {
    648 		/* Tracing not enabled */
    649 		return;
    650 	}
    651 
    652 	if (__predict_false(kd->silenced)) {
    653 		/* Silenced. */
    654 		return;
    655 	}
    656 
    657 	if (kd->mode != KCOV_MODE_TRACE_CMP) {
    658 		/* CMP tracing mode not enabled */
    659 		return;
    660 	}
    661 	KASSERT(kd->remote == NULL);
    662 
    663 	idx = kd->buf[0];
    664 	if ((idx * 4 + 4) <= kd->bufnent) {
    665 		kd->buf[idx * 4 + 1] = type;
    666 		kd->buf[idx * 4 + 2] = arg1;
    667 		kd->buf[idx * 4 + 3] = arg2;
    668 		kd->buf[idx * 4 + 4] = pc;
    669 		kd->buf[0] = idx + 1;
    670 	}
    671 }
    672 
    673 void __sanitizer_cov_trace_cmp1(uint8_t arg1, uint8_t arg2);
    674 
    675 void __nomsan
    676 __sanitizer_cov_trace_cmp1(uint8_t arg1, uint8_t arg2)
    677 {
    678 
    679 	trace_cmp(KCOV_CMP_SIZE(0), arg1, arg2,
    680 	    (intptr_t)__builtin_return_address(0));
    681 }
    682 
    683 void __sanitizer_cov_trace_cmp2(uint16_t arg1, uint16_t arg2);
    684 
    685 void __nomsan
    686 __sanitizer_cov_trace_cmp2(uint16_t arg1, uint16_t arg2)
    687 {
    688 
    689 	trace_cmp(KCOV_CMP_SIZE(1), arg1, arg2,
    690 	    (intptr_t)__builtin_return_address(0));
    691 }
    692 
    693 void __sanitizer_cov_trace_cmp4(uint32_t arg1, uint32_t arg2);
    694 
    695 void __nomsan
    696 __sanitizer_cov_trace_cmp4(uint32_t arg1, uint32_t arg2)
    697 {
    698 
    699 	trace_cmp(KCOV_CMP_SIZE(2), arg1, arg2,
    700 	    (intptr_t)__builtin_return_address(0));
    701 }
    702 
    703 void __sanitizer_cov_trace_cmp8(uint64_t arg1, uint64_t arg2);
    704 
    705 void __nomsan
    706 __sanitizer_cov_trace_cmp8(uint64_t arg1, uint64_t arg2)
    707 {
    708 
    709 	trace_cmp(KCOV_CMP_SIZE(3), arg1, arg2,
    710 	    (intptr_t)__builtin_return_address(0));
    711 }
    712 
    713 void __sanitizer_cov_trace_const_cmp1(uint8_t arg1, uint8_t arg2);
    714 
    715 void __nomsan
    716 __sanitizer_cov_trace_const_cmp1(uint8_t arg1, uint8_t arg2)
    717 {
    718 
    719 	trace_cmp(KCOV_CMP_SIZE(0) | KCOV_CMP_CONST, arg1, arg2,
    720 	    (intptr_t)__builtin_return_address(0));
    721 }
    722 
    723 void __sanitizer_cov_trace_const_cmp2(uint16_t arg1, uint16_t arg2);
    724 
    725 void __nomsan
    726 __sanitizer_cov_trace_const_cmp2(uint16_t arg1, uint16_t arg2)
    727 {
    728 
    729 	trace_cmp(KCOV_CMP_SIZE(1) | KCOV_CMP_CONST, arg1, arg2,
    730 	    (intptr_t)__builtin_return_address(0));
    731 }
    732 
    733 void __sanitizer_cov_trace_const_cmp4(uint32_t arg1, uint32_t arg2);
    734 
    735 void __nomsan
    736 __sanitizer_cov_trace_const_cmp4(uint32_t arg1, uint32_t arg2)
    737 {
    738 
    739 	trace_cmp(KCOV_CMP_SIZE(2) | KCOV_CMP_CONST, arg1, arg2,
    740 	    (intptr_t)__builtin_return_address(0));
    741 }
    742 
    743 void __sanitizer_cov_trace_const_cmp8(uint64_t arg1, uint64_t arg2);
    744 
    745 void __nomsan
    746 __sanitizer_cov_trace_const_cmp8(uint64_t arg1, uint64_t arg2)
    747 {
    748 
    749 	trace_cmp(KCOV_CMP_SIZE(3) | KCOV_CMP_CONST, arg1, arg2,
    750 	    (intptr_t)__builtin_return_address(0));
    751 }
    752 
    753 void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases);
    754 
    755 void __nomsan
    756 __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases)
    757 {
    758 	uint64_t i, nbits, ncases, type;
    759 	intptr_t pc;
    760 
    761 	pc = (intptr_t)__builtin_return_address(0);
    762 	ncases = cases[0];
    763 	nbits = cases[1];
    764 
    765 	switch (nbits) {
    766 	case 8:
    767 		type = KCOV_CMP_SIZE(0);
    768 		break;
    769 	case 16:
    770 		type = KCOV_CMP_SIZE(1);
    771 		break;
    772 	case 32:
    773 		type = KCOV_CMP_SIZE(2);
    774 		break;
    775 	case 64:
    776 		type = KCOV_CMP_SIZE(3);
    777 		break;
    778 	default:
    779 		return;
    780 	}
    781 	type |= KCOV_CMP_CONST;
    782 
    783 	for (i = 0; i < ncases; i++)
    784 		trace_cmp(type, cases[i + 2], val, pc);
    785 }
    786 
    787 /* -------------------------------------------------------------------------- */
    788 
    789 MODULE(MODULE_CLASS_MISC, kcov, NULL);
    790 
    791 static int
    792 kcov_modcmd(modcmd_t cmd, void *arg)
    793 {
    794 
    795    	switch (cmd) {
    796 	case MODULE_CMD_INIT:
    797 		return 0;
    798 	case MODULE_CMD_FINI:
    799 		return EINVAL;
    800 	default:
    801 		return ENOTTY;
    802 	}
    803 }
    804