---
name: "kcov"
section: "4"
platform: "openbsd"
package: "man"
version: "8.0-current-20261101"
release: "OpenBSD 8.0-current (2026-11-01)"
platforms: ["freebsd", "openbsd"]
url: "https://new.carta.tech/kcov/4"
---

# kcov(4)

kernel code coverage tracing

## NAME

**kcov** – kernel code coverage tracing

## SYNOPSIS

**pseudo-device** **kcov**

**#include \<sys/kcov.h\>**

## DESCRIPTION

The **kcov** driver implements collection of code coverage inside the kernel. It can be enabled on a per thread basis from user space, allowing the kernel program counter to be collected during syscalls triggered by the same thread. The collected coverage can be accessed by mapping the device using [mmap(2)](/mmap/2.md).

By default, **kcov** is not enabled but instead requires the following line to be present in the kernel configuration:

```
pseudo-device kcov 1
```

The following [ioctl(2)](/ioctl/2.md) calls are provided:

- KIOSETBUFSIZE *unsigned*, *long*, *\*nentries*

  Allocate a coverage buffer with a capacity of *nentries*. The buffer can be accessed using [mmap(2)](/mmap/2.md), whereas the returned pointer must be interpreted as an array of *unsigned* *long* entries. The first entry contains the number of entries in the array, excluding the first entry.

- KIOENABLE *int*, *\*mode*

  Enable code coverage tracing for the current thread or any remote subsystem attached using KIOREMOTEATTACH. The *mode* must be one of the following:

  - KCOV\_MODE\_TRACE\_PC

    Trace the kernel program counter.

  - KCOV\_MODE\_TRACE\_CMP

    Trace comparison instructions and switch statements. For switch statements, the number of traced comparison instructions is equal to the number of switch cases. Each traced comparison instruction is represented by 4 entries in the coverage buffer:

    1. A mask where the least significant bit is set if one of the comparison operands is a compile-time constant, which is always true for switch statements. The remaining bits represents the log2 size of the operands, ranging from 0 to 3.

    2. First comparison operand. For switch statements, this operand corresponds to the case value.

    3. Second comparison operand. For switch statements, this operand corresponds to the value passed to switch.

    4. Kernel program counter where the comparison instruction took place.

       In this mode, the first entry in the coverage buffer reflects the number of traced comparison instructions. Thus, the effective number of entries in the coverage buffer is given by multiplying the first entry by 4.

- KIODISABLE *void*

  Disable code coverage tracing for the current thread.

- KIOREMOTEATTACH *struct*, *kio\_remote\_attach*, *\*remote*

  Attach collection of remote coverage from other kernel threads, identified by a subsystem. Collection of remote coverage is mutually exclusive with coverage collection of the current thread. The *remote* argument is a pointer to the following structure:

  ```
  struct kio_remote_attach {
  	int	subsystem;
  	int	id;
  };
  ```

  The *subsystem* field must be one of the following:

  - KCOV\_REMOTE\_COMMON

    Collect coverage from tasks and timeouts scheduled by the current process, see task\_add(9) and [timeout(9)](/timeout/9.md). The *id* field is ignored.

## FILES

- */dev/kcov*

  Default device node.

## EXAMPLES

In the following example, the [read(2)](/read/2.md) syscall is traced and the coverage displayed, which in turn can be passed to [addr2line(1)](/addr2line/1.md) in order to translate the kernel program counter into the file name and line number it corresponds to.

```
#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, mode;
	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");
	mode = KCOV_MODE_TRACE_PC;
	if (ioctl(fd, KIOENABLE, &mode) == -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\n", (void *)cover[i + 1]);
	if (munmap(cover, size * sizeof(unsigned long)) == -1)
		err(1, "munmap");
	close(fd);
	return 0;
}
```

## SEE ALSO

[files.conf(5)](/files.conf/5.md), kcov\_remote\_register(9)

## HISTORY

The **kcov** driver first appeared in OpenBSD 6.4.

## AUTHORS

The **kcov** driver was written by Anton Lindqvist ⟨*anton@openbsd.org*⟩.

## CAVEATS

The **kcov** driver is limited to architectures using [clang(1)](/clang/1.md) as their default compiler.
