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