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