Linux Documentation
 help / color / mirror / Atom feed
From: Sasha Levin <sashal@kernel.org>
To: linux-kernel@vger.kernel.org
Cc: Alexander Potapenko <glider@google.com>,
	Andrey Konovalov <andreyknvl@gmail.com>,
	Bill Wendling <morbo@google.com>, Chuck Wolber <chuck@wolber.net>,
	Dmitry Vyukov <dvyukov@google.com>,
	Jonathan Corbet <corbet@lwn.net>,
	Justin Stitt <justinstitt@google.com>,
	kasan-dev@googlegroups.com, linux-doc@vger.kernel.org,
	llvm@lists.linux.dev, Marco Elver <elver@google.com>,
	Masami Hiramatsu <mhiramat@kernel.org>,
	Nathan Chancellor <nathan@kernel.org>,
	Nick Desaulniers <ndesaulniers@google.com>,
	Peter Oberparleiter <oberpar@linux.ibm.com>,
	Peter Zijlstra <peterz@infradead.org>,
	Randy Dunlap <rdunlap@infradead.org>,
	Shuah Khan <skhan@linuxfoundation.org>,
	Thomas Gleixner <tglx@kernel.org>,
	workflows@vger.kernel.org
Subject: [RFC PATCH 20/20] Documentation: dev-tools: document the common code coverage interface
Date: Wed, 28 Oct 2026 07:59:44 -0400	[thread overview]
Message-ID: <20261028120034.871983-21-sashal@kernel.org> (raw)
In-Reply-To: <20261028120034.871983-1-sashal@kernel.org>

Describe the code coverage implementations and what they share: the
Kconfig options, the COVERAGE_PROFILE annotations, the
/sys/kernel/debug/coverage/ interface, MC/DC measurement, and how they
deal with noinstr code. Point to it from the gcov and KCOV
documentation, and document gcov's MC/DC support.

Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 Documentation/dev-tools/coverage.rst | 158 +++++++++++++++++++++++++++
 Documentation/dev-tools/gcov.rst     |  28 +++++
 Documentation/dev-tools/index.rst    |   1 +
 Documentation/dev-tools/kcov.rst     |   3 +
 MAINTAINERS                          |   1 +
 5 files changed, 191 insertions(+)
 create mode 100644 Documentation/dev-tools/coverage.rst

diff --git a/Documentation/dev-tools/coverage.rst b/Documentation/dev-tools/coverage.rst
new file mode 100644
index 0000000000000..547863b2afd6d
--- /dev/null
+++ b/Documentation/dev-tools/coverage.rst
@@ -0,0 +1,158 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=============
+Code coverage
+=============
+
+The kernel can be instrumented to find out which parts of it get executed.
+This serves two different purposes:
+
+* Measuring code coverage, e.g. to assess and improve a test suite, or to
+  show the structural coverage required by safety standards. This is done by
+  one of the code coverage measurement implementations described below.
+
+* Guiding fuzzers. This is done by KCOV, which collects coverage per task;
+  see Documentation/dev-tools/kcov.rst.
+
+All of them are configured in the "Kernel hacking -> Kernel Testing and
+Coverage -> Code coverage" menu, live in ``kernel/coverage/``, and share the
+``/sys/kernel/debug/coverage/`` debugfs directory.
+
+
+Code coverage measurement
+=========================
+
+The implementation is selected by the "Code coverage measurement" choice:
+
+============================  ==============  ================================
+Option                        Compilers       Data
+============================  ==============  ================================
+``CONFIG_GCOV_KERNEL``        GCC, Clang      gcov ``.gcda`` files, see
+                                              Documentation/dev-tools/gcov.rst
+``CONFIG_LLVM_COV_KERNEL``    Clang 19 and    LLVM raw profile of the kernel
+                              later           image (``.profraw``)
+============================  ==============  ================================
+
+The instrumentation and the format of the data are defined by the toolchain,
+so only one implementation can be used at a time. Both only instrument C
+code.
+
+Clang's source-based code coverage (``CONFIG_LLVM_COV_KERNEL``) instruments
+the code in the compiler front end. Its data therefore maps back to the source
+code exactly, regardless of the optimizations applied, and it can show the
+coverage of every condition of a decision. It only instruments code built into
+the kernel image. gcov also supports modules.
+
+
+Selecting the code to instrument
+--------------------------------
+
+``CONFIG_COVERAGE_PROFILE_ALL`` instruments the entire kernel. On architectures
+that don't support it, or to instrument only parts of the kernel, add a line
+like the following to the respective Makefile.
+
+For a single file (e.g. main.o)::
+
+	COVERAGE_PROFILE_main.o := y
+
+For all files in one directory::
+
+	COVERAGE_PROFILE := y
+
+To exclude files from being instrumented even when
+``CONFIG_COVERAGE_PROFILE_ALL`` is enabled, use::
+
+	COVERAGE_PROFILE_main.o := n
+
+and::
+
+	COVERAGE_PROFILE := n
+
+The per-file setting takes precedence over the per-directory one, which takes
+precedence over ``CONFIG_COVERAGE_PROFILE_ALL``.
+
+Only exclude code that can't work when instrumented, for example because it
+runs before the kernel is relocated or is copied elsewhere. Code that must not
+be instrumented for correctness reasons, such as the entry code, is annotated
+``noinstr`` instead; see `noinstr`_.
+
+
+Interface
+---------
+
+``/sys/kernel/debug/coverage/`` contains:
+
+``backend``
+	The name of the selected implementation, ``gcov`` or ``llvm``, followed by
+	``mcdc`` when MC/DC is measured.
+
+``reset``
+	Writing to this file resets all coverage data of the selected
+	implementation. It does not affect KCOV.
+
+``gcov``
+	A symlink to ``/sys/kernel/debug/gcov``, where gcov keeps its data (see
+	Documentation/dev-tools/gcov.rst).
+
+``llvm/profraw``
+	The raw profile of the kernel image, for Clang's source-based code
+	coverage.
+
+``kcov``
+	A symlink to ``/sys/kernel/debug/kcov`` (see
+	Documentation/dev-tools/kcov.rst).
+
+The instrumented code updates the coverage data without synchronizing with
+readers, so reading the data while other CPUs execute instrumented code
+doesn't give an atomic snapshot, and the same applies to a reset.
+
+With Clang's source-based code coverage, convert the raw profile and create a
+report with the ``llvm-profdata`` and ``llvm-cov`` tools of the LLVM version
+that built the kernel, since the raw profile format changes between releases::
+
+	# cp /sys/kernel/debug/coverage/llvm/profraw vmlinux.profraw
+	$ llvm-profdata merge vmlinux.profraw -o vmlinux.profdata
+	$ llvm-cov report -instr-profile=vmlinux.profdata vmlinux
+	$ llvm-cov show -instr-profile=vmlinux.profdata vmlinux kernel/fork.c
+
+
+MC/DC
+-----
+
+Modified condition/decision coverage (MC/DC) verifies that each condition of a
+boolean decision has been shown to independently affect the outcome of the
+decision. It is required by safety standards such as DO-178C (avionics) and
+ISO 26262 (automotive). Enable it with ``CONFIG_COVERAGE_MCDC``:
+
+* With Clang's source-based code coverage, decisions with more than
+  ``CONFIG_LLVM_COV_MCDC_MAX_CONDITIONS`` conditions are not measured. Show
+  the results with ``llvm-cov show -show-mcdc`` and
+  ``llvm-cov report -show-mcdc-summary``.
+
+* With gcov, GCC 14 or later is required, and decisions with more than 64
+  conditions are not measured. Show the results with ``gcov --conditions``.
+
+The compiler warns about every decision it doesn't instrument.
+
+
+noinstr
+=======
+
+Code annotated ``noinstr`` must not be instrumented; this includes the code
+running on kernel entry and exit, and in NMI context. Outside of
+``instrumentation_begin()``/``instrumentation_end()`` sections, ``noinstr``
+functions may only call other ``noinstr`` functions and ``__always_inline``
+functions.
+
+The code coverage measurement implementations insert their instrumentation
+before functions get inlined, which would carry the instrumentation of an
+``__always_inline`` function into the ``noinstr`` code it is inlined into. To
+avoid that, ``__always_inline`` functions are not instrumented when one of them
+is enabled, and as a consequence they don't show up in the coverage data.
+
+With ``CONFIG_NOINSTR_VALIDATION``, objtool reports coverage counters that get
+updated by ``noinstr`` code outside of such sections.
+
+KCOV instruments the code after inlining and honours ``noinstr`` through the
+``no_sanitize_coverage`` attribute with Clang and GCC 12 or later; with older
+GCC, objtool removes its calls from ``noinstr`` code.
diff --git a/Documentation/dev-tools/gcov.rst b/Documentation/dev-tools/gcov.rst
index b6910c3fc00dd..d2950070f3ca4 100644
--- a/Documentation/dev-tools/gcov.rst
+++ b/Documentation/dev-tools/gcov.rst
@@ -22,6 +22,9 @@ Possible uses:
 * minimizing kernel configurations (do I need this option if the
   associated code is never run?)
 
+See Documentation/dev-tools/coverage.rst for the options and interfaces shared
+with the other code coverage implementations.
+
 .. _gcov: https://gcc.gnu.org/onlinedocs/gcc/Gcov.html
 .. _lcov: https://github.com/linux-test-project/lcov
 
@@ -180,6 +183,31 @@ b) gcov is run on the BUILD machine
       [user@build] gcov -o /tmp/coverage/tmp/out/init main.c
 
 
+MC/DC Coverage
+--------------
+
+When using GCC 14 or later with ``CONFIG_COVERAGE_MCDC=y``, Modified
+Condition/Decision Coverage (MC/DC) data is collected alongside standard
+branch coverage. MC/DC verifies that each condition in a decision
+independently affects the decision's outcome.
+
+To view MC/DC data, use::
+
+    gcov --conditions -o /sys/kernel/debug/gcov/path/to/dir file.c
+
+MC/DC coverage is required by safety standards such as DO-178C
+(avionics) and ISO 26262 (automotive).
+
+GCC's condition coverage implementation has a limit of 64 conditions per
+boolean expression, due to the use of 64-bit bitmasks internally.
+Expressions exceeding this limit cannot be instrumented and will produce
+a compiler warning. This does not affect the correctness of the kernel;
+those expressions simply will not have MC/DC coverage data.
+
+Note that MC/DC instrumentation increases binary size and execution
+overhead compared to standard gcov profiling.
+
+
 Note on compilers
 -----------------
 
diff --git a/Documentation/dev-tools/index.rst b/Documentation/dev-tools/index.rst
index 59cbb77b33ff4..d670c1398e495 100644
--- a/Documentation/dev-tools/index.rst
+++ b/Documentation/dev-tools/index.rst
@@ -23,6 +23,7 @@ Documentation/process/debugging/index.rst
    coccinelle
    context-analysis
    sparse
+   coverage
    kcov
    gcov
    kasan
diff --git a/Documentation/dev-tools/kcov.rst b/Documentation/dev-tools/kcov.rst
index 1a739290c8ecc..98a30a1a3f88a 100644
--- a/Documentation/dev-tools/kcov.rst
+++ b/Documentation/dev-tools/kcov.rst
@@ -12,6 +12,9 @@ To achieve this goal, it does not collect coverage in soft/hard interrupts
 (unless remove coverage collection is enabled, see below) and from some
 inherently non-deterministic parts of the kernel (e.g. scheduler, locking).
 
+KCOV is configured next to the other code coverage implementations, see
+Documentation/dev-tools/coverage.rst.
+
 Besides collecting code coverage, KCOV can also collect comparison operands.
 See the "Comparison operands collection" section for details.
 
diff --git a/MAINTAINERS b/MAINTAINERS
index 506f25cfc3e85..ff9b355c2fc0d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6592,6 +6592,7 @@ F:	drivers/media/platform/chips-media/coda
 CODE COVERAGE
 M:	Sasha Levin <sashal@kernel.org>
 S:	Maintained
+F:	Documentation/dev-tools/coverage.rst
 F:	kernel/coverage/Kconfig
 F:	kernel/coverage/Makefile
 F:	kernel/coverage/core.c
-- 
2.53.0


      parent reply	other threads:[~2026-10-28 12:01 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-28 11:59 [RFC PATCH 00/20] Unify code coverage and add Clang source-based coverage with MC/DC Sasha Levin
2026-10-28 11:59 ` [RFC PATCH 01/20] coverage: move gcov and kcov under kernel/coverage/ Sasha Levin
2026-10-28 11:59 ` [RFC PATCH 02/20] kbuild: unify static coverage instrumentation as COVERAGE_PROFILE Sasha Levin
2026-10-28 11:59 ` Sasha Levin [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261028120034.871983-21-sashal@kernel.org \
    --to=sashal@kernel.org \
    --cc=andreyknvl@gmail.com \
    --cc=chuck@wolber.net \
    --cc=corbet@lwn.net \
    --cc=dvyukov@google.com \
    --cc=elver@google.com \
    --cc=glider@google.com \
    --cc=justinstitt@google.com \
    --cc=kasan-dev@googlegroups.com \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=llvm@lists.linux.dev \
    --cc=mhiramat@kernel.org \
    --cc=morbo@google.com \
    --cc=nathan@kernel.org \
    --cc=ndesaulniers@google.com \
    --cc=oberpar@linux.ibm.com \
    --cc=peterz@infradead.org \
    --cc=rdunlap@infradead.org \
    --cc=skhan@linuxfoundation.org \
    --cc=tglx@kernel.org \
    --cc=workflows@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox