Home / Alt manpages / x86_64-linux-gnu-gcov-13(1)

  • x86_64-linux-gnu-gcov-13(1)
  • User command
  • linux

Measure C Test Coverage with gcov-13

A test suite that passes tells you nothing about the branch it never reached, and that gap is exactly what x86_64-linux-gnu-gcov-13 exposes. Compile a small C program with GCC's coverage instrumentation, run it, and produce a readable report of which lines and branches your test actually exercised.

Allow about fifteen minutes. You need a shell, GCC, a C source file, and a test command that can run the instrumented program. No elevated privileges are needed.

Warning

Coverage data can contain source paths and test behaviour. Treat the generated files as project data rather than sending them to an untrusted service.

Checkpoint

The finished result is a .gcov listing plus optional branch and JSON reports. The report is evidence about the test run, not proof that the program is correct.

1. Confirm the installed toolchain

Check the version and the target-prefixed executable before starting, so you never mix data from one GCC installation with a different gcov implementation:

$ gcc --version | head -n 1
gcc (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0
$ x86_64-linux-gnu-gcov-13 --version | head -n 1
gcov (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0

The unqualified gcov, gcov-13, x86_64-linux-gnu-gcov and x86_64-linux-gnu-gcov-13 names refer to the same GCC 13 coverage tool in this installation. Use the explicit target-prefixed name in scripts when the compiler target matters.

2. Create an isolated coverage build

Make a new directory and enter it. It will receive object files, runtime counters and reports:

$ mkdir -p /tmp/gcov-example
$ cd /tmp/gcov-example
$ printf '%s\n' 'temporary coverage files live here'

For a real project, use a build directory ignored by version control. Do not run gcov from a random directory and then search your source tree for unfamiliar generated files.

Save this minimal program as decision.c. It has one branch that a single test input will leave partly uncovered:

#include <stdio.h>

static int classify(int value)
{
    if (value > 0)
        return 1;
    return 0;
}

int main(void)
{
    printf("%d\n", classify(4));
    return 0;
}

Keep one principal statement per line while investigating coverage. gcov reports at line level, so several statements on one line make the result harder to interpret, and optimisation that folds or combines code makes it less useful still. For a coverage run, prefer a debug build without optimisation.

3. Compile with coverage instrumentation

Compile and link with GCC's --coverage option. It enables the extra notes and runtime counters gcov needs:

$ gcc --coverage -O0 -g decision.c -o decision
$ ls decision decision.gcno
decision  decision.gcno

The compiler creates a .gcno file containing the coverage structure. The running program later creates .gcda data beside the object or executable. These are generated artefacts, not source files to edit.

Checkpoint

If decision.gcno is missing, stop here. Check that GCC accepted --coverage and that you are looking in the directory containing the object file. Running gcov before instrumentation exists cannot produce a useful report.

4. Run the tests that should count

Run the instrumented executable with the same test command you use for the build. This example prints one value and writes the counter data:

$ ./decision
1
$ test -s decision.gcda && echo 'coverage data written'
coverage data written

The .gcda file updates when the program exits normally. A crash, forced termination or unwritable output directory can leave no data or incomplete data. Remove old counters before a clean comparison only when you deliberately want to discard the previous run:

$ rm -f decision.gcda decision.c.gcov decision.gcov.json.gz

Warning

That command permanently removes the selected generated reports and counters. It does not change the source or executable, but do not use it if the counters are the only record of an earlier test run: re-run the instrumented tests to recreate them.

5. Generate and read the line report

Run gcov with the source file name, from the same working directory used for compilation:

$ x86_64-linux-gnu-gcov-13 decision.c
File 'decision.c'
Lines executed:85.71% of 7
Creating 'decision.c.gcov'

The exact percentage depends on the source and compiler details. Open the report and look at its colon-separated fields:

$ sed -n '1,12p' decision.c.gcov
        -:    0:Source:decision.c
        1:    1:#include <stdio.h>
        1:    3:static int classify(int value)
        -:    4:{
        1:    5:    if (value > 0)
        1:    6:        return 1;
    #####:    7:    return 0;
  • A hyphen means the line has no executable code.
  • A number is the execution count for that line.
  • A row marked ##### is reachable but was never executed.

With this test, the negative return path is the useful gap: add a test that calls classify with zero or a negative value, then rerun the program and gcov.

gcov sums contributions when you pass several input files. Usually pass the same source list represented by the final link. Do not assume a report from one executable describes another built from stale object files.

6. Add branch and function detail

Use --branch-probabilities for branch frequencies and --branch-counts when counts are more useful than percentages. --function-summaries adds a summary for each function:

$ x86_64-linux-gnu-gcov-13 --branch-probabilities --branch-counts --function-summaries decision.c
File 'decision.c'
Lines executed:85.71% of 7
Branches executed:100.00% of 2
Taken at least once:50.00% of 2
Creating 'decision.c.gcov'

Exact summary wording varies with the input and installed build. The important distinction: line coverage can look healthy while one side of a conditional remains untested. Use the branch section in the .gcov file to choose your next test, rather than treating a single percentage as a release gate.

7. Produce machine-readable output when needed

For tooling, use --json-format. GCC 13 writes a gzip-compressed file ending in .gcov.json.gz, with compiler, working-directory, function, line and optional branch data:

$ x86_64-linux-gnu-gcov-13 --json-format decision.c
$ gzip -cd decision.gcov.json.gz | head -c 160
{"format_version": "1", "gcc_version": "13.3.0", "current_working_directory": "/tmp/gcov-example", "data_file": "decision.c"}

Do not build a parser around the order or number of preamble fields: the GCC 13 manual says this preamble can grow, so identify fields by their names. Store the JSON beside the matching executable and source revision.

Common traps

  • No data file: check that the instrumented executable ran and could write beside its object files.
  • Source not found: run gcov from the compiler's working directory, or use --object-directory for the directory containing the data files.
  • Unexpected filenames: --preserve-paths keeps directory information, while --hash-filenames avoids filesystem-length problems when that mode creates long names.
  • Misleading totals: confirm old .gcda files are not being accumulated from unrelated test runs.
  • Missing headers in the report: gcov can report source or header files containing instrumented code; use --long-file-names when included files need distinct output names.

Done means

  • Toolchain known: the compiler and gcov versions match the intended build.
  • Data written: the executable was built with --coverage and produced a .gcda file after the test run.
  • Report generated: the line report came from the correct working directory and was checked for unexecuted lines.
  • Branches checked: branch detail was reviewed where condition outcomes matter.
  • Files handled deliberately: generated files are isolated, reproducible, and either ignored or removed on purpose after review.