#! /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 { 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-/)); }); } 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(\S+)$/; 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}); } }