blob: 7b180635cdb652df89954199e66f19e6eaee6103 [file] [log] [blame]
Andrew Geissler82c905d2020-04-13 13:39:40 -05001From e13b2b6f8443da660cafa0679c3b16240843ce9f Mon Sep 17 00:00:00 2001
2From: Peter Oberparleiter <oberpar@linux.ibm.com>
3Date: Fri, 24 May 2019 17:16:56 +0200
4Subject: [PATCH 2/2] geninfo: Add intermediate JSON format support
5
6This change adds support for parsing the output of gcov's intermediate
7JSON file format as implemented by GCC version 9.
8
9Note: The way that the intermediate file format support is implemented
10in geninfo removes the need to parse .gcno files directly. Since geninfo
11does not include support for parsing GCC 9 .gcno files, using the
12intermediate format is the only option for geninfo to collect coverage
13data generated by GCC version 9.
14
15Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
16---
17 bin/geninfo | 162 +++++++++++++++++++++++++++++++++++++++++++++++++++-
18 1 file changed, 160 insertions(+), 2 deletions(-)
19
20Upstream-Status: Backport
21Download URL: https://github.com/linux-test-project/lcov/commit/75fbae1cfc5027f818a0bb865bf6f96fab3202da
22
23diff --git a/bin/geninfo b/bin/geninfo
24index 0276666..cceb782 100755
25--- a/bin/geninfo
26+++ b/bin/geninfo
27@@ -59,6 +59,9 @@ use File::Copy qw(copy);
28 use Getopt::Long;
29 use Digest::MD5 qw(md5_base64);
30 use Cwd qw/abs_path/;
31+use PerlIO::gzip;
32+use JSON qw(decode_json);
33+
34 if( $^O eq "msys" )
35 {
36 require File::Spec::Win32;
37@@ -474,7 +477,8 @@ if ($rc_intermediate eq "0") {
38 $intermediate = 1;
39 } elsif (lc($rc_intermediate) eq "auto") {
40 # Use intermediate format if supported by gcov
41- $intermediate = $gcov_caps->{'intermediate-format'} ? 1 : 0;
42+ $intermediate = ($gcov_caps->{'intermediate-format'} ||
43+ $gcov_caps->{'json-format'}) ? 1 : 0;
44 } else {
45 die("ERROR: invalid value for geninfo_intermediate: ".
46 "'$rc_intermediate'\n");
47@@ -2084,6 +2088,48 @@ sub read_intermediate_text($$)
48 }
49
50
51+#
52+# read_intermediate_json(gcov_filename, data, basedir_ref)
53+#
54+# Read gcov intermediate JSON format in GCOV_FILENAME and add the resulting
55+# data to DATA in the following format:
56+#
57+# data: source_filename -> file_data
58+# file_data: GCOV JSON data for file
59+#
60+# Also store the value for current_working_directory to BASEDIR_REF.
61+#
62+
63+sub read_intermediate_json($$$)
64+{
65+ my ($gcov_filename, $data, $basedir_ref) = @_;
66+ my $fd;
67+ my $text;
68+ my $json;
69+
70+ open($fd, "<:gzip", $gcov_filename) or
71+ die("ERROR: Could not read $gcov_filename: $!\n");
72+ local $/;
73+ $text = <$fd>;
74+ close($fd);
75+
76+ $json = decode_json($text);
77+ if (!defined($json) || !exists($json->{"files"}) ||
78+ ref($json->{"files"} ne "ARRAY")) {
79+ die("ERROR: Unrecognized JSON output format in ".
80+ "$gcov_filename\n");
81+ }
82+
83+ $$basedir_ref = $json->{"current_working_directory"};
84+
85+ for my $file (@{$json->{"files"}}) {
86+ my $filename = $file->{"file"};
87+
88+ $data->{$filename} = $file;
89+ }
90+}
91+
92+
93 #
94 # intermediate_text_to_info(fd, data, srcdata)
95 #
96@@ -2173,6 +2219,104 @@ sub intermediate_text_to_info($$$)
97 }
98
99
100+#
101+# intermediate_json_to_info(fd, data, srcdata)
102+#
103+# Write DATA in info format to file descriptor FD.
104+#
105+# data: filename -> file_data:
106+# file_data: GCOV JSON data for file
107+#
108+# srcdata: filename -> [ excl, brexcl, checksums ]
109+# excl: lineno -> 1 for all lines for which to exclude all data
110+# brexcl: lineno -> 1 for all lines for which to exclude branch data
111+# checksums: lineno -> source code checksum
112+#
113+# Note: To simplify processing, gcov data is not combined here, that is counts
114+# that appear multiple times for the same lines/branches are not added.
115+# This is done by lcov/genhtml when reading the data files.
116+#
117+
118+sub intermediate_json_to_info($$$)
119+{
120+ my ($fd, $data, $srcdata) = @_;
121+ my $branch_num = 0;
122+
123+ return if (!%{$data});
124+
125+ print($fd "TN:$test_name\n");
126+ for my $filename (keys(%{$data})) {
127+ my ($excl, $brexcl, $checksums);
128+ my $file_data = $data->{$filename};
129+
130+ if (defined($srcdata->{$filename})) {
131+ ($excl, $brexcl, $checksums) = @{$srcdata->{$filename}};
132+ }
133+
134+ print($fd "SF:$filename\n");
135+
136+ # Function data
137+ if ($func_coverage) {
138+ for my $d (@{$file_data->{"functions"}}) {
139+ my $line = $d->{"start_line"};
140+ my $count = $d->{"execution_count"};
141+ my $name = $d->{"name"};
142+
143+ next if (!defined($line) || !defined($count) ||
144+ !defined($name) || $excl->{$line});
145+
146+ print($fd "FN:$line,$name\n");
147+ print($fd "FNDA:$count,$name\n");
148+ }
149+ }
150+
151+ # Line data
152+ for my $d (@{$file_data->{"lines"}}) {
153+ my $line = $d->{"line_number"};
154+ my $count = $d->{"count"};
155+ my $c;
156+ my $branches = $d->{"branches"};
157+ my $unexec = $d->{"unexecuted_block"};
158+
159+ next if (!defined($line) || !defined($count) ||
160+ $excl->{$line});
161+
162+ if (defined($unexec) && $unexec && $count == 0) {
163+ $unexec = 1;
164+ } else {
165+ $unexec = 0;
166+ }
167+
168+ if ($checksum && exists($checksums->{$line})) {
169+ $c = ",".$checksums->{$line};
170+ } else {
171+ $c = "";
172+ }
173+ print($fd "DA:$line,$count$c\n");
174+
175+ $branch_num = 0;
176+ # Branch data
177+ if ($br_coverage && !$brexcl->{$line}) {
178+ for my $b (@$branches) {
179+ my $brcount = $b->{"count"};
180+
181+ if (!defined($brcount) || $unexec) {
182+ $brcount = "-";
183+ }
184+ print($fd "BRDA:$line,0,$branch_num,".
185+ "$brcount\n");
186+
187+ $branch_num++;
188+ }
189+ }
190+
191+ }
192+
193+ print($fd "end_of_record\n");
194+ }
195+}
196+
197+
198 sub get_output_fd($$)
199 {
200 my ($outfile, $file) = @_;
201@@ -2243,6 +2387,8 @@ sub process_intermediate($$$)
202 my $srcdata;
203 my $is_graph = 0;
204 my ($out, $err, $rc);
205+ my $json_basedir;
206+ my $json_format;
207
208 info("Processing %s\n", abs2rel($file, $dir));
209
210@@ -2296,6 +2442,12 @@ sub process_intermediate($$$)
211 unlink($gcov_filename);
212 }
213
214+ for my $gcov_filename (glob("*.gcov.json.gz")) {
215+ read_intermediate_json($gcov_filename, \%data, \$json_basedir);
216+ unlink($gcov_filename);
217+ $json_format = 1;
218+ }
219+
220 if (!%data) {
221 warn("WARNING: GCOV did not produce any data for $file\n");
222 return;
223@@ -2304,6 +2456,8 @@ sub process_intermediate($$$)
224 # Determine base directory
225 if (defined($base_directory)) {
226 $base = $base_directory;
227+ } elsif (defined($json_basedir)) {
228+ $base = $json_basedir;
229 } else {
230 $base = $fdir;
231
232@@ -2331,7 +2485,11 @@ sub process_intermediate($$$)
233
234 # Generate output
235 $fd = get_output_fd($output_filename, $file);
236- intermediate_text_to_info($fd, \%data, $srcdata);
237+ if ($json_format) {
238+ intermediate_json_to_info($fd, \%data, $srcdata);
239+ } else {
240+ intermediate_text_to_info($fd, \%data, $srcdata);
241+ }
242 close($fd);
243
244 chdir($cwd);
245--
2462.17.1
247