Skip to main content
The Coverage Analyzer agent generates gcov coverage data for C/C++ programs, showing which lines of code were executed during a test run. This data is essential for crash analysis and verification.

Purpose

Generate code coverage data that shows:
  • Which lines were executed (and how many times)
  • Which lines were not executed
  • Branch coverage information
  • Function coverage statistics

Invocation

Invoked by the crash-analysis-agent as part of the crash analysis workflow. Receives:
  • Code repository path
  • Working directory path
  • Crashing example program and build instructions
Creates: gcov/ subdirectory in working directory

Workflow

1

Rebuild with Coverage Flags

Add coverage instrumentation to the build:
  • Add --coverage -g to both CFLAGS and LDFLAGS
  • Alternative: -fprofile-arcs -ftest-coverage
Autotools:
./configure CFLAGS="--coverage -g" LDFLAGS="--coverage"
CMake:
cmake -DCMAKE_C_FLAGS="--coverage -g" \
      -DCMAKE_EXE_LINKER_FLAGS="--coverage" ..
Makefile:
make CFLAGS="--coverage -g" LDFLAGS="--coverage"
2

Run Crashing Program

<crashing-command>
# Creates .gcda files alongside .gcno files in build directory
The execution generates:
  • .gcno files (created at compile time - note data)
  • .gcda files (created at runtime - data)
3

Generate Coverage Reports

# Find all .gcda files and run gcov
find . -name "*.gcda" -exec dirname {} \; | sort -u | while read dir; do
  (cd "$dir" && gcov *.gcda)
done

# Or for specific files:
gcov -o <build-dir> <source-file.c>
4

Copy Coverage Files

find . -name "*.gcov" -exec cp {} gcov/ \;

Coverage File Format

Gcov files (.gcov) show line-by-line execution counts:
        -:    0:Source:example.c
        -:    1:#include <stdio.h>
        -:    2:
        1:    3:int main() {
        1:    4:    int x = 5;
        5:    5:    for (int i = 0; i < 5; i++) {
        5:    6:        x += i;
        -:    7:    }
    #####:    8:    printf("Never executed\n");
        1:    9:    return 0;
        -:   10:}
Legend:
  • Number: Line executed N times
  • #####: Line not executed (0 times)
  • -: Non-executable line (comments, declarations, blank lines)

Validation

After generating coverage, validate: Manual validation:
# Lines starting with a number were executed
grep -E "^\s+[0-9]+:" gcov/*.gcov | head -20

# Lines starting with ##### were not executed
grep -E "^\s+#####:" gcov/*.gcov | head -20
Using line-execution-checker skill:
# Build the line checker
g++ -o line_checker .claude/skills/crash-analysis/line-execution-checker/line_checker.cpp

# Check if specific line was executed
./line_checker <source-file.c>:<line-number>
# Exit code 0 = executed, 1 = not executed

Usage in Crash Analysis

The crash-analyzer-agent uses coverage data to:
  1. Verify execution path: Confirm hypothesized code lines were actually executed
  2. Validate causal chain: Every line in the root-cause hypothesis must show as executed
  3. Detect dead code: Identify code that couldn’t have contributed to crash
  4. Cross-check with traces: Correlate with function-level traces
Critical validation rule:
Every line of code claimed to be part of the crash’s causal chain MUST show as executed in the coverage data. If not, the hypothesis is wrong.

Coverage Metrics

Gcov provides several coverage metrics:
Percentage of executable lines that were executed
gcov example.c
# Lines executed:80.00% of 10

Advanced Usage

Branch Coverage

Show branch coverage details:
gcov -b -c source.c
Output includes:
branch  0 taken 5
branch  1 taken 0  (never executed)

Function-Level Summary

gcov -f source.c
Shows which functions were called:
Function 'main'
Lines executed:100.00% of 5

Function 'helper'
Lines executed:0.00% of 3

HTML Reports

Generate HTML coverage reports with lcov:
# Capture coverage data
lcov --capture --directory . --output-file coverage.info

# Generate HTML
genhtml coverage.info --output-directory coverage_html

Performance Impact

Coverage instrumentation has minimal overhead:
  • Compile time: Slightly slower (debug info + instrumentation)
  • Runtime: <10% slowdown typically
  • Disk space: .gcda files can be large for complex programs
Much lower overhead than function tracing - suitable for longer test runs.

Troubleshooting

  • Program didn’t execute successfully
  • Crashed before coverage data flushed
  • Missing write permissions
  • Check that --coverage was in both CFLAGS and LDFLAGS
  • Wrong .gcda file used (from different build)
  • .gcno and .gcda files don’t match (rebuild needed)
  • Run gcov from correct directory
  • Run gcov from build directory
  • Use -o flag to specify object file directory:
    gcov -o build/src source.c
    
  • Coverage data written on normal exit only
  • For crash analysis, this is expected
  • Data shows path up to crash point

Output Structure

<working-dir>/gcov/
├── file1.c.gcov
├── file2.c.gcov
├── header1.h.gcov
└── module.c.gcov

Crash Analysis

Main crash analysis orchestrator

Function Trace Generator

Complementary function-level trace generation

Build docs developers (and LLMs) love