Blame view
scripts/namespace.pl
13 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
#!/usr/bin/perl -w # # namespace.pl. Mon Aug 30 2004 # # Perform a name space analysis on the linux kernel. # # Copyright Keith Owens <kaos@ocs.com.au>. GPL. # # Invoke by changing directory to the top of the kernel object # tree then namespace.pl, no parameters. # # Tuned for 2.1.x kernels with the new module handling, it will # work with 2.0 kernels as well. # # Last change 2.6.9-rc1, adding support for separate source and object # trees. # # The source must be compiled/assembled first, the object files # are the primary input to this script. Incomplete or missing # objects will result in a flawed analysis. Compile both vmlinux # and modules. # # Even with complete objects, treat the result of the analysis # with caution. Some external references are only used by # certain architectures, others with certain combinations of # configuration parameters. Ideally the source should include # something like # # #ifndef CONFIG_... # static # #endif # symbol_definition; # # so the symbols are defined as static unless a particular # CONFIG_... requires it to be external. # # A symbol that is suffixed with '(export only)' has these properties # # * It is global. # * It is marked EXPORT_SYMBOL or EXPORT_SYMBOL_GPL, either in the same # source file or a different source file. # * Given the current .config, nothing uses the symbol. # # The symbol is a candidate for conversion to static, plus removal of the # export. But be careful that a different .config might use the symbol. # # # Name space analysis and cleanup is an iterative process. You cannot # expect to find all the problems in a single pass. # # * Identify possibly unnecessary global declarations, verify that they # really are unnecessary and change them to static. # * Compile and fix up gcc warnings about static, removing dead symbols # as necessary. # * make clean and rebuild with different configs (especially # CONFIG_MODULES=n) to see which symbols are being defined when the # config does not require them. These symbols bloat the kernel object # for no good reason, which is frustrating for embedded systems. # * Wrap config sensitive symbols in #ifdef CONFIG_foo, as long as the # code does not get too ugly. # * Repeat the name space analysis until you can live with with the # result. # require 5; # at least perl 5 use strict; use File::Find; |
3a25f0b19 kbuild: make name... |
68 69 |
my $nm = ($ENV{'NM'} || "nm") . " -p"; my $objdump = ($ENV{'OBJDUMP'} || "objdump") . " -s -j .comment"; |
1da177e4c Linux-2.6.12-rc2 |
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
my $srctree = ""; my $objtree = ""; $srctree = "$ENV{'srctree'}/" if (exists($ENV{'srctree'})); $objtree = "$ENV{'objtree'}/" if (exists($ENV{'objtree'})); if ($#ARGV != -1) { print STDERR "usage: $0 takes no parameters "; die("giving up "); } my %nmdata = (); # nm data for each object my %def = (); # all definitions for each name my %ksymtab = (); # names that appear in __ksymtab_ my %ref = (); # $ref{$name} exists if there is a true external reference to $name my %export = (); # $export{$name} exists if there is an EXPORT_... of $name |
43f683c9e scripts/namespace... |
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
my %nmexception = ( 'fs/ext3/bitmap' => 1, 'fs/ext4/bitmap' => 1, 'arch/x86/lib/thunk_32' => 1, 'arch/x86/lib/cmpxchg' => 1, 'arch/x86/vdso/vdso32/note' => 1, 'lib/irq_regs' => 1, 'usr/initramfs_data' => 1, 'drivers/scsi/aic94xx/aic94xx_dump' => 1, 'drivers/scsi/libsas/sas_dump' => 1, 'lib/dec_and_lock' => 1, 'drivers/ide/ide-probe-mini' => 1, 'usr/initramfs_data' => 1, 'drivers/acpi/acpia/exdump' => 1, 'drivers/acpi/acpia/rsdump' => 1, 'drivers/acpi/acpia/nsdumpdv' => 1, 'drivers/acpi/acpia/nsdump' => 1, 'arch/ia64/sn/kernel/sn2/io' => 1, 'arch/ia64/kernel/gate-data' => 1, 'security/capability' => 1, 'fs/ntfs/sysctl' => 1, 'fs/jfs/jfs_debug' => 1, ); my %nameexception = ( 'mod_use_count_' => 1, '__initramfs_end' => 1, '__initramfs_start' => 1, '_einittext' => 1, '_sinittext' => 1, 'kallsyms_names' => 1, 'kallsyms_num_syms' => 1, 'kallsyms_addresses'=> 1, '__this_module' => 1, '_etext' => 1, '_edata' => 1, '_end' => 1, '__bss_start' => 1, '_text' => 1, '_stext' => 1, '__gp' => 1, 'ia64_unw_start' => 1, 'ia64_unw_end' => 1, '__init_begin' => 1, '__init_end' => 1, '__bss_stop' => 1, '__nosave_begin' => 1, '__nosave_end' => 1, 'pg0' => 1, |
abb438526 scripts/namespace... |
136 137 138 139 140 141 |
'vdso_enabled' => 1, '__stack_chk_fail' => 1, 'VDSO32_PRELINK' => 1, 'VDSO32_vsyscall' => 1, 'VDSO32_rt_sigreturn'=>1, 'VDSO32_sigreturn' => 1, |
43f683c9e scripts/namespace... |
142 |
); |
1da177e4c Linux-2.6.12-rc2 |
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
&find(\&linux_objects, '.'); # find the objects and do_nm on them &list_multiply_defined(); &resolve_external_references(); &list_extra_externals(); exit(0); sub linux_objects { # Select objects, ignoring objects which are only created by # merging other objects. Also ignore all of modules, scripts # and compressed. Most conglomerate objects are handled by do_nm, # this list only contains the special cases. These include objects # that are linked from just one other object and objects for which # there is really no permanent source file. my $basename = $_; $_ = $File::Find::name; s:^\./::; if (/.*\.o$/ && ! ( m:/built-in.o$: |
abb438526 scripts/namespace... |
164 165 |
|| m:arch/x86/vdso/: || m:arch/x86/boot/: |
1da177e4c Linux-2.6.12-rc2 |
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
|| m:arch/ia64/ia32/ia32.o$: || m:arch/ia64/kernel/gate-syms.o$: || m:arch/ia64/lib/__divdi3.o$: || m:arch/ia64/lib/__divsi3.o$: || m:arch/ia64/lib/__moddi3.o$: || m:arch/ia64/lib/__modsi3.o$: || m:arch/ia64/lib/__udivdi3.o$: || m:arch/ia64/lib/__udivsi3.o$: || m:arch/ia64/lib/__umoddi3.o$: || m:arch/ia64/lib/__umodsi3.o$: || m:arch/ia64/scripts/check_gas_for_hint.o$: || m:arch/ia64/sn/kernel/xp.o$: || m:boot/bbootsect.o$: || m:boot/bsetup.o$: || m:/bootsect.o$: || m:/boot/setup.o$: || m:/compressed/: || m:drivers/cdrom/driver.o$: || m:drivers/char/drm/tdfx_drv.o$: || m:drivers/ide/ide-detect.o$: || m:drivers/ide/pci/idedriver-pci.o$: || m:drivers/media/media.o$: || m:drivers/scsi/sd_mod.o$: || m:drivers/video/video.o$: || m:fs/devpts/devpts.o$: || m:fs/exportfs/exportfs.o$: || m:fs/hugetlbfs/hugetlbfs.o$: || m:fs/msdos/msdos.o$: || m:fs/nls/nls.o$: || m:fs/ramfs/ramfs.o$: || m:fs/romfs/romfs.o$: || m:fs/vfat/vfat.o$: || m:init/mounts.o$: || m:^modules/: || m:net/netlink/netlink.o$: || m:net/sched/sched.o$: || m:/piggy.o$: || m:^scripts/: || m:sound/.*/snd-: || m:^.*/\.tmp_: || m:^\.tmp_: || m:/vmlinux-obj.o$: |
abb438526 scripts/namespace... |
208 |
|| m:^tools/: |
1da177e4c Linux-2.6.12-rc2 |
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
) ) { do_nm($basename, $_); } $_ = $basename; # File::Find expects $_ untouched (undocumented) } sub do_nm { my ($basename, $fullname) = @_; my ($source, $type, $name); if (! -e $basename) { printf STDERR "$basename does not exist "; return; } if ($fullname !~ /\.o$/) { printf STDERR "$fullname is not an object file "; return; } |
c25f41575 scripts/namespace... |
230 231 232 |
($source = $basename) =~ s/\.o$//; if (-e "$source.c" || -e "$source.S") { $source = "$objtree$File::Find::dir/$source"; |
1da177e4c Linux-2.6.12-rc2 |
233 |
} else { |
c25f41575 scripts/namespace... |
234 |
$source = "$srctree$File::Find::dir/$source"; |
1da177e4c Linux-2.6.12-rc2 |
235 236 237 |
} if (! -e "$source.c" && ! -e "$source.S") { # No obvious source, exclude the object if it is conglomerate |
86d08e569 namespace: perlcr... |
238 239 240 |
open(my $objdumpdata, "$objdump $basename|") or die "$objdump $fullname failed $! "; |
1da177e4c Linux-2.6.12-rc2 |
241 |
my $comment; |
86d08e569 namespace: perlcr... |
242 |
while (<$objdumpdata>) { |
1da177e4c Linux-2.6.12-rc2 |
243 244 245 246 247 248 249 250 251 |
chomp(); if (/^In archive/) { # Archives are always conglomerate $comment = "GCC:GCC:"; last; } next if (! /^[ 0-9a-f]{5,} /); $comment .= substr($_, 43); } |
86d08e569 namespace: perlcr... |
252 |
close($objdumpdata); |
1da177e4c Linux-2.6.12-rc2 |
253 254 255 256 257 258 |
if (!defined($comment) || $comment !~ /GCC\:.*GCC\:/m) { printf STDERR "No source file found for $fullname "; } return; } |
86d08e569 namespace: perlcr... |
259 260 261 |
open (my $nmdata, "$nm $basename|") or die "$nm $fullname failed $! "; |
1da177e4c Linux-2.6.12-rc2 |
262 |
my @nmdata; |
86d08e569 namespace: perlcr... |
263 |
while (<$nmdata>) { |
1da177e4c Linux-2.6.12-rc2 |
264 265 266 267 268 269 270 271 272 273 274 275 276 |
chop; ($type, $name) = (split(/ +/, $_, 3))[1..2]; # Expected types # A absolute symbol # B weak external reference to data that has been resolved # C global variable, uninitialised # D global variable, initialised # G global variable, initialised, small data section # R global array, initialised # S global variable, uninitialised, small bss # T global label/procedure # U external reference # W weak external reference to text that has been resolved |
e8cf98134 scripts/namespace... |
277 |
# V similar to W, but the value of the weak symbol becomes zero with no error. |
1da177e4c Linux-2.6.12-rc2 |
278 279 280 281 282 283 284 285 |
# a assembler equate # b static variable, uninitialised # d static variable, initialised # g static variable, initialised, small data section # r static array, initialised # s static variable, uninitialised, small bss # t static label/procedures # w weak external reference to text that has not been resolved |
e8cf98134 scripts/namespace... |
286 |
# v similar to w |
1da177e4c Linux-2.6.12-rc2 |
287 |
# ? undefined type, used a lot by modules |
e8cf98134 scripts/namespace... |
288 |
if ($type !~ /^[ABCDGRSTUWVabdgrstwv?]$/) { |
1da177e4c Linux-2.6.12-rc2 |
289 290 291 292 293 294 295 296 297 298 299 |
printf STDERR "nm output for $fullname contains unknown type '$_' "; } elsif ($name =~ /\./) { # name with '.' is local static } else { $type = 'R' if ($type eq '?'); # binutils replaced ? with R at one point # binutils keeps changing the type for exported symbols, force it to R $type = 'R' if ($name =~ /^__ksymtab/ || $name =~ /^__kstrtab/); $name =~ s/_R[a-f0-9]{8}$//; # module versions adds this |
e8cf98134 scripts/namespace... |
300 |
if ($type =~ /[ABCDGRSTWV]/ && |
1da177e4c Linux-2.6.12-rc2 |
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 |
$name ne 'init_module' && $name ne 'cleanup_module' && $name ne 'Using_Versions' && $name !~ /^Version_[0-9]+$/ && $name !~ /^__parm_/ && $name !~ /^__kstrtab/ && $name !~ /^__ksymtab/ && $name !~ /^__kcrctab_/ && $name !~ /^__exitcall_/ && $name !~ /^__initcall_/ && $name !~ /^__kdb_initcall_/ && $name !~ /^__kdb_exitcall_/ && $name !~ /^__module_/ && $name !~ /^__mod_/ && $name !~ /^__crc_/ && $name ne '__this_module' && $name ne 'kernel_version') { if (!exists($def{$name})) { $def{$name} = []; } push(@{$def{$name}}, $fullname); } push(@nmdata, "$type $name"); if ($name =~ /^__ksymtab_/) { $name = substr($name, 10); if (!exists($ksymtab{$name})) { $ksymtab{$name} = []; } push(@{$ksymtab{$name}}, $fullname); } } } |
86d08e569 namespace: perlcr... |
333 |
close($nmdata); |
1da177e4c Linux-2.6.12-rc2 |
334 |
if ($#nmdata < 0) { |
43f683c9e scripts/namespace... |
335 336 337 338 |
printf "No nm data for $fullname " unless $nmexception{$fullname}; return; |
1da177e4c Linux-2.6.12-rc2 |
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 |
} $nmdata{$fullname} = \@nmdata; } sub drop_def { my ($object, $name) = @_; my $nmdata = $nmdata{$object}; my ($i, $j); for ($i = 0; $i <= $#{$nmdata}; ++$i) { if ($name eq (split(' ', $nmdata->[$i], 2))[1]) { splice(@{$nmdata{$object}}, $i, 1); my $def = $def{$name}; for ($j = 0; $j < $#{$def{$name}}; ++$j) { if ($def{$name}[$j] eq $object) { splice(@{$def{$name}}, $j, 1); } } last; } } } sub list_multiply_defined { |
86d08e569 namespace: perlcr... |
364 |
foreach my $name (keys(%def)) { |
1da177e4c Linux-2.6.12-rc2 |
365 366 |
if ($#{$def{$name}} > 0) { # Special case for cond_syscall |
abb438526 scripts/namespace... |
367 368 369 |
if ($#{$def{$name}} == 1 && ($name =~ /^sys_/ || $name =~ /^compat_sys_/ || $name =~ /^sys32_/)) { |
e8cf98134 scripts/namespace... |
370 371 372 373 374 |
if($def{$name}[0] eq "kernel/sys_ni.o" || $def{$name}[1] eq "kernel/sys_ni.o") { &drop_def("kernel/sys_ni.o", $name); next; } |
1da177e4c Linux-2.6.12-rc2 |
375 |
} |
86d08e569 namespace: perlcr... |
376 |
|
1da177e4c Linux-2.6.12-rc2 |
377 378 |
printf "$name is multiply defined in :- "; |
86d08e569 namespace: perlcr... |
379 |
foreach my $module (@{$def{$name}}) { |
1da177e4c Linux-2.6.12-rc2 |
380 381 382 383 384 385 386 387 388 |
printf "\t$module "; } } } } sub resolve_external_references { |
86d08e569 namespace: perlcr... |
389 |
my ($kstrtab, $ksymtab, $export); |
1da177e4c Linux-2.6.12-rc2 |
390 391 |
printf " "; |
86d08e569 namespace: perlcr... |
392 |
foreach my $object (keys(%nmdata)) { |
1da177e4c Linux-2.6.12-rc2 |
393 |
my $nmdata = $nmdata{$object}; |
86d08e569 namespace: perlcr... |
394 395 |
for (my $i = 0; $i <= $#{$nmdata}; ++$i) { my ($type, $name) = split(' ', $nmdata->[$i], 2); |
1da177e4c Linux-2.6.12-rc2 |
396 397 398 399 400 401 402 403 |
if ($type eq "U" || $type eq "w") { if (exists($def{$name}) || exists($ksymtab{$name})) { # add the owning object to the nmdata $nmdata->[$i] = "$type $name $object"; # only count as a reference if it is not EXPORT_... $kstrtab = "R __kstrtab_$name"; $ksymtab = "R __ksymtab_$name"; $export = 0; |
86d08e569 namespace: perlcr... |
404 |
for (my $j = 0; $j <= $#{$nmdata}; ++$j) { |
1da177e4c Linux-2.6.12-rc2 |
405 406 407 408 409 410 411 412 413 414 415 416 417 |
if ($nmdata->[$j] eq $kstrtab || $nmdata->[$j] eq $ksymtab) { $export = 1; last; } } if ($export) { $export{$name} = ""; } else { $ref{$name} = "" } } |
43f683c9e scripts/namespace... |
418 |
elsif ( ! $nameexception{$name} |
1da177e4c Linux-2.6.12-rc2 |
419 420 421 422 423 424 425 426 427 428 |
&& $name !~ /^__sched_text_/ && $name !~ /^__start_/ && $name !~ /^__end_/ && $name !~ /^__stop_/ && $name !~ /^__scheduling_functions_.*_here/ && $name !~ /^__.*initcall_/ && $name !~ /^__.*per_cpu_start/ && $name !~ /^__.*per_cpu_end/ && $name !~ /^__alt_instructions/ && $name !~ /^__setup_/ |
1da177e4c Linux-2.6.12-rc2 |
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 |
&& $name !~ /^__mod_timer/ && $name !~ /^__mod_page_state/ && $name !~ /^init_module/ && $name !~ /^cleanup_module/ ) { printf "Cannot resolve "; printf "weak " if ($type eq "w"); printf "reference to $name from $object "; } } } } } sub list_extra_externals { my %noref = (); |
86d08e569 namespace: perlcr... |
447 448 |
foreach my $name (keys(%def)) { |
1da177e4c Linux-2.6.12-rc2 |
449 |
if (! exists($ref{$name})) { |
86d08e569 namespace: perlcr... |
450 451 |
my @module = @{$def{$name}}; foreach my $module (@module) { |
1da177e4c Linux-2.6.12-rc2 |
452 453 454 455 456 457 458 459 460 461 462 |
if (! exists($noref{$module})) { $noref{$module} = []; } push(@{$noref{$module}}, $name); } } } if (%noref) { printf " Externally defined symbols with no external references "; |
86d08e569 namespace: perlcr... |
463 |
foreach my $module (sort(keys(%noref))) { |
1da177e4c Linux-2.6.12-rc2 |
464 465 466 |
printf " $module "; foreach (sort(@{$noref{$module}})) { |
86d08e569 namespace: perlcr... |
467 468 469 470 471 472 473 474 |
my $export; if (exists($export{$_})) { $export = " (export only)"; } else { $export = ""; } printf " $_$export "; |
1da177e4c Linux-2.6.12-rc2 |
475 476 477 478 |
} } } } |