Back to home page

LXR

 
 

    


0001 #!/usr/bin/perl -w
0002 #
0003 #   namespace.pl.  Mon Aug 30 2004
0004 #
0005 #   Perform a name space analysis on the linux kernel.
0006 #
0007 #   Copyright Keith Owens <kaos@ocs.com.au>.  GPL.
0008 #
0009 #   Invoke by changing directory to the top of the kernel object
0010 #   tree then namespace.pl, no parameters.
0011 #
0012 #   Tuned for 2.1.x kernels with the new module handling, it will
0013 #   work with 2.0 kernels as well.
0014 #
0015 #   Last change 2.6.9-rc1, adding support for separate source and object
0016 #   trees.
0017 #
0018 #   The source must be compiled/assembled first, the object files
0019 #   are the primary input to this script.  Incomplete or missing
0020 #   objects will result in a flawed analysis.  Compile both vmlinux
0021 #   and modules.
0022 #
0023 #   Even with complete objects, treat the result of the analysis
0024 #   with caution.  Some external references are only used by
0025 #   certain architectures, others with certain combinations of
0026 #   configuration parameters.  Ideally the source should include
0027 #   something like
0028 #
0029 #   #ifndef CONFIG_...
0030 #   static
0031 #   #endif
0032 #   symbol_definition;
0033 #
0034 #   so the symbols are defined as static unless a particular
0035 #   CONFIG_... requires it to be external.
0036 #
0037 #   A symbol that is suffixed with '(export only)' has these properties
0038 #
0039 #   * It is global.
0040 #   * It is marked EXPORT_SYMBOL or EXPORT_SYMBOL_GPL, either in the same
0041 #     source file or a different source file.
0042 #   * Given the current .config, nothing uses the symbol.
0043 #
0044 #   The symbol is a candidate for conversion to static, plus removal of the
0045 #   export.  But be careful that a different .config might use the symbol.
0046 #
0047 #
0048 #   Name space analysis and cleanup is an iterative process.  You cannot
0049 #   expect to find all the problems in a single pass.
0050 #
0051 #   * Identify possibly unnecessary global declarations, verify that they
0052 #     really are unnecessary and change them to static.
0053 #   * Compile and fix up gcc warnings about static, removing dead symbols
0054 #     as necessary.
0055 #   * make clean and rebuild with different configs (especially
0056 #     CONFIG_MODULES=n) to see which symbols are being defined when the
0057 #     config does not require them.  These symbols bloat the kernel object
0058 #     for no good reason, which is frustrating for embedded systems.
0059 #   * Wrap config sensitive symbols in #ifdef CONFIG_foo, as long as the
0060 #     code does not get too ugly.
0061 #   * Repeat the name space analysis until you can live with with the
0062 #     result.
0063 #
0064 
0065 require 5;  # at least perl 5
0066 use strict;
0067 use File::Find;
0068 
0069 my $nm = ($ENV{'NM'} || "nm") . " -p";
0070 my $objdump = ($ENV{'OBJDUMP'} || "objdump") . " -s -j .comment";
0071 my $srctree = "";
0072 my $objtree = "";
0073 $srctree = "$ENV{'srctree'}/" if (exists($ENV{'srctree'}));
0074 $objtree = "$ENV{'objtree'}/" if (exists($ENV{'objtree'}));
0075 
0076 if ($#ARGV != -1) {
0077     print STDERR "usage: $0 takes no parameters\n";
0078     die("giving up\n");
0079 }
0080 
0081 my %nmdata = ();    # nm data for each object
0082 my %def = ();       # all definitions for each name
0083 my %ksymtab = ();   # names that appear in __ksymtab_
0084 my %ref = ();       # $ref{$name} exists if there is a true external reference to $name
0085 my %export = ();    # $export{$name} exists if there is an EXPORT_... of $name
0086 
0087 my %nmexception = (
0088     'fs/ext3/bitmap'            => 1,
0089     'fs/ext4/bitmap'            => 1,
0090     'arch/x86/lib/thunk_32'     => 1,
0091     'arch/x86/lib/cmpxchg'      => 1,
0092     'arch/x86/vdso/vdso32/note'     => 1,
0093     'lib/irq_regs'          => 1,
0094     'usr/initramfs_data'        => 1,
0095     'drivers/scsi/aic94xx/aic94xx_dump' => 1,
0096     'drivers/scsi/libsas/sas_dump'  => 1,
0097     'lib/dec_and_lock'          => 1,
0098     'drivers/ide/ide-probe-mini'    => 1,
0099     'usr/initramfs_data'        => 1,
0100     'drivers/acpi/acpia/exdump'     => 1,
0101     'drivers/acpi/acpia/rsdump'     => 1,
0102     'drivers/acpi/acpia/nsdumpdv'   => 1,
0103     'drivers/acpi/acpia/nsdump'     => 1,
0104     'arch/ia64/sn/kernel/sn2/io'    => 1,
0105     'arch/ia64/kernel/gate-data'    => 1,
0106     'security/capability'       => 1,
0107     'fs/ntfs/sysctl'            => 1,
0108     'fs/jfs/jfs_debug'          => 1,
0109 );
0110 
0111 my %nameexception = (
0112     'mod_use_count_'     => 1,
0113     '__initramfs_end'   => 1,
0114     '__initramfs_start' => 1,
0115     '_einittext'    => 1,
0116     '_sinittext'    => 1,
0117     'kallsyms_names'    => 1,
0118     'kallsyms_num_syms' => 1,
0119     'kallsyms_addresses'=> 1,
0120     'kallsyms_offsets'  => 1,
0121     'kallsyms_relative_base'=> 1,
0122     '__this_module' => 1,
0123     '_etext'        => 1,
0124     '_edata'        => 1,
0125     '_end'      => 1,
0126     '__bss_start'   => 1,
0127     '_text'     => 1,
0128     '_stext'        => 1,
0129     '__gp'      => 1,
0130     'ia64_unw_start'    => 1,
0131     'ia64_unw_end'  => 1,
0132     '__init_begin'  => 1,
0133     '__init_end'    => 1,
0134     '__bss_stop'    => 1,
0135     '__nosave_begin'    => 1,
0136     '__nosave_end'  => 1,
0137     'pg0'       => 1,
0138     'vdso_enabled'  => 1,
0139     '__stack_chk_fail'  => 1,
0140     'VDSO32_PRELINK'    => 1,
0141     'VDSO32_vsyscall'   => 1,
0142     'VDSO32_rt_sigreturn'=>1,
0143     'VDSO32_sigreturn'  => 1,
0144 );
0145 
0146 
0147 &find(\&linux_objects, '.');    # find the objects and do_nm on them
0148 &list_multiply_defined();
0149 &resolve_external_references();
0150 &list_extra_externals();
0151 
0152 exit(0);
0153 
0154 sub linux_objects
0155 {
0156     # Select objects, ignoring objects which are only created by
0157     # merging other objects.  Also ignore all of modules, scripts
0158     # and compressed.  Most conglomerate objects are handled by do_nm,
0159     # this list only contains the special cases.  These include objects
0160     # that are linked from just one other object and objects for which
0161     # there is really no permanent source file.
0162     my $basename = $_;
0163     $_ = $File::Find::name;
0164     s:^\./::;
0165     if (/.*\.o$/ &&
0166         ! (
0167         m:/built-in.o$:
0168         || m:arch/x86/vdso/:
0169         || m:arch/x86/boot/:
0170         || m:arch/ia64/ia32/ia32.o$:
0171         || m:arch/ia64/kernel/gate-syms.o$:
0172         || m:arch/ia64/lib/__divdi3.o$:
0173         || m:arch/ia64/lib/__divsi3.o$:
0174         || m:arch/ia64/lib/__moddi3.o$:
0175         || m:arch/ia64/lib/__modsi3.o$:
0176         || m:arch/ia64/lib/__udivdi3.o$:
0177         || m:arch/ia64/lib/__udivsi3.o$:
0178         || m:arch/ia64/lib/__umoddi3.o$:
0179         || m:arch/ia64/lib/__umodsi3.o$:
0180         || m:arch/ia64/scripts/check_gas_for_hint.o$:
0181         || m:arch/ia64/sn/kernel/xp.o$:
0182         || m:boot/bbootsect.o$:
0183         || m:boot/bsetup.o$:
0184         || m:/bootsect.o$:
0185         || m:/boot/setup.o$:
0186         || m:/compressed/:
0187         || m:drivers/cdrom/driver.o$:
0188         || m:drivers/char/drm/tdfx_drv.o$:
0189         || m:drivers/ide/ide-detect.o$:
0190         || m:drivers/ide/pci/idedriver-pci.o$:
0191         || m:drivers/media/media.o$:
0192         || m:drivers/scsi/sd_mod.o$:
0193         || m:drivers/video/video.o$:
0194         || m:fs/devpts/devpts.o$:
0195         || m:fs/exportfs/exportfs.o$:
0196         || m:fs/hugetlbfs/hugetlbfs.o$:
0197         || m:fs/msdos/msdos.o$:
0198         || m:fs/nls/nls.o$:
0199         || m:fs/ramfs/ramfs.o$:
0200         || m:fs/romfs/romfs.o$:
0201         || m:fs/vfat/vfat.o$:
0202         || m:init/mounts.o$:
0203         || m:^modules/:
0204         || m:net/netlink/netlink.o$:
0205         || m:net/sched/sched.o$:
0206         || m:/piggy.o$:
0207         || m:^scripts/:
0208         || m:sound/.*/snd-:
0209         || m:^.*/\.tmp_:
0210         || m:^\.tmp_:
0211         || m:/vmlinux-obj.o$:
0212         || m:^tools/:
0213         )
0214     ) {
0215         do_nm($basename, $_);
0216     }
0217     $_ = $basename;     # File::Find expects $_ untouched (undocumented)
0218 }
0219 
0220 sub do_nm
0221 {
0222     my ($basename, $fullname) = @_;
0223     my ($source, $type, $name);
0224     if (! -e $basename) {
0225         printf STDERR "$basename does not exist\n";
0226         return;
0227     }
0228     if ($fullname !~ /\.o$/) {
0229         printf STDERR "$fullname is not an object file\n";
0230         return;
0231     }
0232     ($source = $basename) =~ s/\.o$//;
0233     if (-e "$source.c" || -e "$source.S") {
0234         $source = "$objtree$File::Find::dir/$source";
0235     } else {
0236         $source = "$srctree$File::Find::dir/$source";
0237     }
0238     if (! -e "$source.c" && ! -e "$source.S") {
0239         # No obvious source, exclude the object if it is conglomerate
0240             open(my $objdumpdata, "$objdump $basename|")
0241             or die "$objdump $fullname failed $!\n";
0242 
0243         my $comment;
0244         while (<$objdumpdata>) {
0245             chomp();
0246             if (/^In archive/) {
0247                 # Archives are always conglomerate
0248                 $comment = "GCC:GCC:";
0249                 last;
0250             }
0251             next if (! /^[ 0-9a-f]{5,} /);
0252             $comment .= substr($_, 43);
0253         }
0254         close($objdumpdata);
0255 
0256         if (!defined($comment) || $comment !~ /GCC\:.*GCC\:/m) {
0257             printf STDERR "No source file found for $fullname\n";
0258         }
0259         return;
0260     }
0261     open (my $nmdata, "$nm $basename|")
0262         or die "$nm $fullname failed $!\n";
0263 
0264     my @nmdata;
0265     while (<$nmdata>) {
0266         chop;
0267         ($type, $name) = (split(/ +/, $_, 3))[1..2];
0268         # Expected types
0269         # A absolute symbol
0270         # B weak external reference to data that has been resolved
0271         # C global variable, uninitialised
0272         # D global variable, initialised
0273         # G global variable, initialised, small data section
0274         # R global array, initialised
0275         # S global variable, uninitialised, small bss
0276         # T global label/procedure
0277         # U external reference
0278         # W weak external reference to text that has been resolved
0279         # V similar to W, but the value of the weak symbol becomes zero with no error.
0280         # a assembler equate
0281         # b static variable, uninitialised
0282         # d static variable, initialised
0283         # g static variable, initialised, small data section
0284         # r static array, initialised
0285         # s static variable, uninitialised, small bss
0286         # t static label/procedures
0287         # w weak external reference to text that has not been resolved
0288         # v similar to w
0289         # ? undefined type, used a lot by modules
0290         if ($type !~ /^[ABCDGRSTUWVabdgrstwv?]$/) {
0291             printf STDERR "nm output for $fullname contains unknown type '$_'\n";
0292         }
0293         elsif ($name =~ /\./) {
0294             # name with '.' is local static
0295         }
0296         else {
0297             $type = 'R' if ($type eq '?');  # binutils replaced ? with R at one point
0298             # binutils keeps changing the type for exported symbols, force it to R
0299             $type = 'R' if ($name =~ /^__ksymtab/ || $name =~ /^__kstrtab/);
0300             $name =~ s/_R[a-f0-9]{8}$//;    # module versions adds this
0301             if ($type =~ /[ABCDGRSTWV]/ &&
0302                 $name ne 'init_module' &&
0303                 $name ne 'cleanup_module' &&
0304                 $name ne 'Using_Versions' &&
0305                 $name !~ /^Version_[0-9]+$/ &&
0306                 $name !~ /^__parm_/ &&
0307                 $name !~ /^__kstrtab/ &&
0308                 $name !~ /^__ksymtab/ &&
0309                 $name !~ /^__kcrctab_/ &&
0310                 $name !~ /^__exitcall_/ &&
0311                 $name !~ /^__initcall_/ &&
0312                 $name !~ /^__kdb_initcall_/ &&
0313                 $name !~ /^__kdb_exitcall_/ &&
0314                 $name !~ /^__module_/ &&
0315                 $name !~ /^__mod_/ &&
0316                 $name !~ /^__crc_/ &&
0317                 $name ne '__this_module' &&
0318                 $name ne 'kernel_version') {
0319                 if (!exists($def{$name})) {
0320                     $def{$name} = [];
0321                 }
0322                 push(@{$def{$name}}, $fullname);
0323             }
0324             push(@nmdata, "$type $name");
0325             if ($name =~ /^__ksymtab_/) {
0326                 $name = substr($name, 10);
0327                 if (!exists($ksymtab{$name})) {
0328                     $ksymtab{$name} = [];
0329                 }
0330                 push(@{$ksymtab{$name}}, $fullname);
0331             }
0332         }
0333     }
0334     close($nmdata);
0335 
0336     if ($#nmdata < 0) {
0337         printf "No nm data for $fullname\n"
0338         unless $nmexception{$fullname};
0339         return;
0340     }
0341     $nmdata{$fullname} = \@nmdata;
0342 }
0343 
0344 sub drop_def
0345 {
0346     my ($object, $name) = @_;
0347     my $nmdata = $nmdata{$object};
0348     my ($i, $j);
0349     for ($i = 0; $i <= $#{$nmdata}; ++$i) {
0350         if ($name eq (split(' ', $nmdata->[$i], 2))[1]) {
0351             splice(@{$nmdata{$object}}, $i, 1);
0352             my $def = $def{$name};
0353             for ($j = 0; $j < $#{$def{$name}}; ++$j) {
0354                 if ($def{$name}[$j] eq $object) {
0355                     splice(@{$def{$name}}, $j, 1);
0356                 }
0357             }
0358             last;
0359         }
0360     }
0361 }
0362 
0363 sub list_multiply_defined
0364 {
0365     foreach my $name (keys(%def)) {
0366         if ($#{$def{$name}} > 0) {
0367             # Special case for cond_syscall
0368             if ($#{$def{$name}} == 1 &&
0369                ($name =~ /^sys_/ || $name =~ /^compat_sys_/ ||
0370                 $name =~ /^sys32_/)) {
0371                 if($def{$name}[0] eq "kernel/sys_ni.o" ||
0372                    $def{$name}[1] eq "kernel/sys_ni.o") {
0373                     &drop_def("kernel/sys_ni.o", $name);
0374                     next;
0375                 }
0376             }
0377 
0378             printf "$name is multiply defined in :-\n";
0379             foreach my $module (@{$def{$name}}) {
0380                 printf "\t$module\n";
0381             }
0382         }
0383     }
0384 }
0385 
0386 sub resolve_external_references
0387 {
0388     my ($kstrtab, $ksymtab, $export);
0389 
0390     printf "\n";
0391     foreach my $object (keys(%nmdata)) {
0392         my $nmdata = $nmdata{$object};
0393         for (my $i = 0; $i <= $#{$nmdata}; ++$i) {
0394             my ($type, $name) = split(' ', $nmdata->[$i], 2);
0395             if ($type eq "U" || $type eq "w") {
0396                 if (exists($def{$name}) || exists($ksymtab{$name})) {
0397                     # add the owning object to the nmdata
0398                     $nmdata->[$i] = "$type $name $object";
0399                     # only count as a reference if it is not EXPORT_...
0400                     $kstrtab = "R __kstrtab_$name";
0401                     $ksymtab = "R __ksymtab_$name";
0402                     $export = 0;
0403                     for (my $j = 0; $j <= $#{$nmdata}; ++$j) {
0404                         if ($nmdata->[$j] eq $kstrtab ||
0405                             $nmdata->[$j] eq $ksymtab) {
0406                             $export = 1;
0407                             last;
0408                         }
0409                     }
0410                     if ($export) {
0411                         $export{$name} = "";
0412                     }
0413                     else {
0414                         $ref{$name} = ""
0415                     }
0416                 }
0417                 elsif ( ! $nameexception{$name}
0418                     && $name !~ /^__sched_text_/
0419                     && $name !~ /^__start_/
0420                     && $name !~ /^__end_/
0421                     && $name !~ /^__stop_/
0422                     && $name !~ /^__scheduling_functions_.*_here/
0423                     && $name !~ /^__.*initcall_/
0424                     && $name !~ /^__.*per_cpu_start/
0425                     && $name !~ /^__.*per_cpu_end/
0426                     && $name !~ /^__alt_instructions/
0427                     && $name !~ /^__setup_/
0428                     && $name !~ /^__mod_timer/
0429                     && $name !~ /^__mod_page_state/
0430                     && $name !~ /^init_module/
0431                     && $name !~ /^cleanup_module/
0432                 ) {
0433                     printf "Cannot resolve ";
0434                     printf "weak " if ($type eq "w");
0435                     printf "reference to $name from $object\n";
0436                 }
0437             }
0438         }
0439     }
0440 }
0441 
0442 sub list_extra_externals
0443 {
0444     my %noref = ();
0445 
0446     foreach my $name (keys(%def)) {
0447         if (! exists($ref{$name})) {
0448             my @module = @{$def{$name}};
0449             foreach my $module (@module) {
0450                 if (! exists($noref{$module})) {
0451                     $noref{$module} = [];
0452                 }
0453                 push(@{$noref{$module}}, $name);
0454             }
0455         }
0456     }
0457     if (%noref) {
0458         printf "\nExternally defined symbols with no external references\n";
0459         foreach my $module (sort(keys(%noref))) {
0460             printf "  $module\n";
0461             foreach (sort(@{$noref{$module}})) {
0462                 my $export;
0463                 if (exists($export{$_})) {
0464                 $export = " (export only)";
0465                 } else {
0466                 $export = "";
0467                 }
0468                 printf "    $_$export\n";
0469             }
0470         }
0471     }
0472 }