mirror of
https://github.com/ioacademy-jikim/debugging
synced 2025-06-07 16:06:09 +00:00
328 lines
9.1 KiB
Perl
Executable File
328 lines
9.1 KiB
Perl
Executable File
#!/usr/bin/env perl
|
|
|
|
#-------------------------------------------------------------------
|
|
# Check header files and #include directives
|
|
#
|
|
# (1) include/*.h must not include pub_core_...h
|
|
# (2) coregrind/pub_core_xyzzy.h may include pub_tool_xyzzy.h
|
|
# other coregrind headers may not include pub_tool_xyzzy.h
|
|
# (3) coregrind/ *.c must not include pub_tool_xyzzy.h
|
|
# (4) tool *.[ch] files must not include pub_core_...h
|
|
# (5) include pub_core/tool_clreq.h instead of valgrind.h except in tools'
|
|
# export headers
|
|
# (6) coregrind/ *.[ch] must not use tl_assert
|
|
# (7) include/*.h and tool *.[ch] must not use vg_assert
|
|
# (8) coregrind/ *.[ch] must not use VG_(tool_panic)
|
|
# (9) include/*.h and tool *.[ch] must not use VG_(core_panic)
|
|
#-------------------------------------------------------------------
|
|
|
|
use strict;
|
|
use warnings;
|
|
use File::Basename;
|
|
use Getopt::Long;
|
|
|
|
my $this_script = basename($0);
|
|
|
|
# The list of top-level directories is divided into three sets:
|
|
#
|
|
# (1) coregrind directories
|
|
# (2) tool directories
|
|
# (3) directories to ignore
|
|
#
|
|
# If a directory is found that does not belong to any of those sets, the
|
|
# script will terminate unsuccessfully.
|
|
|
|
my %coregrind_dirs = (
|
|
"include" => 1,
|
|
"coregrind" => 1,
|
|
);
|
|
|
|
my %tool_dirs = (
|
|
"none" => 1,
|
|
"lackey" => 1,
|
|
"massif" => 1,
|
|
"memcheck" => 1,
|
|
"drd" => 1,
|
|
"helgrind", => 1,
|
|
"callgrind" => 1,
|
|
"cachegrind" => 1,
|
|
"shared" => 1,
|
|
"exp-bbv" => 1,
|
|
"exp-dhat" => 1,
|
|
"exp-sgcheck" => 1
|
|
);
|
|
|
|
my %dirs_to_ignore = (
|
|
".deps" => 1,
|
|
".svn" => 1,
|
|
".git" => 1, # allow git mirrors of the svn repo
|
|
".in_place" => 1,
|
|
"Inst" => 1, # the nightly scripts creates this
|
|
"VEX" => 1,
|
|
"docs" => 1,
|
|
"auxprogs" => 1,
|
|
"autom4te.cache" => 1,
|
|
"nightly" => 1,
|
|
"perf" => 1,
|
|
"tests" => 1,
|
|
"gdbserver_tests" => 1,
|
|
"mpi" => 1,
|
|
"solaris" => 1
|
|
);
|
|
|
|
my %tool_export_header = (
|
|
"drd/drd.h" => 1,
|
|
"helgrind/helgrind.h" => 1,
|
|
"memcheck/memcheck.h" => 1,
|
|
"callgrind/callgrind.h" => 1
|
|
);
|
|
|
|
my $usage=<<EOF;
|
|
USAGE
|
|
|
|
$this_script
|
|
|
|
[--debug] Debugging output
|
|
|
|
dir ... Directories to process
|
|
EOF
|
|
|
|
my $debug = 0;
|
|
my $num_errors = 0;
|
|
|
|
&main;
|
|
|
|
sub main {
|
|
GetOptions( "debug" => \$debug ) || die $usage;
|
|
|
|
my $argc = $#ARGV + 1;
|
|
|
|
if ($argc < 1) {
|
|
die $usage;
|
|
}
|
|
|
|
foreach my $dir (@ARGV) {
|
|
process_dir(undef, $dir, 0);
|
|
}
|
|
|
|
my $rc = ($num_errors == 0) ? 0 : 1;
|
|
exit $rc;
|
|
}
|
|
|
|
sub process_dir {
|
|
my ($path, $dir, $depth) = @_;
|
|
my $hdir;
|
|
|
|
if ($depth == 0) {
|
|
# The root directory is always processed
|
|
} elsif ($depth == 1) {
|
|
# Toplevel directories
|
|
return if ($dirs_to_ignore{$dir});
|
|
|
|
if (! $tool_dirs{$dir} && ! $coregrind_dirs{$dir}) {
|
|
die "Unknown directory '$dir'. Please update $this_script\n";
|
|
}
|
|
} else {
|
|
# Subdirectories
|
|
return if ($dirs_to_ignore{$dir});
|
|
}
|
|
|
|
print "DIR = $dir DEPTH = $depth\n" if ($debug);
|
|
|
|
chdir($dir) || die "Cannot chdir '$dir'\n";
|
|
|
|
opendir($hdir, ".") || die "cannot open directory '.'";
|
|
|
|
while (my $file = readdir($hdir)) {
|
|
next if ($file eq ".");
|
|
next if ($file eq "..");
|
|
|
|
# Subdirectories
|
|
if (-d $file) {
|
|
my $full_path = defined $path ? "$path/$file" : $file;
|
|
process_dir($full_path, $file, $depth + 1);
|
|
next;
|
|
}
|
|
|
|
# Regular files; only interested in *.c and *.h
|
|
next if (! ($file =~ /\.[ch]$/));
|
|
my $path_name = defined $path ? "$path/$file" : $file;
|
|
process_file($path_name);
|
|
}
|
|
close($hdir);
|
|
chdir("..") || die "Cannot chdir '..'\n";
|
|
}
|
|
|
|
#---------------------------------------------------------------------
|
|
# Return 1, if file is located in <valgrind>/include
|
|
#---------------------------------------------------------------------
|
|
sub is_coregrind_export_header {
|
|
my ($path_name) = @_;
|
|
|
|
return ($path_name =~ /^include\//) ? 1 : 0;
|
|
}
|
|
|
|
#---------------------------------------------------------------------
|
|
# Return 1, if file is located underneath <valgrind>/coregrind
|
|
#---------------------------------------------------------------------
|
|
sub is_coregrind_file {
|
|
my ($path_name) = @_;
|
|
|
|
return ($path_name =~ /^coregrind\//) ? 1 : 0;
|
|
}
|
|
|
|
#---------------------------------------------------------------------
|
|
# Return 1, if file is located underneath <valgrind>/<tool>
|
|
#---------------------------------------------------------------------
|
|
sub is_tool_file {
|
|
my ($path_name) = @_;
|
|
|
|
for my $tool (keys %tool_dirs) {
|
|
return 1 if ($path_name =~ /^$tool\//);
|
|
}
|
|
return 0
|
|
}
|
|
|
|
#---------------------------------------------------------------------
|
|
# Return array of files #include'd by file.
|
|
#---------------------------------------------------------------------
|
|
sub get_included_files {
|
|
my ($path_name) = @_;
|
|
my @includes = ();
|
|
my $file = basename($path_name);
|
|
|
|
open(FILE, "<$file") || die "Cannot open file '$file'";
|
|
|
|
while (my $line = <FILE>) {
|
|
if ($line =~ /^\s*#\s*include "([^"]*)"/) {
|
|
push @includes, $1;
|
|
}
|
|
if ($line =~ /^\s*#\s*include <([^>]*)>/) {
|
|
push @includes, $1;
|
|
}
|
|
}
|
|
close FILE;
|
|
return @includes;
|
|
}
|
|
|
|
#---------------------------------------------------------------------
|
|
# Check a file from <valgrind>/include
|
|
#---------------------------------------------------------------------
|
|
sub check_coregrind_export_header {
|
|
my ($path_name) = @_;
|
|
my $file = basename($path_name);
|
|
|
|
foreach my $inc (get_included_files($path_name)) {
|
|
$inc = basename($inc);
|
|
# Must not include pub_core_....
|
|
if ($inc =~ /pub_core_/) {
|
|
error("File $path_name must not include $inc\n");
|
|
}
|
|
# Only pub_tool_clreq.h may include valgrind.h
|
|
if (($inc eq "valgrind.h") && ($path_name ne "include/pub_tool_clreq.h")) {
|
|
error("File $path_name should include pub_tool_clreq.h instead of $inc\n");
|
|
}
|
|
}
|
|
# Must not use vg_assert
|
|
my $assert = `grep vg_assert $file`;
|
|
if ($assert ne "") {
|
|
error("File $path_name must not use vg_assert\n");
|
|
}
|
|
# Must not use VG_(core_panic)
|
|
my $panic = `grep 'VG_(core_panic)' $file`;
|
|
if ($panic ne "") {
|
|
error("File $path_name must not use VG_(core_panic)\n");
|
|
}
|
|
}
|
|
|
|
#---------------------------------------------------------------------
|
|
# Check a file from <valgrind>/coregrind
|
|
#---------------------------------------------------------------------
|
|
sub check_coregrind_file {
|
|
my ($path_name) = @_;
|
|
my $file = basename($path_name);
|
|
|
|
foreach my $inc (get_included_files($path_name)) {
|
|
print "\tINCLUDE $inc\n" if ($debug);
|
|
# Only pub_tool_xyzzy.h may include pub_core_xyzzy.h
|
|
if ($inc =~ /pub_tool_/) {
|
|
my $buddy = $inc;
|
|
$buddy =~ s/pub_tool/pub_core/;
|
|
if ($file ne $buddy) {
|
|
error("File $path_name must not include $inc\n");
|
|
}
|
|
}
|
|
# Must not include valgrind.h
|
|
if ($inc eq "valgrind.h") {
|
|
error("File $path_name should include pub_core_clreq.h instead of $inc\n");
|
|
}
|
|
}
|
|
# Must not use tl_assert
|
|
my $assert = `grep tl_assert $file`;
|
|
if ($assert ne "") {
|
|
error("File $path_name must not use tl_assert\n");
|
|
}
|
|
# Must not use VG_(tool_panic)
|
|
my $panic = `grep 'VG_(tool_panic)' $file`;
|
|
if ($panic ne "") {
|
|
chomp($panic);
|
|
# Do not complain about the definition of VG_(tool_panic)
|
|
if (($path_name eq "coregrind/m_libcassert.c") &&
|
|
($panic eq "void VG_(tool_panic) ( const HChar* str )")) {
|
|
# OK
|
|
} else {
|
|
error("File $path_name must not use VG_(tool_panic)\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
#---------------------------------------------------------------------
|
|
# Check a file from <valgrind>/<tool>
|
|
#---------------------------------------------------------------------
|
|
sub check_tool_file {
|
|
my ($path_name) = @_;
|
|
my $file = basename($path_name);
|
|
|
|
foreach my $inc (get_included_files($path_name)) {
|
|
print "\tINCLUDE $inc\n" if ($debug);
|
|
# Must not include pub_core_...
|
|
if ($inc =~ /pub_core_/) {
|
|
error("File $path_name must not include $inc\n");
|
|
}
|
|
# Must not include valgrind.h unless this is an export header
|
|
if ($inc eq "valgrind.h" && ! $tool_export_header{$path_name}) {
|
|
error("File $path_name should include pub_tool_clreq.h instead of $inc\n");
|
|
}
|
|
}
|
|
# Must not use vg_assert
|
|
my $assert = `grep vg_assert $file`;
|
|
if ($assert ne "") {
|
|
error("File $path_name must not use vg_assert\n");
|
|
}
|
|
# Must not use VG_(core_panic)
|
|
my $panic = `grep 'VG_(core_panic)' $file`;
|
|
if ($panic ne "") {
|
|
error("File $path_name must not use VG_(core_panic)\n");
|
|
}
|
|
}
|
|
|
|
sub process_file {
|
|
my ($path_name) = @_;
|
|
|
|
print "FILE = $path_name\n" if ($debug);
|
|
|
|
if (is_coregrind_export_header($path_name)) {
|
|
check_coregrind_export_header($path_name);
|
|
} elsif (is_coregrind_file($path_name)) {
|
|
check_coregrind_file($path_name);
|
|
} elsif (is_tool_file($path_name)) {
|
|
check_tool_file($path_name);
|
|
}
|
|
}
|
|
|
|
sub error {
|
|
my ($message) = @_;
|
|
print STDERR "*** $message";
|
|
++$num_errors;
|
|
}
|