xref: /trunk/main/sal/qa/helper/gcov/gcov_filter.pl (revision a89ff9078abb366bc00625aa098662a5b9455273)
1#!/usr/bin/perl -w
2#
3# *************************************************************
4#
5#  Licensed to the Apache Software Foundation (ASF) under one
6#  or more contributor license agreements.  See the NOTICE file
7#  distributed with this work for additional information
8#  regarding copyright ownership.  The ASF licenses this file
9#  to you under the Apache License, Version 2.0 (the
10#  "License"); you may not use this file except in compliance
11#  with the License.  You may obtain a copy of the License at
12#
13#    http://www.apache.org/licenses/LICENSE-2.0
14#
15#  Unless required by applicable law or agreed to in writing,
16#  software distributed under the License is distributed on an
17#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18#  KIND, either express or implied.  See the License for the
19#  specific language governing permissions and limitations
20#  under the License.
21#
22# *************************************************************
23
24# GCOV_FILTER
25#
26# Helper to filter the gcov output.
27# Handle a compare between the hole gcov output and a given select list of exported functions.
28#
29# Q: Why perl?
30# A: regexp ;-)
31#
32
33use strict;
34use File::Basename;
35use Getopt::Long;
36
37# Global constants
38our $version_info = 'gcov helper $Revision: 1.4 $ ';
39our $help;                    # Help option flag
40our $version;                 # Version option flag
41our $cwd = `pwd`;             # current working directory
42chomp($cwd);
43# our $tool_dir = dirname($0);
44# our $tool_file = basename($0);
45
46# our $output_filename;
47our $input_allfunc;
48# our $input_filename;
49
50our $allfuncinfo;             # allfuncinfo option flag
51our $showallfunc;             # showallfunc option flag
52our $no_percentage;           # no_percentage option flag
53our $donotfilter;             # donotfilter option flag
54our $objectdir;
55
56# Prototypes
57sub print_usage(*);
58sub read_gcov_function_file($);
59sub get_PRJ_from_makefile_mk();
60# sub read_ExportedFunctionList();
61sub read_List($);
62
63# if (! ($tool_dir =~ /^\/(.*)$/))
64# {
65#     $tool_dir = "$cwd/$tool_dir";
66# }
67
68# Parse command line options
69if (!GetOptions( "input-allfunc=s" => \$input_allfunc,
70                 "allfuncinfo" => \$allfuncinfo,
71                 "showallfunc" => \$showallfunc,
72                 "no-percentage" => \$no_percentage,
73                 "do-not-filter" => \$donotfilter,
74                 "objectdir=s" => \$objectdir,
75                 "help"   => \$help,
76                 "version" => \$version
77                 ))
78{
79    print_usage(*STDERR);
80    exit(1);
81}
82
83# Check for help option
84if ($help)
85{
86    print_usage(*STDOUT);
87    exit(0);
88}
89
90# Check for version option
91if ($version)
92{
93    print("$version_info\n");
94    exit(0);
95}
96
97# check if enough parameters
98if ($#ARGV < 0)
99{
100    print("No input filename specified\n");
101    print_usage(*STDERR);
102    exit(1);
103}
104
105# special case:
106# the filename contains a . or '/' at the beginning
107my $startdir = $ARGV[0];
108if ( ($startdir =~ /^\.\./) ||
109     ($startdir =~ /^\//) )
110{
111    $startdir = dirname($startdir);
112    # print("start directory is $startdir\n");
113    # chdir $startdir;
114}
115else
116{
117    $startdir = "";
118}
119
120# check for sal.map
121if ( ! $input_allfunc )
122{
123    # this is a try, to get the project directory form a found makefile.mk
124    # may work, but fails due to some disunderstandings may be problems in perl :-(
125    my $sDir = get_PRJ_from_makefile_mk();
126    # chomp($sDir);
127    # HDW: print("PRJ is $dir\n");
128
129    # $sDir2 = "../..";
130    my $sMapFile = "$sDir" . "/util/sal.map";
131    # $sMapFile = "$sDir2" . "/util/sal.map";
132
133    if ( -e $sMapFile)
134    {
135        $input_allfunc = $sMapFile;
136    }
137    else
138    {
139        print("No input-allfunc filename specified\n");
140        print_usage(*STDERR);
141        exit(1);
142    }
143}
144our @aDeprecatedList;
145our @aExportedFunctionList;
146# read_ExportedFunctionList();
147@aExportedFunctionList = read_List($input_allfunc);
148@aDeprecatedList = read_List("deprecated.txt");
149
150if ($allfuncinfo)
151{
152    print("Count of all functions: $#aExportedFunctionList\n");
153    exit(0);
154}
155
156if ($showallfunc)
157{
158    my $func;
159    foreach $func (@aExportedFunctionList)
160    {
161        print("$func\n");
162    }
163    exit(0);
164}
165
166# back to current directory
167# this chdir was for a before chdir (in $startdir creation) but due to the fact,
168# that the get_PRJ_from_makefile_mk works but the after concat of strings not, this
169# chdir is also remarked.
170# chdir $cwd;
171
172# HWD: print "count of param: \n";
173# $input_filename = $ARGV[0];
174
175my $nCount = $#ARGV + 1;
176my $nIdx;
177
178for ($nIdx = 0; $nIdx < $nCount ; ++$nIdx)
179{
180    my $file = $ARGV[$nIdx];
181    # print("processing: $file\n");
182
183    # change directory, to the current file, due to the fact, that we may be need to call gcov
184    # and gcov will create some extra files, like *.gcov near the current file.
185    # if ( $startdir ne "" )
186    # {
187    #     chdir $startdir;
188    #     $file = basename($file);
189    # }
190
191    my $OBJECTS="";
192    if ($objectdir)
193    {
194        $OBJECTS = "-o " . $objectdir;
195    }
196
197    if (! ($file =~ /\.f$/ ))
198    {
199        my $filef = "$file.f";
200        # if (! -e $filef )
201        # {
202        # print "gcov $OBJECTS -l -f $file >$filef\n";
203        my $blah = `gcov $OBJECTS -n -f $file >$filef`;
204        # }
205        $file = $filef;
206    }
207    read_gcov_function_file($file);
208
209    # go back to old directory, because it's possible to change relative to an other directory.
210    if ( $startdir ne "" )
211    {
212        chdir $cwd;
213    }
214}
215
216# print "$tool_dir\n";
217# print "all is right\n";
218exit(0);
219
220
221# --------------------------------------------------------------------------------
222# Read the map file, which should contain all exported functions.
223sub read_List($)
224{
225    local *INPUT_HANDLE;
226    my $filename = $_[0];
227    my @list;
228    my $line = "";
229    open(INPUT_HANDLE, $filename);
230        # or die("ERROR: cannot open $filename!\n");
231
232    while ($line = <INPUT_HANDLE>)
233    {
234        chomp($line);
235        # reg exp: [spaces]functionname[semicolon][line end]
236        if ($line =~ /^\s+(\w*);$/)
237        {
238            # print("$1\n");
239            push(@list, $1);
240        }
241    }
242    close(INPUT_HANDLE);
243    return @list;
244}
245
246# --------------------------------------------------------------------------------
247# Helper function, test is a given value is found in the global exported function list.
248# the given value format could be a simple function name
249# or a prototype
250# e.g.
251# osl_getSystemPathFromFileURL
252# or
253# void getSystemPathFromFileURL( const char* rtl_...)
254#
255sub contain_in_List($$)
256{
257    my $func;
258    my $value = $_[0];
259    my $list = $_[1];
260
261    if ($donotfilter)
262    {
263        return $value;
264    }
265
266    foreach $func (@$list) # (@aExportedFunctionList)
267    {
268        # first try, direct check
269        if ($value eq $func)
270        {
271            # HWD: print("$value eq $func\n");
272            return $value;
273        }
274
275        # value not found, second try, may be we found it if we search word wise.
276        # helper, to insert a space after the word, before '('
277        $value =~ s/\(/ \(/g;
278        # may be here we should replace all white spaces by ' '
279
280        # split by 'space'
281        my @list = split(' ', $value);
282        for(@list)
283        {
284            # HWD: print "$list[$n]\n";
285            if ($_ eq $func)
286            {
287                # HWD: print ("found $func in $value\n");
288                return $_;
289            }
290        }
291    }
292    # not found
293    return "";
294}
295# --------------------------------------------------------------------------------
296# Read the gcov function (gcov -f) file
297# and compare line by line with the export function list
298# so we get a list of functions, which are only exported, and not all stuff.
299# sample of output
300# new gcov gcc 3.4 format
301sub read_gcov_function_file($)
302{
303    local *INPUT_HANDLE;
304    my $file = $_[0];
305    my $line = "";
306    open(INPUT_HANDLE, $file)
307        or die("ERROR: cannot open $file!\n");
308
309    while ($line = <INPUT_HANDLE>)
310    {
311        chomp($line);
312        # sample line (for reg exp:)
313        # 100.00% of 3 source lines executed in function osl_thread_init_Impl
314        if ($line =~ /^Function \`(.*)\'$/ )
315        {
316            my $sFunctionName = $1;
317            my $sPercentage;
318            $line = <INPUT_HANDLE>;
319            if ($line =~ /^Lines executed:(.*)% of/ )
320            {
321                $sPercentage = $1;
322            }
323            my $value = contain_in_List( $sFunctionName, \@aExportedFunctionList );
324            if ($value)
325            {
326                my $isDeprecated = contain_in_List( $sFunctionName, \@aDeprecatedList );
327                if ($isDeprecated)
328                {
329                    # Function is deprecated, do not export it.
330                }
331                else
332                {
333                    if ($no_percentage)
334                    {
335                        print("$value\n");
336                    }
337                    else
338                    {
339                        print("$sPercentage $value\n");
340                    }
341                }
342            }
343            # push(@aExportedFunctionList, $1);
344        }
345    }
346    close(INPUT_HANDLE);
347}
348
349# gcov format since gcc 3.3.6
350# 100.00% von 3 Zeilen in function helloworld ausgeführt
351# 100.00% von 5 Zeilen in function main ausgeführt
352# 100.00% von 8 Zeilen in file tmp.c ausgeführt
353sub read_gcov_function_file_old_gcc_3($)
354{
355    local *INPUT_HANDLE;
356    my $file = $_[0];
357    my $line = "";
358    open(INPUT_HANDLE, $file)
359        or die("ERROR: cannot open $file!\n");
360
361    while ($line = <INPUT_HANDLE>)
362    {
363        chomp($line);
364        # sample line (for reg exp:)
365        # 100.00% of 3 source lines executed in function osl_thread_init_Impl
366        if ($line =~ /^(.*)% of \d+ source lines executed in function (.*)$/ )
367        {
368            my $value = contain_in_List( $2, \@aExportedFunctionList );
369            if ($value)
370            {
371                my $isDeprecated = contain_in_List( $2, \@aDeprecatedList );
372                if ($isDeprecated)
373                {
374                    # Function is deprecated, do not export it.
375                }
376                else
377                {
378                    if ($no_percentage)
379                    {
380                        print("$value\n");
381                    }
382                    else
383                    {
384                        print("$1 $value\n");
385                    }
386                }
387            }
388            # push(@aExportedFunctionList, $1);
389        }
390    }
391    close(INPUT_HANDLE);
392}
393
394# ------------------------------------------------------------------------------
395# helper, to read the PRJ value out of a makefile.mk file
396sub get_PRJ_from_makefile_mk()
397{
398    local *INPUT_HANDLE;
399    # my $startdir = @_[0];
400    my $line = "";
401    my $value = "";
402    open(INPUT_HANDLE, "makefile.mk")
403        or die("ERROR: cannot open makefile.mk\n");
404
405    while ($line = <INPUT_HANDLE>)
406    {
407        chomp($line);
408        # sample line
409        # PRJ=
410        # HWD: print("$line\n");
411        if ($line =~ /^PRJ\s*=(.*)\s*$/)
412        {
413            # HWD: print("FOUND #####\n");
414            $value = $1;
415            chomp($value);
416            $value =~ s/\$\//\//g;
417        }
418    }
419    close(INPUT_HANDLE);
420    return $value;
421}
422
423# ----------------------------------------------------------------------------
424sub print_usage(*)
425{
426    local *HANDLE = $_[0];
427    my $tool_name = basename($0);
428
429    print(HANDLE <<END_OF_USAGE);
430
431Usage: $tool_name [OPTIONS] INPUTFILE
432
433    -h, --help                     Print this help, then exit
434    -v, --version                  Print version number, then exit
435    -i, --input-allfunc FILENAME   Map file, which contain all exported functions
436    -s, --showallfunc              Shows all exported functions then exit
437    -a, --allfuncinfo              Shows the count of all exported functions then quit
438    -n, --no-percentage            Suppress the output of the percent value for tested functions
439    -d, --do-not-filter            Show all functions, which gcov -f produce
440
441END_OF_USAGE
442    ;
443}
444