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