X-Git-Url: https://git.jankratochvil.net/?p=nethome.git;a=blobdiff_plain;f=bin%2Fcheckstatic;h=8dc611a02a74bfdcbc4ca5e3bc1177b205de7162;hp=e525384060bf905aa660eb96ef97cf9c2d2726fe;hb=f1fd1da97405a124a824d3808d6bc59df1b16b9b;hpb=53597f24b007ce503dd7d22356c722cf0334f504 diff --git a/bin/checkstatic b/bin/checkstatic index e525384..8dc611a 100755 --- a/bin/checkstatic +++ b/bin/checkstatic @@ -1,38 +1,148 @@ -#! /bin/sh - -fis="${*:-*.o}" - -for i in $fis;do - rest="`echo '' $fis ''|sed "s# $i # #"`" - trail="()" - for t in T BCDRS;do - for sym in `nm $i|sed -n 's/^.* ['$t'] \(.*\)$/\1/p'`;do - if nm $rest|grep -q ' U '"$sym"'$';then :;else - echo "$i $sym$trail"|sed 's/\.o /.c /' - fi - done - trail="" - done -done - -echo - -function checkextern +#! /usr/bin/perl + +use strict; +use warnings; +use Cwd; +use Data::Dumper; +use Getopt::Long; + + +my(%symtab)=(); + +my $D; +my $opt_nm="nm"; +my $opt_headers=1; +die if !GetOptions( + "d|debug+",\$D, + "nm=s" ,\$opt_nm, + "headers!",\$opt_headers, + ); + + +sub defmiss +{ +my($ref,$missval,$sub)=@_; + + $$ref=$missval if !defined $$ref; + &{$sub}($ref); +} + +sub addsymtype +{ +my($slot,$type,$symref)=@_; + + defmiss(\$slot,{},sub { + my($typeref)=@_; + push(@{$$$typeref{$type}},$symref); + }); +} + +sub storesym { - ctags -f - --c-types=$1 `cvsfiles|grep '\.h$'` | \ - if $2;then - grep ' /\^extern ' - else - cat - fi \ - | while read -r line;do - sym="` echo "$line" | awk '{print $1}'`" - file="`echo "$line" | awk '{print $2}'`" - if nm $fis|grep -q " [$3] ""$sym"'$';then :;else - echo "extern $file $sym$4" - fi - done +my(%sym)=@_; + + $sym{"fn_c"}=~s#^$ENV{PWD}/#./# if defined $sym{"fn_c"}; + defmiss(\$symtab{$sym{"name"}},{},sub { + my($slotref)=@_; + my($type)=$sym{"type"}; + addsymtype($$slotref,$type,\%sym); + addsymtype($$slotref,$type,\%sym) + if ($type!~/nU/ && ($type=~s/(n)[[:upper:]]/$1+/ || $type=~s/(n)[[:lower:]]/$1-/)); + }); } -checkextern x true BCDRS "" -checkextern p false T "()" +open(NM,"-|",'find -name "*.o"|xargs -- '.$opt_nm.' -f posix --print-file-name --no-sort --line-numbers') + or die "Cannot get nm output: $!"; +while () { + chomp; + die "Line $. of nm output not recognized: $_" + # $1 $2 $3 $4 + if !/^([^:]*):\s*(\S*) (\w) [^\t]*(?:\t(.*))?$/; + storesym( + "fn_o"=>$1, + "name"=>$2, + "type"=>"n$3", + "fn_c"=>$4, + ); + } +close NM; + +if ($opt_headers) { + open(CTAGS,"-|",'find -name "*.h"|xargs ctags -f - --c-types=xp') + or die "Cannot get ctags output: $!"; + while () { + chomp; + die "Line $. of ctags output not recognized: $_" + # $1 $2 $3 + if !/^([^\t]*)\t([^\t]*)\t.*\t(\w)$/; + storesym( + "name"=>$1, + "fn_c"=>$2, + "type"=>"c$3", + ); + } + close CTAGS; + } + +print Data::Dumper->Dump([\%symtab],["%symtab"]) if $D; + +sub dumpsyms +{ +my($error,@arr)=@_; + + print("$error ".$arr[0]{"name"}.($arr[0]{"type"}=~/cp|n[tT]/ ? "()" : "").":\n"); + my($symref); + while ($symref=shift(@arr)) { + print("\t"); + if (defined($$symref{"fn_c"})) { + print($$symref{"fn_c"}); + print("\t(".$$symref{"fn_o"}.")") if defined $$symref{"fn_o"}; + } + else { + my($fn)=$$symref{"fn_o"}; + $fn=~s/\.o$/.c/; + print($fn); + } + print("\n"); + } +} + +sub refendef +{ +my($ref)=@_; + + return [] if !defined($ref); + return $ref; +} + +my($symname); +foreach $symname (sort keys %symtab) { + my($typesref)=$symtab{$symname}; + my($ref,$ref1,$ref2); + +# >=2 n[:upper:]\U symbols => global conflict + if (@{refendef($ref=$$typesref{"n+"})}>=2) { + dumpsyms("global conflict",@{$ref}); + } + +# >=1 n[:upper:]\U symbol && >=1 n[:lower:] symbol => local override + if (@{refendef($ref1=$$typesref{"n+"})}>=1 && @{refendef($ref2=$$typesref{"n-"})}>=1) { + dumpsyms("local override of global",@{$ref1}); + dumpsyms(" -- with local",@{$ref2}); + } + +# >=1 n[:upper:]\U symbol && ==0 nU symbol => global singularity + if (@{refendef($ref=$$typesref{"n+"})}>=1 && @{refendef($$typesref{"nU"})}==0) { + dumpsyms("global singularity",@{$ref}); + } + +# >=1 cx symbol && ==0 n[:upper:]\U symbol => floating extern data + if (@{refendef($ref=$$typesref{"cx"})}>=1 && @{refendef($$typesref{"n+"})}==0) { + dumpsyms("floating extern data",@{$ref}); + } + +# >=1 cp symbol && ==0 n[:upper:]\U symbol => floating extern func + if (@{refendef($ref=$$typesref{"cp"})}>=1 && @{refendef($$typesref{"n+"})}==0) { + dumpsyms("floating extern func",@{$ref}); + } + }