summaryrefslogtreecommitdiff
path: root/common/gcov
blob: b7e3ed5a9352e3088c2f8775309c5ea0993f55b1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#!/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
}