| 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 | require 5; |
| 66 | use strict;
|
| 67 | use File::Find;
|
| 68 |
|
| 69 | my $nm = ($ENV{'NM'} || "nm") . " -p";
|
| 70 | my $objdump = ($ENV{'OBJDUMP'} || "objdump") . " -s -j .comment";
|
| 71 | my $srctree = "";
|
| 72 | my $objtree = "";
|
| 73 | $srctree = "$ENV{'srctree'}/" if (exists($ENV{'srctree'}));
|
| 74 | $objtree = "$ENV{'objtree'}/" if (exists($ENV{'objtree'}));
|
| 75 |
|
| 76 | if ($#ARGV != -1) {
|
| 77 | print STDERR "usage: $0 takes no parameters\n";
|
| 78 | die("giving up\n");
|
| 79 | }
|
| 80 |
|
| 81 | my %nmdata = (); |
| 82 | my %def = (); |
| 83 | my %ksymtab = (); |
| 84 | my %ref = (); |
| 85 | my %export = (); |
| 86 |
|
| 87 | &find(\&linux_objects, '.'); |
| 88 | &list_multiply_defined();
|
| 89 | &resolve_external_references();
|
| 90 | &list_extra_externals();
|
| 91 |
|
| 92 | exit(0);
|
| 93 |
|
| 94 | sub linux_objects
|
| 95 | {
|
| 96 | |
| 97 | |
| 98 | |
| 99 | |
| 100 | |
| 101 | |
| 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; |
| 156 | }
|
| 157 |
|
| 158 | sub 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 | |
| 178 | open(my $objdumpdata, "$objdump $basename|")
|
| 179 | or die "$objdump $fullname failed $!\n";
|
| 180 |
|
| 181 | my $comment;
|
| 182 | while (<$objdumpdata>) {
|
| 183 | chomp();
|
| 184 | if (/^In archive/) {
|
| 185 | |
| 186 | $comment = "GCC:GCC:";
|
| 187 | last;
|
| 188 | }
|
| 189 | next if (! /^[ 0-9a-f]{5,} /);
|
| 190 | $comment .= substr($_, 43);
|
| 191 | }
|
| 192 | close($objdumpdata);
|
| 193 |
|
| 194 | if (!defined($comment) || $comment !~ /GCC\:.*GCC\:/m) {
|
| 195 | printf STDERR "No source file found for $fullname\n";
|
| 196 | }
|
| 197 | return;
|
| 198 | }
|
| 199 | open (my $nmdata, "$nm $basename|")
|
| 200 | or die "$nm $fullname failed $!\n";
|
| 201 |
|
| 202 | my @nmdata;
|
| 203 | while (<$nmdata>) {
|
| 204 | chop;
|
| 205 | ($type, $name) = (split(/ +/, $_, 3))[1..2];
|
| 206 | |
| 207 | |
| 208 | |
| 209 | |
| 210 | |
| 211 | |
| 212 | |
| 213 | |
| 214 | |
| 215 | |
| 216 | |
| 217 | |
| 218 | |
| 219 | |
| 220 | |
| 221 | |
| 222 | |
| 223 | |
| 224 | |
| 225 | |
| 226 | if ($type !~ /^[ABCDGRSTUWabdgrstw?]$/) {
|
| 227 | printf STDERR "nm output for $fullname contains unknown type '$_'\n";
|
| 228 | }
|
| 229 | elsif ($name =~ /\./) {
|
| 230 | |
| 231 | }
|
| 232 | else {
|
| 233 | $type = 'R' if ($type eq '?'); |
| 234 | |
| 235 | $type = 'R' if ($name =~ /^__ksymtab/ || $name =~ /^__kstrtab/);
|
| 236 | $name =~ s/_R[a-f0-9]{8}$//; |
| 237 | if ($type =~ /[ABCDGRSTW]/ &&
|
| 238 | $name ne 'init_module' &&
|
| 239 | $name ne 'cleanup_module' &&
|
| 240 | $name ne 'Using_Versions' &&
|
| 241 | $name !~ /^Version_[0-9]+$/ &&
|
| 242 | $name !~ /^__parm_/ &&
|
| 243 | $name !~ /^__kstrtab/ &&
|
| 244 | $name !~ /^__ksymtab/ &&
|
| 245 | $name !~ /^__kcrctab_/ &&
|
| 246 | $name !~ /^__exitcall_/ &&
|
| 247 | $name !~ /^__initcall_/ &&
|
| 248 | $name !~ /^__kdb_initcall_/ &&
|
| 249 | $name !~ /^__kdb_exitcall_/ &&
|
| 250 | $name !~ /^__module_/ &&
|
| 251 | $name !~ /^__mod_/ &&
|
| 252 | $name !~ /^__crc_/ &&
|
| 253 | $name ne '__this_module' &&
|
| 254 | $name ne 'kernel_version') {
|
| 255 | if (!exists($def{$name})) {
|
| 256 | $def{$name} = [];
|
| 257 | }
|
| 258 | push(@{$def{$name}}, $fullname);
|
| 259 | }
|
| 260 | push(@nmdata, "$type $name");
|
| 261 | if ($name =~ /^__ksymtab_/) {
|
| 262 | $name = substr($name, 10);
|
| 263 | if (!exists($ksymtab{$name})) {
|
| 264 | $ksymtab{$name} = [];
|
| 265 | }
|
| 266 | push(@{$ksymtab{$name}}, $fullname);
|
| 267 | }
|
| 268 | }
|
| 269 | }
|
| 270 | close($nmdata);
|
| 271 |
|
| 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 |
|
| 298 | sub 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 |
|
| 317 | sub list_multiply_defined
|
| 318 | {
|
| 319 | foreach my $name (keys(%def)) {
|
| 320 | if ($#{$def{$name}} > 0) {
|
| 321 | |
| 322 | if ($#{$def{$name}} == 1 && $name =~ /^sys_/ &&
|
| 323 | ($def{$name}[0] eq "kernel/sys.o" ||
|
| 324 | $def{$name}[1] eq "kernel/sys.o")) {
|
| 325 | &drop_def("kernel/sys.o", $name);
|
| 326 | next;
|
| 327 | }
|
| 328 | |
| 329 | if ($#{$def{$name}} == 1 && $name =~ /^__kernel_/ &&
|
| 330 | $def{$name}[0] eq "arch/x86/kernel/vsyscall-int80_32.o" &&
|
| 331 | $def{$name}[1] eq "arch/x86/kernel/vsyscall-sysenter_32.o") {
|
| 332 | &drop_def("arch/x86/kernel/vsyscall-sysenter_32.o", $name);
|
| 333 | next;
|
| 334 | }
|
| 335 |
|
| 336 | printf "$name is multiply defined in :-\n";
|
| 337 | foreach my $module (@{$def{$name}}) {
|
| 338 | printf "\t$module\n";
|
| 339 | }
|
| 340 | }
|
| 341 | }
|
| 342 | }
|
| 343 |
|
| 344 | sub resolve_external_references
|
| 345 | {
|
| 346 | my ($kstrtab, $ksymtab, $export);
|
| 347 |
|
| 348 | printf "\n";
|
| 349 | foreach my $object (keys(%nmdata)) {
|
| 350 | my $nmdata = $nmdata{$object};
|
| 351 | for (my $i = 0; $i <= $#{$nmdata}; ++$i) {
|
| 352 | my ($type, $name) = split(' ', $nmdata->[$i], 2);
|
| 353 | if ($type eq "U" || $type eq "w") {
|
| 354 | if (exists($def{$name}) || exists($ksymtab{$name})) {
|
| 355 | |
| 356 | $nmdata->[$i] = "$type $name $object";
|
| 357 | |
| 358 | $kstrtab = "R __kstrtab_$name";
|
| 359 | $ksymtab = "R __ksymtab_$name";
|
| 360 | $export = 0;
|
| 361 | for (my $j = 0; $j <= $#{$nmdata}; ++$j) {
|
| 362 | if ($nmdata->[$j] eq $kstrtab ||
|
| 363 | $nmdata->[$j] eq $ksymtab) {
|
| 364 | $export = 1;
|
| 365 | last;
|
| 366 | }
|
| 367 | }
|
| 368 | if ($export) {
|
| 369 | $export{$name} = "";
|
| 370 | }
|
| 371 | else {
|
| 372 | $ref{$name} = ""
|
| 373 | }
|
| 374 | }
|
| 375 | elsif ( $name ne "mod_use_count_"
|
| 376 | && $name ne "__initramfs_end"
|
| 377 | && $name ne "__initramfs_start"
|
| 378 | && $name ne "_einittext"
|
| 379 | && $name ne "_sinittext"
|
| 380 | && $name ne "kallsyms_names"
|
| 381 | && $name ne "kallsyms_num_syms"
|
| 382 | && $name ne "kallsyms_addresses"
|
| 383 | && $name ne "__this_module"
|
| 384 | && $name ne "_etext"
|
| 385 | && $name ne "_edata"
|
| 386 | && $name ne "_end"
|
| 387 | && $name ne "__bss_start"
|
| 388 | && $name ne "_text"
|
| 389 | && $name ne "_stext"
|
| 390 | && $name ne "__gp"
|
| 391 | && $name ne "ia64_unw_start"
|
| 392 | && $name ne "ia64_unw_end"
|
| 393 | && $name ne "__init_begin"
|
| 394 | && $name ne "__init_end"
|
| 395 | && $name ne "__bss_stop"
|
| 396 | && $name ne "__nosave_begin"
|
| 397 | && $name ne "__nosave_end"
|
| 398 | && $name ne "pg0"
|
| 399 | && $name ne "__module_text_address"
|
| 400 | && $name !~ /^__sched_text_/
|
| 401 | && $name !~ /^__start_/
|
| 402 | && $name !~ /^__end_/
|
| 403 | && $name !~ /^__stop_/
|
| 404 | && $name !~ /^__scheduling_functions_.*_here/
|
| 405 | && $name !~ /^__.*initcall_/
|
| 406 | && $name !~ /^__.*per_cpu_start/
|
| 407 | && $name !~ /^__.*per_cpu_end/
|
| 408 | && $name !~ /^__alt_instructions/
|
| 409 | && $name !~ /^__setup_/
|
| 410 | && $name !~ /^jiffies/
|
| 411 | && $name !~ /^__mod_timer/
|
| 412 | && $name !~ /^__mod_page_state/
|
| 413 | && $name !~ /^init_module/
|
| 414 | && $name !~ /^cleanup_module/
|
| 415 | ) {
|
| 416 | printf "Cannot resolve ";
|
| 417 | printf "weak " if ($type eq "w");
|
| 418 | printf "reference to $name from $object\n";
|
| 419 | }
|
| 420 | }
|
| 421 | }
|
| 422 | }
|
| 423 | }
|
| 424 |
|
| 425 | sub list_extra_externals
|
| 426 | {
|
| 427 | my %noref = ();
|
| 428 |
|
| 429 | foreach my $name (keys(%def)) {
|
| 430 | if (! exists($ref{$name})) {
|
| 431 | my @module = @{$def{$name}};
|
| 432 | foreach my $module (@module) {
|
| 433 | if (! exists($noref{$module})) {
|
| 434 | $noref{$module} = [];
|
| 435 | }
|
| 436 | push(@{$noref{$module}}, $name);
|
| 437 | }
|
| 438 | }
|
| 439 | }
|
| 440 | if (%noref) {
|
| 441 | printf "\nExternally defined symbols with no external references\n";
|
| 442 | foreach my $module (sort(keys(%noref))) {
|
| 443 | printf " $module\n";
|
| 444 | foreach (sort(@{$noref{$module}})) {
|
| 445 | my $export;
|
| 446 | if (exists($export{$_})) {
|
| 447 | $export = " (export only)";
|
| 448 | } else {
|
| 449 | $export = "";
|
| 450 | }
|
| 451 | printf " $_$export\n";
|
| 452 | }
|
| 453 | }
|
| 454 | }
|
| 455 | }
|