Home | History | Annotate | Download | only in tests
      1 #!/usr/bin/env perl
      2 
      3 #-------------------------------------------------------------------
      4 # Check header files and #include directives
      5 #
      6 # (1) include/*.h must not include pub_core_...h
      7 # (2) coregrind/pub_core_xyzzy.h may include pub_tool_xyzzy.h
      8 #     other coregrind headers may not include pub_tool_xyzzy.h
      9 # (3) coregrind/ *.c must not include pub_tool_xyzzy.h
     10 # (4) tool *.[ch] files must not include pub_core_...h
     11 # (5) include pub_core/tool_clreq.h instead of valgrind.h except in tools'
     12 #     export headers
     13 #-------------------------------------------------------------------
     14 
     15 use strict;
     16 use warnings;
     17 use File::Basename;
     18 use Getopt::Long;
     19 
     20 my $this_script = basename($0);
     21 
     22 # The list of top-level directories is divided into three sets:
     23 #
     24 # (1) coregrind directories
     25 # (2) tool directories
     26 # (3) directories to ignore
     27 #
     28 # If a directory is found that does not belong to any of those sets, the
     29 # script will terminate unsuccessfully.
     30 
     31 my %coregrind_dirs = (
     32     "include" => 1,
     33     "coregrind" => 1,
     34     );
     35 
     36 my %tool_dirs = (
     37     "none" => 1,
     38     "lackey" => 1,
     39     "massif" => 1,
     40     "memcheck" => 1,
     41     "drd" => 1,
     42     "helgrind", => 1,
     43     "callgrind" => 1,
     44     "cachegrind" => 1,
     45     "shared" => 1,
     46     "exp-bbv" => 1,
     47     "exp-dhat" => 1,
     48     "exp-sgcheck" => 1
     49     );
     50 
     51 my %dirs_to_ignore = (
     52     ".deps" => 1,
     53     ".svn" => 1,
     54     ".git" => 1,            # allow git mirrors of the svn repo
     55     ".in_place" => 1,
     56     "Inst" => 1,            # the nightly scripts creates this
     57     "VEX" => 1,
     58     "docs" => 1,
     59     "auxprogs" => 1,
     60     "autom4te.cache" => 1,
     61     "nightly" => 1,
     62     "perf" => 1,
     63     "tests" => 1,
     64     "gdbserver_tests" => 1,
     65     "mpi" => 1
     66     );
     67 
     68 my %tool_export_header = (
     69     "drd/drd.h" => 1,
     70     "helgrind/helgrind.h" => 1,
     71     "memcheck/memcheck.h" => 1,
     72     "callgrind/callgrind.h" => 1
     73     );
     74 
     75 my $usage=<<EOF;
     76 USAGE
     77 
     78   $this_script
     79 
     80     [--debug]          Debugging output
     81 
     82     dir ...            Directories to process
     83 EOF
     84 
     85 my $debug = 0;
     86 my $num_errors = 0;
     87 
     88 &main;
     89 
     90 sub main {
     91     GetOptions( "debug"  => \$debug ) || die $usage;
     92 
     93     my $argc = $#ARGV + 1;
     94 
     95     if ($argc < 1) {
     96         die $usage;
     97     }
     98 
     99     foreach my $dir (@ARGV) {
    100         process_dir(undef, $dir, 0);
    101     }
    102 
    103     my $rc = ($num_errors == 0) ? 0 : 1;
    104     exit $rc;
    105 }
    106 
    107 sub process_dir {
    108     my ($path, $dir, $depth) = @_;
    109     my $hdir;
    110 
    111     if ($depth == 0) {
    112 # The root directory is always processed
    113     } elsif ($depth == 1) {
    114 # Toplevel directories
    115         return if ($dirs_to_ignore{$dir});
    116 
    117         if (! $tool_dirs{$dir} && ! $coregrind_dirs{$dir}) {
    118             die "Unknown directory '$dir'. Please update $this_script\n";
    119         }
    120     } else {
    121 # Subdirectories
    122         return if ($dirs_to_ignore{$dir});
    123     }
    124 
    125     print "DIR = $dir   DEPTH = $depth\n" if ($debug);
    126 
    127     chdir($dir) || die "Cannot chdir '$dir'\n";
    128 
    129     opendir($hdir, ".") || die "cannot open directory '.'";
    130 
    131     while (my $file = readdir($hdir)) {
    132         next if ($file eq ".");
    133         next if ($file eq "..");
    134 
    135 # Subdirectories
    136         if (-d $file) {
    137             my $full_path = defined $path ? "$path/$file" : $file;
    138             process_dir($full_path, $file, $depth + 1);
    139             next;
    140         }
    141 
    142 # Regular files; only interested in *.c and *.h
    143         next if (! ($file =~ /\.[ch]$/));
    144         my $path_name = defined $path ? "$path/$file" : $file;
    145         process_file($path_name);
    146     }
    147     close($hdir);
    148     chdir("..") || die "Cannot chdir '..'\n";
    149 }
    150 
    151 #---------------------------------------------------------------------
    152 # Return 1, if file is located in <valgrind>/include
    153 #---------------------------------------------------------------------
    154 sub is_coregrind_export_header {
    155     my ($path_name) = @_;
    156 
    157     return ($path_name =~ /^include\//) ? 1 : 0;
    158 }
    159 
    160 #---------------------------------------------------------------------
    161 # Return 1, if file is located underneath <valgrind>/coregrind
    162 #---------------------------------------------------------------------
    163 sub is_coregrind_file {
    164     my ($path_name) = @_;
    165 
    166     return ($path_name =~ /^coregrind\//) ? 1 : 0;
    167 }
    168 
    169 #---------------------------------------------------------------------
    170 # Return 1, if file is located underneath <valgrind>/<tool>
    171 #---------------------------------------------------------------------
    172 sub is_tool_file {
    173     my ($path_name) = @_;
    174 
    175     for my $tool (keys %tool_dirs) {
    176         return 1 if ($path_name =~ /^$tool\//);
    177     }
    178     return 0
    179 }
    180 
    181 #---------------------------------------------------------------------
    182 # Return array of files #include'd by file.
    183 #---------------------------------------------------------------------
    184 sub get_included_files {
    185     my ($path_name) = @_;
    186     my @includes = ();
    187     my $file = basename($path_name);
    188 
    189     open(FILE, "<$file") || die "Cannot open file '$file'";
    190 
    191     while (my $line = <FILE>) {
    192         if ($line =~ /^\s*#\s*include "([^"]*)"/) {
    193             push @includes, $1;
    194         }
    195         if ($line =~ /^\s*#\s*include <([^>]*)>/) {
    196             push @includes, $1;
    197         }
    198     }
    199     close FILE;
    200     return @includes;
    201 }
    202 
    203 #---------------------------------------------------------------------
    204 # Check a file from <valgrind>/include
    205 #---------------------------------------------------------------------
    206 sub check_coregrind_export_header {
    207     my ($path_name) = @_;
    208 
    209     foreach my $inc (get_included_files($path_name)) {
    210         $inc = basename($inc);
    211 # Must not include pub_core_....
    212         if ($inc =~ /pub_core_/) {
    213             error("File $path_name must not include $inc\n");
    214         }
    215 # Only pub_tool_clreq.h may include valgrind.h
    216         if (($inc eq "valgrind.h") && ($path_name ne "include/pub_tool_clreq.h")) {
    217             error("File $path_name should include pub_tool_clreq.h instead of $inc\n");
    218         }
    219     }
    220 }
    221 
    222 #---------------------------------------------------------------------
    223 # Check a file from <valgrind>/coregrind
    224 #---------------------------------------------------------------------
    225 sub check_coregrind_file {
    226     my ($path_name) = @_;
    227     my $file = basename($path_name);
    228 
    229     foreach my $inc (get_included_files($path_name)) {
    230         print "\tINCLUDE $inc\n" if ($debug);
    231 # Only pub_tool_xyzzy.h may include pub_core_xyzzy.h
    232         if ($inc =~ /pub_tool_/) {
    233             my $buddy = $inc;
    234             $buddy =~ s/pub_tool/pub_core/;
    235             if ($file ne $buddy) {
    236                 error("File $path_name must not include $inc\n");
    237             }
    238         }
    239 # Must not include valgrind.h
    240         if ($inc eq "valgrind.h") {
    241             error("File $path_name should include pub_core_clreq.h instead of $inc\n");
    242         }
    243     }
    244 }
    245 
    246 #---------------------------------------------------------------------
    247 # Check a file from <valgrind>/<tool>
    248 #---------------------------------------------------------------------
    249 sub check_tool_file {
    250     my ($path_name) = @_;
    251     my $file = basename($path_name);
    252 
    253     foreach my $inc (get_included_files($path_name)) {
    254         print "\tINCLUDE $inc\n" if ($debug);
    255 # Must not include pub_core_...
    256         if ($inc =~ /pub_core_/) {
    257             error("File $path_name must not include $inc\n");
    258         }
    259 # Must not include valgrind.h unless this is an export header
    260         if ($inc eq "valgrind.h" && ! $tool_export_header{$path_name}) {
    261             error("File $path_name should include pub_tool_clreq.h instead of $inc\n");
    262         }
    263     }
    264 }
    265 
    266 sub process_file {
    267     my ($path_name) = @_;
    268 
    269     print "FILE = $path_name\n" if ($debug);
    270 
    271     if (is_coregrind_export_header($path_name)) {
    272         check_coregrind_export_header($path_name);
    273     } elsif (is_coregrind_file($path_name)) {
    274         check_coregrind_file($path_name);
    275     } elsif (is_tool_file($path_name)) {
    276         check_tool_file($path_name);
    277     }
    278 }
    279 
    280 sub error {
    281     my ($message) = @_;
    282     print STDERR "*** $message";
    283     ++$num_errors;
    284 }
    285