Imported vendor release 1.14-1 16/228016/1 accepted/tizen/unified/20200318.130445 submit/tizen/20200318.071145
authorJIHUN <JIHUN87.PARK@samsung.com>
Wed, 18 Mar 2020 06:24:00 +0000 (15:24 +0900)
committerJIHUN <JIHUN87.PARK@samsung.com>
Wed, 18 Mar 2020 06:24:00 +0000 (15:24 +0900)
Change-Id: I619ba38522669a0d06f5c2c84d1d6ab748cb8f33
Signed-off-by: JIHUN <JIHUN87.PARK@samsung.com>
bin/gendesc
bin/genhtml
bin/geninfo
bin/genpng
bin/lcov
bin/updateversion.pl
lcovrc
man/genhtml.1
man/lcovrc.5
packaging/lcov.spec [moved from rpm/lcov.spec with 97% similarity]

index ea07b4e..97cde00 100755 (executable)
@@ -13,8 +13,8 @@
 #   General Public License for more details.                 
 #
 #   You should have received a copy of the GNU General Public License
-#   along with this program;  if not, write to the Free Software
-#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#   along with this program;  if not, see
+#   <http://www.gnu.org/licenses/>.
 #
 #
 # gendesc
index b86102f..b6cbad9 100755 (executable)
@@ -13,8 +13,8 @@
 #   General Public License for more details. 
 #
 #   You should have received a copy of the GNU General Public License
-#   along with this program;  if not, write to the Free Software
-#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#   along with this program;  if not, see
+#   <http://www.gnu.org/licenses/>.
 #
 #
 # genhtml
@@ -155,6 +155,9 @@ our $BR_CLOSE       = 5;
 our $BR_SUB = 0;
 our $BR_ADD = 1;
 
+# Block value used for unnamed blocks
+our $UNNAMED_BLOCK = vec(pack('b*', 1 x 32), 0, 32);
+
 # Error classes which users may specify to ignore during processing
 our $ERROR_SOURCE      = 0;
 our %ERROR_ID = (
@@ -1625,6 +1628,7 @@ sub read_info_file($)
                                   ($1, $2, $3, $4);
 
                                last if (!$br_coverage);
+                               $block = -1 if ($block == $UNNAMED_BLOCK);
                                $sumbrcount->{$line} .=
                                        "$block,$branch,$taken:";
 
index 5a8b8b5..56c65c1 100755 (executable)
@@ -13,8 +13,8 @@
 #   General Public License for more details.                 
 #
 #   You should have received a copy of the GNU General Public License
-#   along with this program;  if not, write to the Free Software
-#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#   along with this program;  if not, see
+#   <http://www.gnu.org/licenses/>.
 #
 #
 # geninfo
@@ -54,9 +54,14 @@ use warnings;
 use File::Basename; 
 use File::Spec::Functions qw /abs2rel catdir file_name_is_absolute splitdir
                              splitpath catpath/;
+use File::Temp qw(tempfile tempdir);
+use File::Copy qw(copy);
 use Getopt::Long;
 use Digest::MD5 qw(md5_base64);
 use Cwd qw/abs_path/;
+use PerlIO::gzip;
+use JSON qw(decode_json);
+
 if( $^O eq "msys" )
 {
        require File::Spec::Win32;
@@ -163,13 +168,13 @@ sub solve_relative_path($$);
 sub read_gcov_header($);
 sub read_gcov_file($);
 sub info(@);
+sub process_intermediate($$$);
 sub map_llvm_version($);
 sub version_to_str($);
 sub get_gcov_version();
 sub system_no_output($@);
 sub read_config($);
 sub apply_config($);
-sub get_exclusion_data($);
 sub apply_exclusion_data($$);
 sub process_graphfile($$);
 sub filter_fn_name($);
@@ -264,6 +269,8 @@ our $gcno_split_crc;
 our $func_coverage = 1;
 our $br_coverage = 0;
 our $rc_auto_base = 1;
+our $rc_intermediate = "auto";
+our $intermediate;
 our $excl_line = "LCOV_EXCL_LINE";
 our $excl_br_line = "LCOV_EXCL_BR_LINE";
 
@@ -331,6 +338,7 @@ if ($config || %opt_rc)
                "geninfo_compat"                => \$opt_compat,
                "geninfo_adjust_src_path"       => \$rc_adjust_src_path,
                "geninfo_auto_base"             => \$rc_auto_base,
+               "geninfo_intermediate"          => \$rc_intermediate,
                "lcov_function_coverage"        => \$func_coverage,
                "lcov_branch_coverage"          => \$br_coverage,
                "lcov_excl_line"                => \$excl_line,
@@ -460,15 +468,39 @@ if (system_no_output(3, $gcov_tool, "--help") == -1)
 }
 
 ($gcov_version, $gcov_version_string) = get_gcov_version();
+$gcov_caps = get_gcov_capabilities();
+
+# Determine intermediate mode
+if ($rc_intermediate eq "0") {
+       $intermediate = 0;
+} elsif ($rc_intermediate eq "1") {
+       $intermediate = 1;
+} elsif (lc($rc_intermediate) eq "auto") {
+       # Use intermediate format if supported by gcov
+       $intermediate = ($gcov_caps->{'intermediate-format'} ||
+                        $gcov_caps->{'json-format'}) ? 1 : 0;
+} else {
+       die("ERROR: invalid value for geninfo_intermediate: ".
+           "'$rc_intermediate'\n");
+}
+
+if ($intermediate) {
+       info("Using intermediate gcov format\n");
+       if ($opt_derive_func_data) {
+               warn("WARNING: --derive-func-data is not compatible with ".
+                    "intermediate format - ignoring\n");
+               $opt_derive_func_data = 0;
+       }
+}
 
 # Determine gcov options
-$gcov_caps = get_gcov_capabilities();
 push(@gcov_options, "-b") if ($gcov_caps->{'branch-probabilities'} &&
                              ($br_coverage || $func_coverage));
 push(@gcov_options, "-c") if ($gcov_caps->{'branch-counts'} &&
                              $br_coverage);
 push(@gcov_options, "-a") if ($gcov_caps->{'all-blocks'} &&
-                             $opt_gcov_all_blocks && $br_coverage);
+                             $opt_gcov_all_blocks && $br_coverage &&
+                             !$intermediate);
 if ($gcov_caps->{'hash-filenames'})
 {
        push(@gcov_options, "-x");
@@ -599,7 +631,7 @@ foreach my $entry (@data_directory) {
        gen_info($entry);
 }
 
-if ($initial && $br_coverage) {
+if ($initial && $br_coverage && !$intermediate) {
        warn("Note: --initial does not generate branch coverage ".
             "data\n");
 }
@@ -768,6 +800,7 @@ sub gen_info($)
        my $prefix;
        my $type;
        my $ext;
+       my $tempdir;
 
        if ($initial) {
                $type = "graph";
@@ -798,16 +831,22 @@ sub gen_info($)
                $prefix = "";
        }
 
+       $tempdir = tempdir(CLEANUP => 1);
+
        # Process all files in list
        foreach $file (@file_list) {
                # Process file
-               if ($initial) {
+               if ($intermediate) {
+                       process_intermediate($file, $prefix, $tempdir);
+               } elsif ($initial) {
                        process_graphfile($file, $prefix);
                } else {
                        process_dafile($file, $prefix);
                }
        }
 
+       unlink($tempdir);
+
        # Report whether files were excluded.
        if (%excluded_files) {
                info("Excluded data for %d files due to include/exclude options\n",
@@ -1058,10 +1097,12 @@ sub process_dafile($$)
 
        # Try to find base directory automatically if requested by user
        if ($rc_auto_base) {
-               $base_dir = find_base_from_graph($base_dir, $instr, $graph);
+               $base_dir = find_base_from_source($base_dir,
+                       [ keys(%{$instr}), keys(%{$graph}) ]);
        }
 
-       ($instr, $graph) = adjust_graph_filenames($base_dir, $instr, $graph);
+       adjust_source_filenames($instr, $base_dir);
+       adjust_source_filenames($graph, $base_dir);
 
        # Set $object_dir to real location of object files. This may differ
        # from $da_dir if the graph file is just a link to the "real" object
@@ -2017,6 +2058,453 @@ sub read_gcov_file($)
 }
 
 
+#
+# read_intermediate_text(gcov_filename, data)
+#
+# Read gcov intermediate text format in GCOV_FILENAME and add the resulting
+# data to DATA in the following format:
+#
+# data:      source_filename -> file_data
+# file_data: concatenated lines of intermediate text data
+#
+
+sub read_intermediate_text($$)
+{
+       my ($gcov_filename, $data) = @_;
+       my $fd;
+       my $filename;
+
+       open($fd, "<", $gcov_filename) or
+               die("ERROR: Could not read $gcov_filename: $!\n");
+       while (my $line = <$fd>) {
+               if ($line =~ /^file:(.*)$/) {
+                       $filename = $1;
+                       chomp($filename);
+               } elsif (defined($filename)) {
+                       $data->{$filename} .= $line;
+               }
+       }
+       close($fd);
+}
+
+
+#
+# read_intermediate_json(gcov_filename, data, basedir_ref)
+#
+# Read gcov intermediate JSON format in GCOV_FILENAME and add the resulting
+# data to DATA in the following format:
+#
+# data:      source_filename -> file_data
+# file_data: GCOV JSON data for file
+#
+# Also store the value for current_working_directory to BASEDIR_REF.
+#
+
+sub read_intermediate_json($$$)
+{
+       my ($gcov_filename, $data, $basedir_ref) = @_;
+       my $fd;
+       my $text;
+       my $json;
+
+       open($fd, "<:gzip", $gcov_filename) or
+               die("ERROR: Could not read $gcov_filename: $!\n");
+       local $/;
+       $text = <$fd>;
+       close($fd);
+
+       $json = decode_json($text);
+       if (!defined($json) || !exists($json->{"files"}) ||
+           ref($json->{"files"} ne "ARRAY")) {
+               die("ERROR: Unrecognized JSON output format in ".
+                   "$gcov_filename\n");
+       }
+
+       $$basedir_ref = $json->{"current_working_directory"};
+
+       for my $file (@{$json->{"files"}}) {
+               my $filename = $file->{"file"};
+
+               $data->{$filename} = $file;
+       }
+}
+
+
+#
+# intermediate_text_to_info(fd, data, srcdata)
+#
+# Write DATA in info format to file descriptor FD.
+#
+# data:      filename -> file_data:
+# file_data: concatenated lines of intermediate text data
+#
+# srcdata:   filename -> [ excl, brexcl, checksums ]
+# excl:      lineno -> 1 for all lines for which to exclude all data
+# brexcl:    lineno -> 1 for all lines for which to exclude branch data
+# checksums: lineno -> source code checksum
+#
+# Note: To simplify processing, gcov data is not combined here, that is counts
+#       that appear multiple times for the same lines/branches are not added.
+#       This is done by lcov/genhtml when reading the data files.
+#
+
+sub intermediate_text_to_info($$$)
+{
+       my ($fd, $data, $srcdata) = @_;
+       my $branch_num = 0;
+       my $c;
+
+       return if (!%{$data});
+
+       print($fd "TN:$test_name\n");
+       for my $filename (keys(%{$data})) {
+               my ($excl, $brexcl, $checksums);
+
+               if (defined($srcdata->{$filename})) {
+                       ($excl, $brexcl, $checksums) = @{$srcdata->{$filename}};
+               }
+
+               print($fd "SF:$filename\n");
+               for my $line (split(/\n/, $data->{$filename})) {
+                       if ($line =~ /^lcount:(\d+),(\d+),?/) {
+                               # lcount:<line>,<count>
+                               # lcount:<line>,<count>,<has_unexecuted_blocks>
+                               if ($checksum && exists($checksums->{$1})) {
+                                       $c = ",".$checksums->{$1};
+                               } else {
+                                       $c = "";
+                               }
+                               print($fd "DA:$1,$2$c\n") if (!$excl->{$1});
+
+                               # Intermediate text format does not provide
+                               # branch numbers, and the same branch may appear
+                               # multiple times on the same line (e.g. in
+                               # template instances). Synthesize a branch
+                               # number based on the assumptions:
+                               # a) the order of branches is fixed across
+                               #    instances
+                               # b) an instance starts with an lcount line
+                               $branch_num = 0;
+                       } elsif ($line =~ /^function:(\d+),(\d+),([^,]+)$/) {
+                               next if (!$func_coverage || $excl->{$1});
+
+                               # function:<line>,<count>,<name>
+                               print($fd "FN:$1,$3\n");
+                               print($fd "FNDA:$2,$3\n");
+                       } elsif ($line =~ /^function:(\d+),\d+,(\d+),([^,]+)$/) {
+                               next if (!$func_coverage || $excl->{$1});
+
+                               # function:<start_line>,<end_line>,<count>,
+                               #          <name>
+                               print($fd "FN:$1,$3\n");
+                               print($fd "FNDA:$2,$3\n");
+                       } elsif ($line =~ /^branch:(\d+),(taken|nottaken|notexec)/) {
+                               next if (!$br_coverage || $excl->{$1} ||
+                                        $brexcl->{$1});
+
+                               # branch:<line>,taken|nottaken|notexec
+                               if ($2 eq "taken") {
+                                       $c = 1;
+                               } elsif ($2 eq "nottaken") {
+                                       $c = 0;
+                               } else {
+                                       $c = "-";
+                               }
+                               print($fd "BRDA:$1,0,$branch_num,$c\n");
+                               $branch_num++;
+                       }
+               }
+               print($fd "end_of_record\n");
+       }
+}
+
+
+#
+# intermediate_json_to_info(fd, data, srcdata)
+#
+# Write DATA in info format to file descriptor FD.
+#
+# data:      filename -> file_data:
+# file_data: GCOV JSON data for file
+#
+# srcdata:   filename -> [ excl, brexcl, checksums ]
+# excl:      lineno -> 1 for all lines for which to exclude all data
+# brexcl:    lineno -> 1 for all lines for which to exclude branch data
+# checksums: lineno -> source code checksum
+#
+# Note: To simplify processing, gcov data is not combined here, that is counts
+#       that appear multiple times for the same lines/branches are not added.
+#       This is done by lcov/genhtml when reading the data files.
+#
+
+sub intermediate_json_to_info($$$)
+{
+       my ($fd, $data, $srcdata) = @_;
+       my $branch_num = 0;
+
+       return if (!%{$data});
+
+       print($fd "TN:$test_name\n");
+       for my $filename (keys(%{$data})) {
+               my ($excl, $brexcl, $checksums);
+               my $file_data = $data->{$filename};
+
+               if (defined($srcdata->{$filename})) {
+                       ($excl, $brexcl, $checksums) = @{$srcdata->{$filename}};
+               }
+
+               print($fd "SF:$filename\n");
+
+               # Function data
+               if ($func_coverage) {
+                       for my $d (@{$file_data->{"functions"}}) {
+                               my $line = $d->{"start_line"};
+                               my $count = $d->{"execution_count"};
+                               my $name = $d->{"name"};
+
+                               next if (!defined($line) || !defined($count) ||
+                                        !defined($name) || $excl->{$line});
+
+                               print($fd "FN:$line,$name\n");
+                               print($fd "FNDA:$count,$name\n");
+                       }
+               }
+
+               # Line data
+               for my $d (@{$file_data->{"lines"}}) {
+                       my $line = $d->{"line_number"};
+                       my $count = $d->{"count"};
+                       my $c;
+                       my $branches = $d->{"branches"};
+                       my $unexec = $d->{"unexecuted_block"};
+
+                       next if (!defined($line) || !defined($count) ||
+                                $excl->{$line});
+
+                       if (defined($unexec) && $unexec && $count == 0) {
+                               $unexec = 1;
+                       } else {
+                               $unexec = 0;
+                       }
+
+                       if ($checksum && exists($checksums->{$line})) {
+                               $c = ",".$checksums->{$line};
+                       } else {
+                               $c = "";
+                       }
+                       print($fd "DA:$line,$count$c\n");
+
+                       $branch_num = 0;
+                       # Branch data
+                       if ($br_coverage && !$brexcl->{$line}) {
+                               for my $b (@$branches) {
+                                       my $brcount = $b->{"count"};
+
+                                       if (!defined($brcount) || $unexec) {
+                                               $brcount = "-";
+                                       }
+                                       print($fd "BRDA:$line,0,$branch_num,".
+                                             "$brcount\n");
+
+                                       $branch_num++;
+                               }
+                       }
+
+               }
+
+               print($fd "end_of_record\n");
+       }
+}
+
+
+sub get_output_fd($$)
+{
+       my ($outfile, $file) = @_;
+       my $fd;
+
+       if (!defined($outfile)) {
+               open($fd, ">", "$file.info") or
+                       die("ERROR: Cannot create file $file.info: $!\n");
+       } elsif ($outfile eq "-") {
+               open($fd, ">&STDOUT") or
+                       die("ERROR: Cannot duplicate stdout: $!\n");
+       } else {
+               open($fd, ">>", $outfile) or
+                       die("ERROR: Cannot write to file $outfile: $!\n");
+       }
+
+       return $fd;
+}
+
+
+#
+# print_gcov_warnings(stderr_file, is_graph, map)
+#
+# Print GCOV warnings in file STDERR_FILE to STDERR. If IS_GRAPH is non-zero,
+# suppress warnings about missing as these are expected. Replace keys found
+# in MAP with their values.
+#
+
+sub print_gcov_warnings($$$)
+{
+       my ($stderr_file, $is_graph, $map) = @_;
+       my $fd;
+
+       if (!open($fd, "<", $stderr_file)) {
+               warn("WARNING: Could not open GCOV stderr file ".
+                    "$stderr_file: $!\n");
+               return;
+       }
+       while (my $line = <$fd>) {
+               next if ($is_graph && $line =~ /cannot open data file/);
+
+               for my $key (keys(%{$map})) {
+                       $line =~ s/\Q$key\E/$map->{$key}/g;
+               }
+
+               print(STDERR $line);
+       }
+       close($fd);
+}
+
+
+#
+# process_intermediate(file, dir, tempdir)
+#
+# Create output for a single file (either a data file or a graph file) using
+# gcov's intermediate option.
+#
+
+sub process_intermediate($$$)
+{
+       my ($file, $dir, $tempdir) = @_;
+       my ($fdir, $fbase, $fext);
+       my $data_file;
+       my $errmsg;
+       my %data;
+       my $fd;
+       my $base;
+       my $srcdata;
+       my $is_graph = 0;
+       my ($out, $err, $rc);
+       my $json_basedir;
+       my $json_format;
+
+       info("Processing %s\n", abs2rel($file, $dir));
+
+       $file = solve_relative_path($cwd, $file);
+       ($fdir, $fbase, $fext) = split_filename($file);
+
+       $is_graph = 1 if (".$fext" eq $graph_file_extension);
+
+       if ($is_graph) {
+               # Process graph file - copy to temp directory to prevent
+               # accidental processing of associated data file
+               $data_file = "$tempdir/$fbase$graph_file_extension";
+               if (!copy($file, $data_file)) {
+                       $errmsg = "ERROR: Could not copy file $file";
+                       goto err;
+               }
+       } else {
+               # Process data file in place
+               $data_file = $file;
+       }
+
+       # Change directory
+       if (!chdir($tempdir)) {
+               $errmsg = "Could not change to directory $tempdir: $!";
+               goto err;
+       }
+
+       # Run gcov on data file
+       ($out, $err, $rc) = system_no_output(1 + 2 + 4, $gcov_tool,
+                                            $data_file, @gcov_options, "-i");
+       defined($out) && unlink($out);
+       if (defined($err)) {
+               print_gcov_warnings($err, $is_graph, {
+                       $data_file => $file,
+               });
+               unlink($err);
+       }
+       if ($rc) {
+               $errmsg = "GCOV failed for $file";
+               goto err;
+       }
+
+       if ($is_graph) {
+               # Remove graph file copy
+               unlink($data_file);
+       }
+
+       # Parse resulting file(s)
+       for my $gcov_filename (glob("*.gcov")) {
+               read_intermediate_text($gcov_filename, \%data);
+               unlink($gcov_filename);
+       }
+
+       for my $gcov_filename (glob("*.gcov.json.gz")) {
+               read_intermediate_json($gcov_filename, \%data, \$json_basedir);
+               unlink($gcov_filename);
+               $json_format = 1;
+       }
+
+       if (!%data) {
+               warn("WARNING: GCOV did not produce any data for $file\n");
+               return;
+       }
+
+       # Determine base directory
+       if (defined($base_directory)) {
+               $base = $base_directory;
+       } elsif (defined($json_basedir)) {
+               $base = $json_basedir;
+       } else {
+               $base = $fdir;
+
+               if (is_compat($COMPAT_MODE_LIBTOOL)) {
+                       # Avoid files from .libs dirs
+                       $base =~ s/\.libs$//;
+               }
+
+               # Try to find base directory automatically if requested by user
+               if ($rc_auto_base) {
+                       $base = find_base_from_source($base, [ keys(%data) ]);
+               }
+       }
+
+       # Apply base file name to relative source files
+       adjust_source_filenames(\%data, $base);
+
+       # Remove excluded source files
+       filter_source_files(\%data);
+
+       # Get data on exclusion markers and checksums if requested
+       if (!$no_markers || $checksum) {
+               $srcdata = get_all_source_data(keys(%data));
+       }
+
+       # Generate output
+       $fd = get_output_fd($output_filename, $file);
+       if ($json_format) {
+               intermediate_json_to_info($fd, \%data, $srcdata);
+       } else {
+               intermediate_text_to_info($fd, \%data, $srcdata);
+       }
+       close($fd);
+
+       chdir($cwd);
+
+       return;
+
+err:
+       if ($ignore[$ERROR_GCOV]) {
+               warn("WARNING: $errmsg!\n");
+       } else {
+               die("ERROR: $errmsg!\n")
+       }
+}
+
+
 # Map LLVM versions to the version of GCC gcov which they emulate.
 
 sub map_llvm_version($)
@@ -2151,8 +2639,12 @@ sub int_handler()
 #
 #   MODE & 1: suppress STDOUT
 #   MODE & 2: suppress STDERR
+#   MODE & 4: redirect to temporary files instead of suppressing
 #
-# Return 0 on success, non-zero otherwise.
+# Return (stdout, stderr, rc):
+#    stdout: path to tempfile containing stdout or undef
+#    stderr: path to tempfile containing stderr or undef
+#    0 on success, non-zero otherwise
 #
 
 sub system_no_output($@)
@@ -2161,14 +2653,31 @@ sub system_no_output($@)
        my $result;
        local *OLD_STDERR;
        local *OLD_STDOUT;
+       my $stdout_file;
+       my $stderr_file;
+       my $fd;
 
        # Save old stdout and stderr handles
        ($mode & 1) && open(OLD_STDOUT, ">>&", "STDOUT");
        ($mode & 2) && open(OLD_STDERR, ">>&", "STDERR");
 
-       # Redirect to /dev/null
-       ($mode & 1) && open(STDOUT, ">", "/dev/null");
-       ($mode & 2) && open(STDERR, ">", "/dev/null");
+       if ($mode & 4) {
+               # Redirect to temporary files
+               if ($mode & 1) {
+                       ($fd, $stdout_file) = tempfile(UNLINK => 1);
+                       open(STDOUT, ">", $stdout_file) || warn("$!\n");
+                       close($fd);
+               }
+               if ($mode & 2) {
+                       ($fd, $stderr_file) = tempfile(UNLINK => 1);
+                       open(STDERR, ">", $stderr_file) || warn("$!\n");
+                       close($fd);
+               }
+       } else {
+               # Redirect to /dev/null
+               ($mode & 1) && open(STDOUT, ">", "/dev/null");
+               ($mode & 2) && open(STDERR, ">", "/dev/null");
+       }
  
        debug("system(".join(' ', @_).")\n");
        system(@_);
@@ -2181,8 +2690,18 @@ sub system_no_output($@)
        # Restore old handles
        ($mode & 1) && open(STDOUT, ">>&", "OLD_STDOUT");
        ($mode & 2) && open(STDERR, ">>&", "OLD_STDERR");
+
+       # Remove empty output files
+       if (defined($stdout_file) && -z $stdout_file) {
+               unlink($stdout_file);
+               $stdout_file = undef;
+       }
+       if (defined($stderr_file) && -z $stderr_file) {
+               unlink($stderr_file);
+               $stderr_file = undef;
+       }
  
-       return $result;
+       return ($stdout_file, $stderr_file, $result);
 }
 
 
@@ -2260,23 +2779,28 @@ sub apply_config($)
 
 
 #
-# get_exclusion_data(filename)
+# get_source_data(filename)
 #
-# Scan specified source code file for exclusion markers and return
-#   linenumber -> 1
-# for all lines which should be excluded.
+# Scan specified source code file for exclusion markers and checksums. Return
+#   ( excl, brexcl, checksums ) where
+#   excl:      lineno -> 1 for all lines for which to exclude all data
+#   brexcl:    lineno -> 1 for all lines for which to exclude branch data
+#   checksums: lineno -> source code checksum
 #
 
-sub get_exclusion_data($)
+sub get_source_data($)
 {
        my ($filename) = @_;
        my %list;
        my $flag = 0;
+       my %brdata;
+       my $brflag = 0;
+       my %checksums;
        local *HANDLE;
 
        if (!open(HANDLE, "<", $filename)) {
                warn("WARNING: could not open $filename\n");
-               return undef;
+               return;
        }
        while (<HANDLE>) {
                if (/$EXCL_STOP/) {
@@ -2287,14 +2811,62 @@ sub get_exclusion_data($)
                if (/$excl_line/ || $flag) {
                        $list{$.} = 1;
                }
+               if (/$EXCL_BR_STOP/) {
+                       $brflag = 0;
+               } elsif (/$EXCL_BR_START/) {
+                       $brflag = 1;
+               }
+               if (/$excl_br_line/ || $brflag) {
+                       $brdata{$.} = 1;
+               }
+               if ($checksum) {
+                       chomp();
+                       $checksums{$.} = md5_base64($_);
+               }
        }
        close(HANDLE);
 
-       if ($flag) {
+       if ($flag || $brflag) {
                warn("WARNING: unterminated exclusion section in $filename\n");
        }
 
-       return \%list;
+       return (\%list, \%brdata, \%checksums);
+}
+
+
+#
+# get_all_source_data(filenames)
+#
+# Scan specified source code files for exclusion markers and return
+#   filename -> [ excl, brexcl, checksums ]
+#   excl:      lineno -> 1 for all lines for which to exclude all data
+#   brexcl:    lineno -> 1 for all lines for which to exclude branch data
+#   checksums: lineno -> source code checksum
+#
+
+sub get_all_source_data(@)
+{
+       my @filenames = @_;
+       my %data;
+       my $failed = 0;
+
+       for my $filename (@filenames) {
+               my @d;
+               next if (exists($data{$filename}));
+
+               @d = get_source_data($filename);
+               if (@d) {
+                       $data{$filename} = [ @d ];
+               } else {
+                       $failed = 1;
+               }
+       }
+
+       if ($failed) {
+               warn("WARNING: some exclusion markers may be ignored\n");
+       }
+
+       return \%data;
 }
 
 
@@ -2318,35 +2890,17 @@ sub apply_exclusion_data($$)
 {
        my ($instr, $graph) = @_;
        my $filename;
-       my %excl_data;
-       my $excl_read_failed = 0;
+       my $excl_data;
 
-       # Collect exclusion marker data
-       foreach $filename (sort_uniq_lex(keys(%{$graph}), keys(%{$instr}))) {
-               my $excl = get_exclusion_data($filename);
-
-               # Skip and note if file could not be read
-               if (!defined($excl)) {
-                       $excl_read_failed = 1;
-                       next;
-               }
-
-               # Add to collection if there are markers
-               $excl_data{$filename} = $excl if (keys(%{$excl}) > 0);
-       }
-
-       # Warn if not all source files could be read
-       if ($excl_read_failed) {
-               warn("WARNING: some exclusion markers may be ignored\n");
-       }
+       ($excl_data) = get_all_source_data(keys(%{$graph}), keys(%{$instr}));
 
        # Skip if no markers were found
-       return ($instr, $graph) if (keys(%excl_data) == 0);
+       return ($instr, $graph) if (!%$excl_data);
 
        # Apply exclusion marker data to graph
-       foreach $filename (keys(%excl_data)) {
+       foreach $filename (keys(%$excl_data)) {
                my $function_data = $graph->{$filename};
-               my $excl = $excl_data{$filename};
+               my $excl = $excl_data->{$filename}->[0];
                my $function;
 
                next if (!defined($function_data));
@@ -2384,9 +2938,9 @@ sub apply_exclusion_data($$)
        }
 
        # Apply exclusion marker data to instr
-       foreach $filename (keys(%excl_data)) {
+       foreach $filename (keys(%$excl_data)) {
                my $line_data = $instr->{$filename};
-               my $excl = $excl_data{$filename};
+               my $excl = $excl_data->{$filename}->[0];
                my $line;
                my @new_data;
 
@@ -2468,10 +3022,12 @@ sub process_graphfile($$)
 
        # Try to find base directory automatically if requested by user
        if ($rc_auto_base) {
-               $base_dir = find_base_from_graph($base_dir, $instr, $graph);
+               $base_dir = find_base_from_source($base_dir,
+                       [ keys(%{$instr}), keys(%{$graph}) ]);
        }
 
-       ($instr, $graph) = adjust_graph_filenames($base_dir, $instr, $graph);
+       adjust_source_filenames($instr, $base_dir);
+       adjust_source_filenames($graph, $base_dir);
 
        if (!$no_markers) {
                # Apply exclusion marker data to graph file data
@@ -2767,11 +3323,11 @@ sub parent_dir($)
 }
 
 #
-# find_base_from_graph(base_dir, instr, graph)
+# find_base_from_source(base_dir, source_files)
 #
-# Try to determine the base directory of the graph file specified by INSTR
-# and GRAPH. The base directory is the base for all relative filenames in
-# the graph file. It is defined by the current working directory at time
+# Try to determine the base directory of the object file built from
+# SOURCE_FILES. The base directory is the base for all relative filenames in
+# the gcov data. It is defined by the current working directory at time
 # of compiling the source file.
 #
 # This function implements a heuristic which relies on the following
@@ -2781,16 +3337,16 @@ sub parent_dir($)
 # - files by the same name are not present in multiple parent directories
 #
 
-sub find_base_from_graph($$$)
+sub find_base_from_source($$)
 {
-       my ($base_dir, $instr, $graph) = @_;
+       my ($base_dir, $source_files) = @_;
        my $old_base;
        my $best_miss;
        my $best_base;
        my %rel_files;
 
        # Determine list of relative paths
-       foreach my $filename (keys(%{$instr}), keys(%{$graph})) {
+       foreach my $filename (@$source_files) {
                next if (file_name_is_absolute($filename));
 
                $rel_files{$filename} = 1;
@@ -2829,17 +3385,17 @@ sub find_base_from_graph($$$)
 }
 
 #
-# adjust_graph_filenames(base_dir, instr, graph)
+# adjust_source_filenames(hash, base_dir)
 #
-# Make relative paths in INSTR and GRAPH absolute and apply
-# geninfo_adjust_src_path setting to graph file data.
+# Transform all keys of HASH to absolute form and apply requested
+# transformations.
 #
 
-sub adjust_graph_filenames($$$)
+sub adjust_source_filenames($$$)
 {
-       my ($base_dir, $instr, $graph) = @_;
+       my ($hash, $base_dir) = @_;
 
-       foreach my $filename (keys(%{$instr})) {
+       foreach my $filename (keys(%{$hash})) {
                my $old_filename = $filename;
 
                # Convert to absolute canonical form
@@ -2851,28 +3407,50 @@ sub adjust_graph_filenames($$$)
                }
 
                if ($filename ne $old_filename) {
-                       $instr->{$filename} = delete($instr->{$old_filename});
+                       $hash->{$filename} = delete($hash->{$old_filename});
                }
        }
+}
 
-       foreach my $filename (keys(%{$graph})) {
-               my $old_filename = $filename;
 
-               # Make absolute
-               # Convert to absolute canonical form
-               $filename = solve_relative_path($base_dir, $filename);
+#
+# filter_source_files(hash)
+#
+# Remove unwanted source file data from HASH.
+#
 
-               # Apply adjustment
-               if (defined($adjust_src_pattern)) {
-                       $filename =~ s/$adjust_src_pattern/$adjust_src_replace/g;
+sub filter_source_files($)
+{
+       my ($hash) = @_;
+
+       foreach my $filename (keys(%{$hash})) {
+               # Skip external files if requested
+               goto del if (!$opt_external && is_external($filename));
+
+               # Apply include patterns
+               if (@include_patterns) {
+                       my $keep;
+
+                       foreach my $pattern (@include_patterns) {
+                               if ($filename =~ (/^$pattern$/)) {
+                                       $keep = 1;
+                                       last;
+                               }
+                       }
+                       goto del if (!$keep);
                }
 
-               if ($filename ne $old_filename) {
-                       $graph->{$filename} = delete($graph->{$old_filename});
+               # Apply exclude patterns
+               foreach my $pattern (@exclude_patterns) {
+                       goto del if ($filename =~ (/^$pattern$/));
                }
-       }
+               next;
 
-       return ($instr, $graph);
+del:
+               # Remove file data
+               delete($hash->{$filename});
+               $excluded_files{$filename} = 1;
+       }
 }
 
 #
@@ -3784,6 +4362,7 @@ sub get_gcov_capabilities()
                'c' => 'branch-counts',
                'f' => 'function-summaries',
                'h' => 'help',
+               'i' => 'intermediate-format',
                'l' => 'long-file-names',
                'n' => 'no-output',
                'o' => 'object-directory',
index e1d431a..bf8e821 100755 (executable)
@@ -13,8 +13,8 @@
 #   General Public License for more details.                 
 #
 #   You should have received a copy of the GNU General Public License
-#   along with this program;  if not, write to the Free Software
-#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#   along with this program;  if not, see
+#   <http://www.gnu.org/licenses/>.
 #
 #
 # genpng
index e30d991..f76f9d4 100755 (executable)
--- a/bin/lcov
+++ b/bin/lcov
@@ -13,8 +13,8 @@
 #   General Public License for more details.                 
 #
 #   You should have received a copy of the GNU General Public License
-#   along with this program;  if not, write to the Free Software
-#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#   along with this program;  if not, see
+#   <http://www.gnu.org/licenses/>.
 #
 #
 # lcov
index 19db81e..d39918a 100755 (executable)
@@ -84,7 +84,9 @@ sub get_file_info($)
 
        return (0, 0, 0) if (!-e $filename);
        @stat = stat($filename);
-       ($sec, $min, $hour, $day, $month, $year) = gmtime($stat[9]);
+       my $epoch = int($ENV{SOURCE_DATE_EPOCH} || $stat[9]);
+       $epoch = $stat[9] if $stat[9] < $epoch;
+       ($sec, $min, $hour, $day, $month, $year) = gmtime($epoch);
        $year += 1900;
        $month += 1;
 
diff --git a/lcovrc b/lcovrc
index 40f364f..bd4bc3b 100644 (file)
--- a/lcovrc
+++ b/lcovrc
@@ -134,6 +134,9 @@ genhtml_desc_html=0
 # when collecting coverage data.
 geninfo_auto_base = 1
 
+# Use gcov intermediate format? Valid values are 0, 1, auto
+geninfo_intermediate = auto
+
 # Directory containing gcov kernel files
 # lcov_gcov_dir = /proc/gcov
 
index aa1e1e7..6f13be3 100644 (file)
@@ -65,6 +65,7 @@ genhtml \- Generate HTML view from LCOV coverage data files
 .IR keyword = value ]
 .br
 .RB [ \-\-precision
+.IR num ]
 .RB [ \-\-missed ]
 .br
 .IR tracefile(s)
index a6d654b..07d35ff 100644 (file)
@@ -223,6 +223,11 @@ geninfo_compat_libtool = 0
 geninfo_auto_base = 1
 .br
 
+# Use gcov intermediate format? Valid values are 0, 1, auto
+.br
+geninfo_intermediate = auto
+.br
+
 # Directory containing gcov kernel files
 .br
 lcov_gcov_dir = /proc/gcov
@@ -789,6 +794,25 @@ located, and in addition, is different between files of the same project.
 Default is 1.
 .PP
 
+.BR geninfo_intermediate " ="
+.IR 0 | 1 | auto
+.IP
+Specify whether to use gcov intermediate format
+.br
+
+Use this option to control whether geninfo should use the gcov intermediate
+format while collecting coverage data. The use of the gcov intermediate format
+should increase processing speed. It also provides branch coverage data when
+using the \-\-initial command line option.
+.br
+
+Valid values are 0 for off, 1 for on, and "auto" to let geninfo automatically
+use immediate format when supported by gcov.
+.br
+
+Default is "auto".
+.PP
+
 .BR lcov_gcov_dir " ="
 .I path_to_kernel_coverage_data
 .IP
similarity index 97%
rename from rpm/lcov.spec
rename to packaging/lcov.spec
index e96c8d4..753cd38 100644 (file)
@@ -9,6 +9,8 @@ Source0: http://downloads.sourceforge.net/ltp/%{name}-%{version}.tar.gz
 BuildRoot: %{_tmppath}/%{name}-%{version}-root
 BuildArch: noarch
 Requires: perl >= 5.8.8
+Requires: perl-PerlIO-gzip
+Requires: perl-json
 
 %description
 LCOV is a graphical front-end for GCC's coverage testing tool gcov. It collects