openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

lmsc.pl (7329B)


      1 #!/usr/bin/perl
      2 # 
      3 #
      4 # This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      5 # 
      6 # Copyright 2007-2019 Broadcom Inc. All rights reserved.
      7 # 
      8 ################################################################################
      9 #
     10 # lmsc.pl
     11 #
     12 # Linux Module Symbol Checker
     13 #
     14 # Look for all undefined or non-exported symbols in the given set of files. 
     15 # 
     16 
     17 
     18 sub help
     19   {
     20     print "Linux Module Symbol Checker\n\n"; 
     21     print "  Check for undefined symbols between a group modules.\n";
     22     print "  Can be used to detect link errors which will occur at insmod time\n"; 
     23     print "  and verify the expected link dependencies between them.\n"; 
     24     print "  Any symbols which cannot be linked between the set of given files\n"; 
     25     print "  will be displayed.\n\n"; 
     26     print "Usage: lmsc.pl [option=value]* <file0> <file1> <file2> ...\n"; 
     27     print "       lmsc.pl [option=value]* <file0>,<file1>,<file2> <file1,file10> ..\n"; 
     28     print "  Options:\n"; 
     29     print "    kernel=<filename>    This image is included in all file sets.\n"; 
     30     print "    ferror=<num>         Specify exit code when files cannot be found.\n";
     31     print "                         Allows recovery in makefiles.\n";
     32     exit(2); 
     33   }
     34       
     35     
     36 use File::Basename; 
     37 
     38 #
     39 # File aliases. Mainly used to reference kernel images
     40 #
     41 my $KERN_PATH="/projects/ntsw-sw/linux/kernels";
     42 my $KERN_BASE="$KERN_PATH/vmlinux";
     43 my $KERN_TOOLS_PATH="/projects/ntsw-tools/linux/kernels";
     44 my $KERN_TOOLS_BASE="$KERN_TOOLS_PATH/vmlinux";
     45 my $KERN_REL=`uname -r`; 
     46 
     47 # Strip trailing whitespace
     48 $KERN_REL =~ s/\s+$//;
     49 
     50 my %ALIASES = (
     51     "bmw-2_6", "$KERN_BASE.bmw-2.6wrs",
     52     "gto-2_6", "$KERN_BASE.gto-2.6wrs",
     53     "gto-2_6-wr30", "$KERN_BASE.gto-2.6wrs30",
     54     "gto", "$KERN_BASE.gto",
     55     "gtr-3_7", "$KERN_PATH/wrx/xlp316/vmlinux",
     56     "gtx-2_6", "$KERN_BASE.gtx-2.6wrl",
     57     "iproc-2_6", "$KERN_TOOLS_PATH/../iproc_ldks/ldk26/iproc/kernel/linux-custom/vmlinux",
     58     "iproc-3_6", "$KERN_TOOLS_PATH/../iproc_ldks/ldk36/iproc/kernel/linux-custom/vmlinux",
     59     "iproc-4_4", "$KERN_TOOLS_PATH/../iproc_ldks/xldk40/XLDK/kernel/linux/vmlinux",
     60     "iproc", "$KERN_TOOLS_PATH/../iproc_ldks/iproc/XLDK32/kernel/linux/vmlinux",
     61     "iproc_64", "$KERN_TOOLS_PATH/../iproc_ldks/iproc/XLDK64/kernel/linux/vmlinux",
     62     "jag", "$KERN_BASE.jag",
     63     "jag-2_6", "$KERN_BASE.jag-2.6wrs",
     64     "keystone-2_6", "$KERN_BASE.key_be-26wrs",
     65     "keystone_le-2_6", "$KERN_BASE.key_le-26wrs",
     66     "nsx", "$KERN_TOOLS_BASE.nsx",
     67     "nsx-2_6", "$KERN_BASE.nsx-2.6",
     68     "nsx_wrl-2_6", "$KERN_BASE.nsx-2.6wrs",
     69     "raptor", "$KERN_BASE.raptor",
     70     "raptor-2_6", "$KERN_BASE.raptor-2.6wrs",
     71     "wrx-3_7", "$KERN_PATH/wrx/xlp208/vmlinux",
     72     "x86-generic-2_6", "/lib/modules/$KERN_REL/source/vmlinux",
     73     "x86-generic_64-2_6", "/lib/modules/$KERN_REL/source/vmlinux",
     74     "x86-smp_generic-2_6", "/lib/modules/$KERN_REL/source/vmlinux",
     75     "x86-smp_generic_64-2_6", "/lib/modules/$KERN_REL/source/vmlinux",
     76 );
     77                
     78 #
     79 # All of the sets of files which require dependency/link checking
     80 #
     81 my @FILESETS; 
     82 
     83 #
     84 # All defined symbols, by file
     85 my %DEFINED; 
     86 
     87 #
     88 # All undefined symbols, by file
     89 #
     90 my %UNDEFINED;
     91 
     92 
     93 #
     94 # Simple command line options
     95 #
     96 my @FILES; 
     97 my $KERNEL; 
     98 my $FERROR = -1; 
     99 
    100 if(@ARGV==0) {
    101   help(); 
    102 }
    103 
    104 foreach (@ARGV) {
    105   if(/kernel=(.*)/) {
    106     # Specifies a kernel name that should be prepended to all sets
    107     $KERNEL = $1; 
    108     next;
    109   }
    110   if(/ferror=(.*)/) {
    111     # Override exit code if file does not exist
    112     $FERROR=$1; 
    113     next; 
    114   }
    115   if(/^(--help|-h|--h|help)/) {
    116     help(); 
    117   }
    118 
    119   push @FILES, $_; 
    120 }
    121 
    122 #
    123 # A single set of files can be specified as "file0 file1 file2..." on the command line. 
    124 # Multiple sets of files can be specified as "file0,file1,file2 file0,file2,file3..." on the command line. 
    125 # 
    126 
    127 if((grep { /,/ } @FILES) == 0) {
    128   # Assume all arguments are in the same fileset  
    129   push @FILESETS, join(",", @FILES); 
    130 }
    131 else {
    132   # Each argument represents a separate fileset
    133   push @FILESETS, @FILES;   
    134 }
    135 
    136 #
    137 # Add the kernel image if specified
    138 #
    139 if(defined($KERNEL)) {
    140   map { $_ = "$KERNEL,$_"; } @FILESETS; 
    141 }
    142 
    143 
    144 
    145 #
    146 # Load all file symbols
    147 #
    148 load_all_symbols(); 
    149 
    150 
    151 #
    152 # Check all filesets and set exit code
    153 #
    154 exit(check_all()); 
    155 
    156 
    157 ################################################################################
    158 
    159 #
    160 # Check for filename aliases
    161 #
    162 sub alias
    163   {
    164     my $file = shift; 
    165     return defined($ALIASES{$file}) ? $ALIASES{$file} : $file; 
    166   }
    167     
    168 
    169 #
    170 # Check All Filesets
    171 #
    172 sub check_all
    173   {
    174     my $count; 
    175     foreach my $fs (@FILESETS) {
    176       $count += check_fs(split /,/,$fs); 
    177     }
    178     return $count == 0 ? 0 : -1; 
    179   }
    180 
    181 #
    182 # Check a single fileset
    183 #
    184 sub check_fs
    185   {
    186     my @files = @_; 
    187 
    188     my @defined; 
    189 
    190     # Get all defined symbols for this fileset
    191     foreach (@files) {
    192       push @defined, @{$DEFINED{alias($_)}}; 
    193     }
    194     
    195     # Check 
    196     my @pfiles = map { basename($_); } @files; 
    197     printf("Link Check: @pfiles: "); 
    198     my $count = 0; 
    199 
    200     foreach my $file (@files) {
    201       foreach my $sym (@{$UNDEFINED{$file}}) {
    202         if($sym =~ /^__crc_(.+)/) {
    203           $sym = $1; 
    204         } 
    205 
    206         if((grep { $_ eq $sym } @defined) == 0) {
    207           printf("\n    *** %s: $sym", basename($file)); 
    208           $count++;
    209         }
    210       }
    211     }
    212 
    213     if($count == 0) {
    214       printf("OK"); 
    215     }
    216     printf("\n"); 
    217     return $count; 
    218   }
    219 
    220 
    221 #
    222 # Load all defined and undefined symbols for a file
    223 #
    224 sub load_all_symbols
    225   {    
    226     foreach my $fs (@FILESETS) {
    227       foreach my $file (split /,/, $fs) {
    228         
    229         #
    230         # Check for aliases
    231         #
    232         $file = alias($file); 
    233         
    234         # Load the defined symbols if we haven't already
    235         if(!defined($DEFINED{$file})) {
    236 
    237           #
    238           # File exist?
    239           #
    240           if(!(-e $file)) {
    241             printf("Warning: Cannot find file '$file'. Link check not performed.\n"); 
    242             exit($FERROR); 
    243           }
    244 
    245           #
    246           # Get all defined symbols
    247           #   
    248           my @defined = nm($file, "--defined-only"); 
    249     
    250           # 
    251           # If these are 2.6 modules, only the ksymtab symbols are actually available for linking. 
    252           #
    253           if(grep { /__ksymtab_/ } @defined) {
    254             @defined = grep { s/__ksymtab_// } @defined; 
    255           }
    256           
    257           $DEFINED{$file} = \@defined; 
    258         }
    259 
    260         # Load the undefined symbols if we haven't already
    261         if(!defined($UNDEFINED{$file})) {
    262           my @undefined = nm($file, "--undefined-only"); 
    263           $UNDEFINED{$file} = \@undefined;        
    264         }
    265       }
    266     }
    267   }
    268 
    269 #
    270 # Use 'nm' to retrieve symbols
    271 #
    272 sub nm
    273   {
    274     my ($file, @flags) = @_; 
    275 
    276     my @symbols; 
    277     
    278     foreach my $nm_output (`/tools/bin/nm @flags $file`) {
    279       my @lines = split(/\n/, $nm_output);
    280       foreach(@lines) {
    281         @str = split / / ;
    282         $symbol = $str[$#str];
    283         
    284         # Magic symbols
    285         if($symbol =~ /(__start|__stop)___kallsyms/) {
    286           next;
    287         }
    288         if($symbol =~ /__this_module/) {
    289           next;
    290         }
    291         if($symbol =~ /__stack_chk_/) {
    292           next;
    293         }
    294         if($symbol =~ /mcount/) {
    295           next;
    296         }
    297         push @symbols, $symbol;
    298       }
    299     }
    300     chomp @symbols;
    301     return @symbols;
    302   }
    303