#!/bin/bash # SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2023 Oracle. All Rights Reserved. # # Routines for capturing kernel code coverage reports GCOV_DIR=/sys/kernel/debug/gcov # Find the topmost directories of the .gcno directory hierarchy __gcov_find_topdirs() { find "${GCOV_DIR}/" -name '*.gcno' -printf '%d|%h\n' | \ sort -g -k 1 | \ uniq | \ $AWK_PROG -F '|' 'BEGIN { x = -1 } { if (x < 0) x = $1; if ($1 == x) printf("%s\n", $2);}' } # Generate lcov html report from kernel gcov data if configured _gcov_generate_report() { local output_dir="$1" test -n "${output_dir}" || return # Kernel support built in? test -d "$GCOV_DIR" || return readarray -t gcno_dirs < <(__gcov_find_topdirs) test "${#gcno_dirs[@]}" -gt 0 || return mkdir -p "${output_dir}/raw/" # Collect raw coverage data from the kernel readarray -t source_dirs < <(find "${GCOV_DIR}/" -mindepth 1 -maxdepth 1 -type d) for dir in "${source_dirs[@]}"; do cp -p -R -d -u "${dir}" "${output_dir}/raw/" done # If lcov is installed, use it to summarize the gcda data. # If it is not installed, there's no point in going forward command -v lcov > /dev/null || return local lcov=(lcov --exclude 'include*' --capture) lcov+=(--output-file "${output_dir}/gcov.report") for d in "${gcno_dirs[@]}"; do lcov+=(--directory "${d}") done # Generate a detailed HTML report from the summary local gcov_start_time="$(date --date="${fstests_start_time:-now}")" local genhtml=() if command -v genhtml > /dev/null; then genhtml+=(genhtml -o "${output_dir}/" "${output_dir}/gcov.report") genhtml+=(--title "fstests on $(hostname -s) @ ${gcov_start_time}" --legend) fi # Try to convert the HTML report summary as text for easier grepping if # there's an HTML renderer present local totext=() test "${#totext[@]}" -eq 0 && \ command -v lynx &>/dev/null && \ totext=(lynx -dump "${output_dir}/index.html" -width 120 -nonumbers -nolist) test "${#totext[@]}" -eq 0 && \ command -v links &>/dev/null && \ totext=(links -dump "${output_dir}/index.html" -width 120) test "${#totext[@]}" -eq 0 && \ command -v elinks &>/dev/null && \ totext=(elinks -dump "${output_dir}/index.html" --dump-width 120 --no-numbering --no-references) # Analyze kernel data "${lcov[@]}" > "${output_dir}/gcov.stdout" 2> "${output_dir}/gcov.stderr" test "${#genhtml[@]}" -ne 0 && \ "${genhtml[@]}" >> "${output_dir}/gcov.stdout" 2>> "${output_dir}/gcov.stderr" test "${#totext[@]}" -ne 0 && \ "${totext[@]}" > "${output_dir}/index.txt" 2>> "${output_dir}/gcov.stderr" } # Reset gcov usage data _gcov_reset() { echo 1 > "${GCOV_DIR}/reset" } # If the caller wanted us to capture gcov reports but the kernel doesn't # support it, turn it off. _gcov_check_report_gcov() { test -z "$REPORT_GCOV" && return 0 test -w "${GCOV_DIR}/reset" && return 0 unset REPORT_GCOV return 1 }