annotate kdiff3/admin/nmcheck @ 69:8febbfb1148c

KDiff3 0.9.89
author joachim99
date Mon, 10 Apr 2006 08:40:51 +0000
parents 415083d043f3
children
rev   line source
joachim99@14 1 #!/usr/bin/perl -w
joachim99@14 2
joachim99@14 3 # Check namespace cleanness of a library.
joachim99@14 4 # Allowed symbols are passed as arguments.
joachim99@14 5 # They may have trailing * = wildcard.
joachim99@14 6 # Wildcards may be also specified as *::* (e.g. K*::* for all KDE classes)
joachim99@14 7 # Symbols are listed as full function unmangled names without arguments,
joachim99@14 8 # e.g. 'foo bar* nspace::*' allows foo(), foo(int), bar(), barbar()
joachim99@14 9 # and all symbols in namespace/class nspace.
joachim99@14 10 # If an argument has comma in it, it's a filename of a file containing
joachim99@14 11 # allowed symbols, one per line.
joachim99@14 12
joachim99@14 13
joachim99@14 14 $thisProg = "$0"; # This programs name
joachim99@14 15
joachim99@14 16 $library = "";
joachim99@14 17 $allowed_symbols = "";
joachim99@14 18 $debug = 0;
joachim99@14 19 $allowed_weak = "";
joachim99@14 20 $weak_specified = 0;
joachim99@14 21
joachim99@14 22 while( defined( $ARGV[ 0 ] ))
joachim99@14 23 {
joachim99@14 24 $_ = shift;
joachim99@14 25 if( /^--verbose$|^-v$/ )
joachim99@14 26 {
joachim99@14 27 $debug = 1;
joachim99@14 28 }
joachim99@14 29 elsif( /^--help$|^-h$/ )
joachim99@14 30 {
joachim99@14 31 print STDOUT "Usage $thisProg [OPTION] ... library [allowed symbols] ...\n",
joachim99@14 32 "\n",
joachim99@14 33 "Check if the given library has only allowed public symbols.\n",
joachim99@14 34 "\n",
joachim99@14 35 " --allowweak=[symbol] allow only these weak symbols\n",
joachim99@14 36 " -v, --verbose verbosely list files processed\n",
joachim99@14 37 " -h, --help print this help, then exit\n";
joachim99@14 38 exit 0;
joachim99@14 39 }
joachim99@14 40 elsif( /^--allowweak=(.*)$/ )
joachim99@14 41 {
joachim99@14 42 $allowed_weak .= " " . $1;
joachim99@14 43 $weak_specified = 1;
joachim99@14 44 }
joachim99@14 45 elsif( /^--allowweak$/ ) # simply list all weak
joachim99@14 46 {
joachim99@14 47 $allowed_weak .= " ";
joachim99@14 48 $weak_specified = 1;
joachim99@14 49 }
joachim99@14 50 elsif( /^--*/ )
joachim99@14 51 {
joachim99@14 52 die "Invalid argument!\n";
joachim99@14 53 }
joachim99@14 54 else
joachim99@14 55 {
joachim99@14 56 if( ! $library )
joachim99@14 57 {
joachim99@14 58 $library = $_;
joachim99@14 59 }
joachim99@14 60 else
joachim99@14 61 {
joachim99@14 62 $allowed_symbols .= " " . $_;
joachim99@14 63 }
joachim99@14 64 }
joachim99@14 65 }
joachim99@14 66
joachim99@14 67 if( ! $weak_specified )
joachim99@14 68 {
joachim99@14 69 $allowed_weak = "*";
joachim99@14 70 # allow all weak symbols by default
joachim99@14 71 # instances of templates and similar stuff - unfortunately includes also things from other libraries,
joachim99@14 72 # so it cannot be on by default
joachim99@14 73 }
joachim99@14 74
joachim99@14 75 print STDERR "library:" . $library . "\n" if $debug;
joachim99@14 76 print STDERR "allowed_symbols:" . $allowed_symbols . "\n" if $debug;
joachim99@14 77 print STDERR "allowed_weak:" . $allowed_weak . "\n" if $debug;
joachim99@14 78
joachim99@14 79 $default_symbols = "_fini _init"; # system symbols
joachim99@14 80 # on my system, every .so has :
joachim99@14 81 # A _DYNAMIC
joachim99@14 82 # A _GLOBAL_OFFSET_TABLE_
joachim99@14 83 # A __bss_start
joachim99@14 84 # A _edata
joachim99@14 85 # A _end
joachim99@14 86 # T _fini
joachim99@14 87 # T _init
joachim99@14 88 # no need to list A symbols in $default_symbols
joachim99@14 89
joachim99@14 90 print STDERR "default_symbols: " . $default_symbols . "\n" if $debug;
joachim99@14 91
joachim99@14 92 print STDOUT "Namespace cleanness check for " . $library . " :\n";
joachim99@14 93
joachim99@14 94 $lib_file = "";
joachim99@14 95 if( $library =~ /\.la$/ )
joachim99@14 96 {
joachim99@14 97 # get the real library file from .la
joachim99@14 98 open( FILEIN, $library ) || die "Couldn't open $! !\n";
joachim99@14 99 while( $line = <FILEIN> )
joachim99@14 100 {
joachim99@14 101 if( $line =~ /library_names=\'([^ ]*).*/o )
joachim99@14 102 {
joachim99@14 103 $lib_file = $1;
joachim99@14 104 }
joachim99@14 105 }
joachim99@14 106 close( FILEIN );
joachim99@14 107 if( ! $lib_file )
joachim99@14 108 {
joachim99@14 109 print STDERR "Library file not found in .la file!\n";
joachim99@14 110 exit 1;
joachim99@14 111 }
joachim99@14 112 my $libpath = $library;
joachim99@14 113 $libpath =~ s%[^/]*$%%;
joachim99@14 114 if( -e $libpath . ".libs/" . $lib_file )
joachim99@14 115 {
joachim99@14 116 $lib_file = $libpath . ".libs/" . $lib_file;
joachim99@14 117 }
joachim99@14 118 else
joachim99@14 119 {
joachim99@14 120 $lib_file = $libpath . $lib_file;
joachim99@14 121 }
joachim99@14 122 }
joachim99@14 123 else
joachim99@14 124 {
joachim99@14 125 $lib_file = $library;
joachim99@14 126 }
joachim99@14 127
joachim99@14 128 print STDERR "libfile: ". $lib_file . "\n" if $debug;
joachim99@14 129
joachim99@14 130 $allowed_symbols .= " " . $default_symbols;
joachim99@14 131
joachim99@14 132 sub process_symbols($\@\%\@);
joachim99@14 133
joachim99@14 134 @wildcards = ();
joachim99@14 135 %exacts = ();
joachim99@14 136 @regwildcards = ();
joachim99@14 137 process_symbols( $allowed_symbols, @wildcards, %exacts, @regwildcards );
joachim99@14 138 @weak_wildcards = ();
joachim99@14 139 %weak_exacts = ();
joachim99@14 140 @weak_regwildcards = ();
joachim99@14 141 process_symbols( $allowed_weak, @weak_wildcards, %weak_exacts, @weak_regwildcards );
joachim99@14 142
joachim99@14 143 # grep is for stripping not exported symbols, which don't have address (=first column)
joachim99@14 144 $nm_command = "nm -BDCg " . $lib_file . " | grep -v '^ ' |";
joachim99@14 145
joachim99@14 146 # TODO how portable is this nmcheck stuff?
joachim99@14 147
joachim99@14 148 print STDERR "nm command:" . $nm_command . "\n" if $debug;
joachim99@14 149
joachim99@14 150 open( FILEIN, $nm_command ) || die "nm command failed\n";
joachim99@14 151
joachim99@14 152 my $exit_code = 0;
joachim99@14 153
joachim99@14 154 while( $line = <FILEIN> )
joachim99@14 155 {
joachim99@14 156 my $type;
joachim99@14 157 my $symbol;
joachim99@14 158 if( $line =~ /^[^ ]* (.) (.*)$/o )
joachim99@14 159 {
joachim99@14 160 $type = $1;
joachim99@14 161 $symbol = $2;
joachim99@14 162 }
joachim99@14 163 else
joachim99@14 164 {
joachim99@14 165 die "Invalid line: " . $line . "\n";
joachim99@14 166 }
joachim99@14 167
joachim99@14 168 print STDERR "Type: " . $type . " , symbol: " . $symbol . "\n" if $debug;
joachim99@14 169 if( $type eq "A" )
joachim99@14 170 { # these should be system symbols, so ignore them
joachim99@14 171 next;
joachim99@14 172 }
joachim99@14 173
joachim99@14 174 my $orig_symbol = $symbol;
joachim99@14 175
joachim99@14 176 if( $symbol =~ /\(anonymous namespace\)/o )
joachim99@14 177 { # TODO tell to prefer named namespaces? (shorter symbols)
joachim99@14 178 next;
joachim99@14 179 }
joachim99@14 180
joachim99@14 181 # strip prefixes
joachim99@14 182 # the :: appending is to make "CLASS::*" work also for "vtable for CLASS"
joachim99@14 183 $symbol =~ s/^typeinfo for (.*)$/$1::/o;
joachim99@14 184 $symbol =~ s/^typeinfo fn for (.*)$/$1::/o;
joachim99@14 185 $symbol =~ s/^typeinfo name for (.*)$/$1::/o;
joachim99@14 186 $symbol =~ s/^vtable for (.*)$/$1::/o;
joachim99@14 187 $symbol =~ s/^guard variable for (.*)$/$1::/o;
joachim99@14 188 $symbol =~ s/^reference temporary for (.*)$/$1::/o;
joachim99@14 189 $symbol =~ s/^VTT for (.*)$/$1::/o;
joachim99@14 190 $symbol =~ s/^virtual thunk \[[^\]]*\] to (.*)$/$1::/o;
joachim99@14 191 $symbol =~ s/^non-virtual thunk \[[^\]]*\] to (.*)$/$1::/o;
joachim99@14 192 $symbol =~ s/^covariant return thunk \[[^\]]*\] to (.*)$/$1::/o;
joachim99@14 193 $symbol =~ s/^construction vtable thunk for (.*)$/$1::/o;
joachim99@14 194 $symbol =~ s/^construction vtable for .*-in-(.*) [0-9]*$/$1::/o;
joachim99@14 195
joachim99@14 196 # templates seem to have also return types mangled in their name, and nm prints it too
joachim99@14 197 # they have also template arguments in the symbol
joachim99@14 198 # get rid of both of those
joachim99@14 199 while( $symbol =~ /<.*>/o )
joachim99@14 200 {
joachim99@14 201 $symbol =~ s/<[^<>]*>//o; # strip innermost <>
joachim99@14 202 }
joachim99@14 203 if( $symbol !~ /operator\(\)/o )
joachim99@14 204 {
joachim99@14 205 $symbol =~ s/ ?\(.*\).*$//o; # strip () and all after it
joachim99@14 206 }
joachim99@14 207 else
joachim99@14 208 {
joachim99@14 209 $symbol =~ s/(^|:| )operator\(\) ?\(.*\).*$//o; # strip () and all after it
joachim99@14 210 }
joachim99@14 211 $symbol =~ s/\[.*\] *$//o; # strip [in-charge] etc.
joachim99@14 212 if( $symbol =~ /(^|:| )operator /o )
joachim99@14 213 {
joachim99@14 214 $symbol =~ s/.* ([^\s]*)operator /$1/o; # strip everything before 'X::operator blah'
joachim99@14 215 }
joachim99@14 216 else
joachim99@14 217 {
joachim99@14 218 $symbol =~ s/.* ([^\s]+) *$/$1/o; # get last word (strip return type)
joachim99@14 219 }
joachim99@14 220
joachim99@14 221 # print STDERR "Processed symbol: " . $symbol . "\n" if $debug;
joachim99@14 222
joachim99@14 223 my $found = 0;
joachim99@14 224 if( $exacts{ $symbol } )
joachim99@14 225 {
joachim99@14 226 $found = 1;
joachim99@14 227 }
joachim99@14 228 if( ! $found )
joachim99@14 229 {
joachim99@14 230 for my $wild ( @wildcards )
joachim99@14 231 {
joachim99@14 232 if( index( $symbol, $wild ) == 0 )
joachim99@14 233 {
joachim99@14 234 $found = 1;
joachim99@14 235 last;
joachim99@14 236 }
joachim99@14 237 }
joachim99@14 238 }
joachim99@14 239 if( ! $found )
joachim99@14 240 {
joachim99@14 241 for my $wild ( @regwildcards )
joachim99@14 242 {
joachim99@14 243 if( $symbol =~ /^$wild$/ )
joachim99@14 244 {
joachim99@14 245 $found = 1;
joachim99@14 246 last;
joachim99@14 247 }
joachim99@14 248 }
joachim99@14 249 }
joachim99@14 250 if( ( ! $found ) && ( $type eq "W" || $type eq "V" ))
joachim99@14 251 {
joachim99@14 252 if( $weak_exacts{ $symbol } )
joachim99@14 253 {
joachim99@14 254 $found = 1;
joachim99@14 255 }
joachim99@14 256 if( ! $found )
joachim99@14 257 {
joachim99@14 258 for my $wild ( @weak_wildcards )
joachim99@14 259 {
joachim99@14 260 if( index( $symbol, $wild ) == 0 )
joachim99@14 261 {
joachim99@14 262 $found = 1;
joachim99@14 263 last;
joachim99@14 264 }
joachim99@14 265 }
joachim99@14 266 }
joachim99@14 267 if( ! $found )
joachim99@14 268 {
joachim99@14 269 for my $wild ( @weak_regwildcards )
joachim99@14 270 {
joachim99@14 271 if( $symbol =~ /^$wild$/ )
joachim99@14 272 {
joachim99@14 273 $found = 1;
joachim99@14 274 last;
joachim99@14 275 }
joachim99@14 276 }
joachim99@14 277 }
joachim99@14 278 }
joachim99@14 279
joachim99@14 280 if( ! $found )
joachim99@14 281 {
joachim99@14 282 print STDERR "Public symbol " . $orig_symbol . " is not allowed!\n";
joachim99@14 283 $exit_code = 1;
joachim99@14 284 }
joachim99@14 285 }
joachim99@14 286
joachim99@14 287 close( FILEIN );
joachim99@14 288
joachim99@14 289 print STDOUT $exit_code == 0 ? "OK\n" : "FAILED\n";
joachim99@14 290
joachim99@14 291 exit $exit_code;
joachim99@14 292
joachim99@14 293 sub process_symbols($\@\%\@)
joachim99@14 294 {
joachim99@14 295 my $allowed_symbols = $_[ 0 ];
joachim99@14 296 my $wildcards_ref = $_[ 1 ];
joachim99@14 297 my $exacts_ref = $_[ 2 ];
joachim99@14 298 my $regwildcards_ref = $_[ 3 ];
joachim99@14 299
joachim99@14 300 $allowed_symbols =~ s/^ *//o; # strip whitespace
joachim99@14 301 $allowed_symbols =~ s/ *$//o;
joachim99@14 302
joachim99@14 303 if( $allowed_symbols eq "NONE" )
joachim99@14 304 {
joachim99@14 305 $allowed_symbols = "";
joachim99@14 306 }
joachim99@14 307
joachim99@14 308 my @symbols1 = split( ' ', $allowed_symbols );
joachim99@14 309 my $i = 0;
joachim99@14 310 my @symbols2 = ();
joachim99@14 311 while( defined( $symbols1[ $i ] ))
joachim99@14 312 {
joachim99@14 313 my $symbol = $symbols1[ $i ];
joachim99@14 314 if( $symbol =~ /\./ ) # dot in name -> file
joachim99@14 315 {
joachim99@14 316 open( SYMIN, $symbol ) || die ( "Cannot open file " . $symbol . "!" );
joachim99@14 317 while( $line = <SYMIN> )
joachim99@14 318 {
joachim99@14 319 $line =~ s/^\s*//o; # strip whitespace
joachim99@14 320 $line =~ s/\s*$//o;
joachim99@14 321 if( $line !~ /^$/o # empty line
joachim99@14 322 && $line !~ /^\s*#/ ) # comment line starting with #
joachim99@14 323 {
joachim99@14 324 $symbols2[ $#symbols2 + 1 ] = $line;
joachim99@14 325 }
joachim99@14 326 }
joachim99@14 327 close( SYMIN );
joachim99@14 328 }
joachim99@14 329 else
joachim99@14 330 {
joachim99@14 331 $symbols2[ $#symbols2 + 1 ] = $symbol;
joachim99@14 332 }
joachim99@14 333 $i++;
joachim99@14 334 }
joachim99@14 335 $i = 0;
joachim99@14 336 while( defined( $symbols2[ $i ] ))
joachim99@14 337 {
joachim99@14 338 my $symbol = $symbols2[ $i ];
joachim99@14 339 if( $symbol =~ /__/
joachim99@14 340 || $symbol =~ /^_[A-Z]/ )
joachim99@14 341 { # ISO C++ 2.10.2
joachim99@14 342 die "Symbols containing a double underscore or beginning with an underscore and an upper-case letter are reserved!\n";
joachim99@14 343 }
joachim99@14 344 elsif( $symbol eq "main"
joachim99@14 345 || $symbol eq "main*" )
joachim99@14 346 {
joachim99@14 347 die "Symbol main is not allowed!\n";
joachim99@14 348 }
joachim99@14 349 if( $symbol =~ /^([^\*]*)\*$/o # trailing * without any * before it
joachim99@14 350 && $symbol !~ /operator\*$/o )
joachim99@14 351 {
joachim99@14 352 print STDERR "wildcard:" . $symbol . "\n" if $debug;
joachim99@14 353 $wildcards_ref->[ $#{$wildcards_ref} + 1 ] = $1;
joachim99@14 354 }
joachim99@14 355 elsif( $symbol =~ /\*$/o
joachim99@14 356 && ( $symbol =~ /\*::/o || $symbol =~ /::\*/o )
joachim99@14 357 && $symbol !~ /^\*/o
joachim99@14 358 && $symbol !~ /operator\*$/o )
joachim99@14 359 {
joachim99@14 360 print STDERR "regwildcard:" . $symbol . "\n" if $debug;
joachim99@14 361 $symbol =~ s/\*/\.\*/go; # change * to .* (regexp)
joachim99@14 362 $regwildcards_ref->[ $#{$regwildcards_ref} + 1 ] = $symbol;
joachim99@14 363 }
joachim99@14 364 else
joachim99@14 365 {
joachim99@14 366 print STDERR "exact:" . $symbol . "\n" if $debug;
joachim99@14 367 $exacts_ref->{ $symbol } = 1;
joachim99@14 368 }
joachim99@14 369 $i++;
joachim99@14 370 }
joachim99@14 371 }