|
65 | 65 | #
|
66 | 66 |
|
67 | 67 | use strict;
|
68 |
| -use File::Basename; |
| 68 | +use File::Basename; |
| 69 | +use File::Temp qw(tempfile); |
69 | 70 | use Getopt::Long;
|
70 | 71 | use Digest::MD5 qw(md5_base64);
|
71 | 72 |
|
72 | 73 |
|
73 | 74 | # Global constants
|
74 | 75 | our $title = "LCOV - code coverage report";
|
75 |
| -our $lcov_version = 'LCOV version 1.11 pre (CVS $Revision: 1.70 $)'; |
| 76 | +our $lcov_version = 'LCOV version 1.11 pre (CVS $Revision: 1.71 $)'; |
76 | 77 | our $lcov_url = "http://ltp.sourceforge.net/coverage/lcov.php";
|
77 | 78 | our $tool_name = basename($0);
|
78 | 79 |
|
@@ -672,6 +673,162 @@ sub print_overall_rate($$$$$$$$$)
|
672 | 673 | if ($br_do);
|
673 | 674 | }
|
674 | 675 |
|
| 676 | +sub get_fn_list($) |
| 677 | +{ |
| 678 | + my ($info) = @_; |
| 679 | + my %fns; |
| 680 | + my @result; |
| 681 | + |
| 682 | + foreach my $filename (keys(%{$info})) { |
| 683 | + my $data = $info->{$filename}; |
| 684 | + my $funcdata = $data->{"func"}; |
| 685 | + my $sumfnccount = $data->{"sumfnc"}; |
| 686 | + |
| 687 | + if (defined($funcdata)) { |
| 688 | + foreach my $func_name (keys(%{$funcdata})) { |
| 689 | + $fns{$func_name} = 1; |
| 690 | + } |
| 691 | + } |
| 692 | + |
| 693 | + if (defined($sumfnccount)) { |
| 694 | + foreach my $func_name (keys(%{$sumfnccount})) { |
| 695 | + $fns{$func_name} = 1; |
| 696 | + } |
| 697 | + } |
| 698 | + } |
| 699 | + |
| 700 | + @result = keys(%fns); |
| 701 | + |
| 702 | + return \@result; |
| 703 | +} |
| 704 | + |
| 705 | +# |
| 706 | +# rename_functions(info, conv) |
| 707 | +# |
| 708 | +# Rename all function names in INFO according to CONV: OLD_NAME -> NEW_NAME. |
| 709 | +# |
| 710 | + |
| 711 | +sub rename_functions($$) |
| 712 | +{ |
| 713 | + my ($info, $conv) = @_; |
| 714 | + |
| 715 | + foreach my $filename (keys(%{$info})) { |
| 716 | + my $data = $info->{$filename}; |
| 717 | + my $funcdata; |
| 718 | + my $testfncdata; |
| 719 | + my $sumfnccount; |
| 720 | + my %newfuncdata; |
| 721 | + my %newsumfnccount; |
| 722 | + |
| 723 | + # funcdata: function name -> line number |
| 724 | + $funcdata = $data->{"func"}; |
| 725 | + foreach my $fn_name (keys(%{$funcdata})) { |
| 726 | + $newfuncdata{$conv->{$fn_name}} = $funcdata->{$fn_name}; |
| 727 | + } |
| 728 | + $data->{"func"} = \%newfuncdata; |
| 729 | + |
| 730 | + # testfncdata: test name -> testfnccount |
| 731 | + # testfnccount: function name -> execution count |
| 732 | + $testfncdata = $data->{"testfnc"}; |
| 733 | + foreach my $test_name (keys(%{$testfncdata})) { |
| 734 | + my $testfnccount = $testfncdata->{$test_name}; |
| 735 | + my %newtestfnccount; |
| 736 | + |
| 737 | + foreach my $fn_name (keys(%{$testfnccount})) { |
| 738 | + $newtestfnccount{$conv->{$fn_name}} = |
| 739 | + $testfnccount->{$fn_name}; |
| 740 | + } |
| 741 | + $testfncdata->{$test_name} = \%newtestfnccount; |
| 742 | + } |
| 743 | + |
| 744 | + # sumfnccount: function name -> execution count |
| 745 | + $sumfnccount = $data->{"sumfnc"}; |
| 746 | + foreach my $fn_name (keys(%{$sumfnccount})) { |
| 747 | + $newsumfnccount{$conv->{$fn_name}} = |
| 748 | + $sumfnccount->{$fn_name}; |
| 749 | + } |
| 750 | + $data->{"sumfnc"} = \%newsumfnccount; |
| 751 | + } |
| 752 | +} |
| 753 | + |
| 754 | +# |
| 755 | +# check_unique_conv(CONV) |
| 756 | +# |
| 757 | +# Check that there is no A in CONV: A -> B where C -> B. |
| 758 | +# |
| 759 | + |
| 760 | +sub check_unique_conv($) |
| 761 | +{ |
| 762 | + my ($conv) = @_; |
| 763 | + my %rconv; |
| 764 | + |
| 765 | + foreach my $fn_name (keys(%{$conv})) { |
| 766 | + my $c = $conv->{$fn_name}; |
| 767 | + |
| 768 | + if (defined($rconv{$c})) { |
| 769 | + die("ERROR: non-unique c++filt output for ". |
| 770 | + "'$fn_name' and '$rconv{$c}!\n"); |
| 771 | + } |
| 772 | + $rconv{$c} = $fn_name; |
| 773 | + } |
| 774 | +} |
| 775 | + |
| 776 | +# |
| 777 | +# demangle_cpp(INFO) |
| 778 | +# |
| 779 | +# Demangle all function names found in INFO. |
| 780 | +# |
| 781 | +sub demangle_cpp($) |
| 782 | +{ |
| 783 | + my ($info) = @_; |
| 784 | + my $fn_list = get_fn_list($info); |
| 785 | + my @fn_list_demangled; |
| 786 | + my $tmpfile; |
| 787 | + my $handle; |
| 788 | + my %demangled; |
| 789 | + my $changed; |
| 790 | + |
| 791 | + # Nothing to do |
| 792 | + return if (!@$fn_list); |
| 793 | + |
| 794 | + # Write list to temp file |
| 795 | + (undef, $tmpfile) = tempfile(); |
| 796 | + die("ERROR: could not create temporary file") if (!defined($tmpfile)); |
| 797 | + open($handle, ">", $tmpfile) or |
| 798 | + die("ERROR: could not write to $tmpfile: $!\n"); |
| 799 | + print($handle join("\n", @$fn_list)); |
| 800 | + close($handle); |
| 801 | + |
| 802 | + # Run c++ filt on tempfile file and parse output, creating a hash |
| 803 | + open($handle, "-|", "c++filt < $tmpfile") or |
| 804 | + die("ERROR: could not run c++filt: $!\n"); |
| 805 | + @fn_list_demangled = <$handle>; |
| 806 | + close($handle); |
| 807 | + unlink($tmpfile) or |
| 808 | + warn("WARNING: could not remove temporary file $tmpfile: $!\n"); |
| 809 | + |
| 810 | + if (scalar(@fn_list_demangled) != scalar(@$fn_list)) { |
| 811 | + die("ERROR: c++filt output not as expected (". |
| 812 | + scalar(@fn_list_demangled)." vs ". |
| 813 | + scalar(@$fn_list).") lines\n"); |
| 814 | + } |
| 815 | + |
| 816 | + # Build old_name -> new_name |
| 817 | + $changed = 0; |
| 818 | + for (my $i = 0; $i < scalar(@$fn_list); $i++) { |
| 819 | + chomp($fn_list_demangled[$i]); |
| 820 | + $demangled{$fn_list->[$i]} = $fn_list_demangled[$i]; |
| 821 | + $changed++ if ($fn_list->[$i] ne $fn_list_demangled[$i]); |
| 822 | + } |
| 823 | + |
| 824 | + # Should not be necessary but could silently produce incorrect results |
| 825 | + check_unique_conv(\%demangled); |
| 826 | + |
| 827 | + info("Demangling $changed function names\n"); |
| 828 | + |
| 829 | + # Change all occurrences of function names in INFO |
| 830 | + rename_functions($info, \%demangled); |
| 831 | +} |
675 | 832 |
|
676 | 833 | #
|
677 | 834 | # gen_html()
|
@@ -730,6 +887,9 @@ sub gen_html()
|
730 | 887 | %info_data = %{apply_baseline(\%info_data, \%base_data)};
|
731 | 888 | }
|
732 | 889 |
|
| 890 | + # Demangle C++ function names if requested |
| 891 | + demangle_cpp(\%info_data) if ($demangle_cpp); |
| 892 | + |
733 | 893 | @dir_list = get_dir_list(keys(%info_data));
|
734 | 894 |
|
735 | 895 | if ($no_prefix)
|
@@ -5194,12 +5354,7 @@ END_OF_HTML
|
5194 | 5354 | my $count = $sumfncdata->{$name};
|
5195 | 5355 | my $countstyle;
|
5196 | 5356 |
|
5197 |
| - # Demangle C++ function names if requested |
5198 |
| - if ($demangle_cpp) { |
5199 |
| - $name = `c++filt "$name"`; |
5200 |
| - chomp($name); |
5201 |
| - } |
5202 |
| - # Escape any remaining special characters |
| 5357 | + # Escape special characters |
5203 | 5358 | $name = escape_html($name);
|
5204 | 5359 | if ($startline < 1) {
|
5205 | 5360 | $startline = 1;
|
|
0 commit comments