| 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 | use warnings;
|
| 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 | my %nmexception = (
|
| 88 | 'fs/ext3/bitmap' => 1,
|
| 89 | 'fs/ext4/bitmap' => 1,
|
| 90 | 'arch/x86/lib/thunk_32' => 1,
|
| 91 | 'arch/x86/lib/cmpxchg' => 1,
|
| 92 | 'arch/x86/vdso/vdso32/note' => 1,
|
| 93 | 'lib/irq_regs' => 1,
|
| 94 | 'usr/initramfs_data' => 1,
|
| 95 | 'drivers/scsi/aic94xx/aic94xx_dump' => 1,
|
| 96 | 'drivers/scsi/libsas/sas_dump' => 1,
|
| 97 | 'lib/dec_and_lock' => 1,
|
| 98 | 'drivers/ide/ide-probe-mini' => 1,
|
| 99 | 'usr/initramfs_data' => 1,
|
| 100 | 'drivers/acpi/acpia/exdump' => 1,
|
| 101 | 'drivers/acpi/acpia/rsdump' => 1,
|
| 102 | 'drivers/acpi/acpia/nsdumpdv' => 1,
|
| 103 | 'drivers/acpi/acpia/nsdump' => 1,
|
| 104 | 'arch/ia64/sn/kernel/sn2/io' => 1,
|
| 105 | 'arch/ia64/kernel/gate-data' => 1,
|
| 106 | 'security/capability' => 1,
|
| 107 | 'fs/ntfs/sysctl' => 1,
|
| 108 | 'fs/jfs/jfs_debug' => 1,
|
| 109 | );
|
| 110 |
|
| 111 | my %nameexception = (
|
| 112 | 'mod_use_count_' => 1,
|
| 113 | '__initramfs_end' => 1,
|
| 114 | '__initramfs_start' => 1,
|
| 115 | '_einittext' => 1,
|
| 116 | '_sinittext' => 1,
|
| 117 | 'kallsyms_names' => 1,
|
| 118 | 'kallsyms_num_syms' => 1,
|
| 119 | 'kallsyms_addresses'=> 1,
|
| 120 | 'kallsyms_offsets' => 1,
|
| 121 | 'kallsyms_relative_base'=> 1,
|
| 122 | '__this_module' => 1,
|
| 123 | '_etext' => 1,
|
| 124 | '_edata' => 1,
|
| 125 | '_end' => 1,
|
| 126 | '__bss_start' => 1,
|
| 127 | '_text' => 1,
|
| 128 | '_stext' => 1,
|
| 129 | '__gp' => 1,
|
| 130 | 'ia64_unw_start' => 1,
|
| 131 | 'ia64_unw_end' => 1,
|
| 132 | '__init_begin' => 1,
|
| 133 | '__init_end' => 1,
|
| 134 | '__bss_stop' => 1,
|
| 135 | '__nosave_begin' => 1,
|
| 136 | '__nosave_end' => 1,
|
| 137 | 'pg0' => 1,
|
| 138 | 'vdso_enabled' => 1,
|
| 139 | '__stack_chk_fail' => 1,
|
| 140 | 'VDSO32_PRELINK' => 1,
|
| 141 | 'VDSO32_vsyscall' => 1,
|
| 142 | 'VDSO32_rt_sigreturn'=>1,
|
| 143 | 'VDSO32_sigreturn' => 1,
|
| 144 | );
|
| 145 |
|
| 146 |
|
| 147 | &find(\&linux_objects, '.'); |
| 148 | &list_multiply_defined();
|
| 149 | &resolve_external_references();
|
| 150 | &list_extra_externals();
|
| 151 |
|
| 152 | exit(0);
|
| 153 |
|
| 154 | sub linux_objects
|
| 155 | {
|
| 156 | |
| 157 | |
| 158 | |
| 159 | |
| 160 | |
| 161 | |
| 162 | my $basename = $_;
|
| 163 | $_ = $File::Find::name;
|
| 164 | s:^\./::;
|
| 165 | if (/.*\.o$/ &&
|
| 166 | ! (
|
| 167 | m:/built-in.o$:
|
| 168 | || m:arch/x86/vdso/:
|
| 169 | || m:arch/x86/boot/:
|
| 170 | || m:arch/ia64/ia32/ia32.o$:
|
| 171 | || m:arch/ia64/kernel/gate-syms.o$:
|
| 172 | || m:arch/ia64/lib/__divdi3.o$:
|
| 173 | || m:arch/ia64/lib/__divsi3.o$:
|
| 174 | || m:arch/ia64/lib/__moddi3.o$:
|
| 175 | || m:arch/ia64/lib/__modsi3.o$:
|
| 176 | || m:arch/ia64/lib/__udivdi3.o$:
|
| 177 | || m:arch/ia64/lib/__udivsi3.o$:
|
| 178 | || m:arch/ia64/lib/__umoddi3.o$:
|
| 179 | || m:arch/ia64/lib/__umodsi3.o$:
|
| 180 | || m:arch/ia64/scripts/check_gas_for_hint.o$:
|
| 181 | || m:arch/ia64/sn/kernel/xp.o$:
|
| 182 | || m:boot/bbootsect.o$:
|
| 183 | || m:boot/bsetup.o$:
|
| 184 | || m:/bootsect.o$:
|
| 185 | || m:/boot/setup.o$:
|
| 186 | || m:/compressed/:
|
| 187 | || m:drivers/cdrom/driver.o$:
|
| 188 | || m:drivers/char/drm/tdfx_drv.o$:
|
| 189 | || m:drivers/ide/ide-detect.o$:
|
| 190 | || m:drivers/ide/pci/idedriver-pci.o$:
|
| 191 | || m:drivers/media/media.o$:
|
| 192 | || m:drivers/scsi/sd_mod.o$:
|
| 193 | || m:drivers/video/video.o$:
|
| 194 | || m:fs/devpts/devpts.o$:
|
| 195 | || m:fs/exportfs/exportfs.o$:
|
| 196 | || m:fs/hugetlbfs/hugetlbfs.o$:
|
| 197 | || m:fs/msdos/msdos.o$:
|
| 198 | || m:fs/nls/nls.o$:
|
| 199 | || m:fs/ramfs/ramfs.o$:
|
| 200 | || m:fs/romfs/romfs.o$:
|
| 201 | || m:fs/vfat/vfat.o$:
|
| 202 | || m:init/mounts.o$:
|
| 203 | || m:^modules/:
|
| 204 | || m:net/netlink/netlink.o$:
|
| 205 | || m:net/sched/sched.o$:
|
| 206 | || m:/piggy.o$:
|
| 207 | || m:^scripts/:
|
| 208 | || m:sound/.*/snd-:
|
| 209 | || m:^.*/\.tmp_:
|
| 210 | || m:^\.tmp_:
|
| 211 | || m:/vmlinux-obj.o$:
|
| 212 | || m:^tools/:
|
| 213 | )
|
| 214 | ) {
|
| 215 | do_nm($basename, $_);
|
| 216 | }
|
| 217 | $_ = $basename; |
| 218 | }
|
| 219 |
|
| 220 | sub do_nm
|
| 221 | {
|
| 222 | my ($basename, $fullname) = @_;
|
| 223 | my ($source, $type, $name);
|
| 224 | if (! -e $basename) {
|
| 225 | printf STDERR "$basename does not exist\n";
|
| 226 | return;
|
| 227 | }
|
| 228 | if ($fullname !~ /\.o$/) {
|
| 229 | printf STDERR "$fullname is not an object file\n";
|
| 230 | return;
|
| 231 | }
|
| 232 | ($source = $basename) =~ s/\.o$//;
|
| 233 | if (-e "$source.c" || -e "$source.S") {
|
| 234 | $source = "$objtree$File::Find::dir/$source";
|
| 235 | } else {
|
| 236 | $source = "$srctree$File::Find::dir/$source";
|
| 237 | }
|
| 238 | if (! -e "$source.c" && ! -e "$source.S") {
|
| 239 | |
| 240 | open(my $objdumpdata, "$objdump $basename|")
|
| 241 | or die "$objdump $fullname failed $!\n";
|
| 242 |
|
| 243 | my $comment;
|
| 244 | while (<$objdumpdata>) {
|
| 245 | chomp();
|
| 246 | if (/^In archive/) {
|
| 247 | |
| 248 | $comment = "GCC:GCC:";
|
| 249 | last;
|
| 250 | }
|
| 251 | next if (! /^[ 0-9a-f]{5,} /);
|
| 252 | $comment .= substr($_, 43);
|
| 253 | }
|
| 254 | close($objdumpdata);
|
| 255 |
|
| 256 | if (!defined($comment) || $comment !~ /GCC\:.*GCC\:/m) {
|
| 257 | printf STDERR "No source file found for $fullname\n";
|
| 258 | }
|
| 259 | return;
|
| 260 | }
|
| 261 | open (my $nmdata, "$nm $basename|")
|
| 262 | or die "$nm $fullname failed $!\n";
|
| 263 |
|
| 264 | my @nmdata;
|
| 265 | while (<$nmdata>) {
|
| 266 | chop;
|
| 267 | ($type, $name) = (split(/ +/, $_, 3))[1..2];
|
| 268 | |
| 269 | |
| 270 | |
| 271 | |
| 272 | |
| 273 | |
| 274 | |
| 275 | |
| 276 | |
| 277 | |
| 278 | |
| 279 | |
| 280 | |
| 281 | |
| 282 | |
| 283 | |
| 284 | |
| 285 | |
| 286 | |
| 287 | |
| 288 | |
| 289 | |
| 290 | if ($type !~ /^[ABCDGRSTUWVabdgrstwv?]$/) {
|
| 291 | printf STDERR "nm output for $fullname contains unknown type '$_'\n";
|
| 292 | }
|
| 293 | elsif ($name =~ /\./) {
|
| 294 | |
| 295 | }
|
| 296 | else {
|
| 297 | $type = 'R' if ($type eq '?'); |
| 298 | |
| 299 | $type = 'R' if ($name =~ /^__ksymtab/ || $name =~ /^__kstrtab/);
|
| 300 | $name =~ s/_R[a-f0-9]{8}$//; |
| 301 | if ($type =~ /[ABCDGRSTWV]/ &&
|
| 302 | $name ne 'init_module' &&
|
| 303 | $name ne 'cleanup_module' &&
|
| 304 | $name ne 'Using_Versions' &&
|
| 305 | $name !~ /^Version_[0-9]+$/ &&
|
| 306 | $name !~ /^__parm_/ &&
|
| 307 | $name !~ /^__kstrtab/ &&
|
| 308 | $name !~ /^__ksymtab/ &&
|
| 309 | $name !~ /^__kcrctab_/ &&
|
| 310 | $name !~ /^__exitcall_/ &&
|
| 311 | $name !~ /^__initcall_/ &&
|
| 312 | $name !~ /^__kdb_initcall_/ &&
|
| 313 | $name !~ /^__kdb_exitcall_/ &&
|
| 314 | $name !~ /^__module_/ &&
|
| 315 | $name !~ /^__mod_/ &&
|
| 316 | $name !~ /^__crc_/ &&
|
| 317 | $name ne '__this_module' &&
|
| 318 | $name ne 'kernel_version') {
|
| 319 | if (!exists($def{$name})) {
|
| 320 | $def{$name} = [];
|
| 321 | }
|
| 322 | push(@{$def{$name}}, $fullname);
|
| 323 | }
|
| 324 | push(@nmdata, "$type $name");
|
| 325 | if ($name =~ /^__ksymtab_/) {
|
| 326 | $name = substr($name, 10);
|
| 327 | if (!exists($ksymtab{$name})) {
|
| 328 | $ksymtab{$name} = [];
|
| 329 | }
|
| 330 | push(@{$ksymtab{$name}}, $fullname);
|
| 331 | }
|
| 332 | }
|
| 333 | }
|
| 334 | close($nmdata);
|
| 335 |
|
| 336 | if ($#nmdata < 0) {
|
| 337 | printf "No nm data for $fullname\n"
|
| 338 | unless $nmexception{$fullname};
|
| 339 | return;
|
| 340 | }
|
| 341 | $nmdata{$fullname} = \@nmdata;
|
| 342 | }
|
| 343 |
|
| 344 | sub drop_def
|
| 345 | {
|
| 346 | my ($object, $name) = @_;
|
| 347 | my $nmdata = $nmdata{$object};
|
| 348 | my ($i, $j);
|
| 349 | for ($i = 0; $i <= $#{$nmdata}; ++$i) {
|
| 350 | if ($name eq (split(' ', $nmdata->[$i], 2))[1]) {
|
| 351 | splice(@{$nmdata{$object}}, $i, 1);
|
| 352 | my $def = $def{$name};
|
| 353 | for ($j = 0; $j < $#{$def{$name}}; ++$j) {
|
| 354 | if ($def{$name}[$j] eq $object) {
|
| 355 | splice(@{$def{$name}}, $j, 1);
|
| 356 | }
|
| 357 | }
|
| 358 | last;
|
| 359 | }
|
| 360 | }
|
| 361 | }
|
| 362 |
|
| 363 | sub list_multiply_defined
|
| 364 | {
|
| 365 | foreach my $name (keys(%def)) {
|
| 366 | if ($#{$def{$name}} > 0) {
|
| 367 | |
| 368 | if ($#{$def{$name}} == 1 &&
|
| 369 | ($name =~ /^sys_/ || $name =~ /^compat_sys_/ ||
|
| 370 | $name =~ /^sys32_/)) {
|
| 371 | if($def{$name}[0] eq "kernel/sys_ni.o" ||
|
| 372 | $def{$name}[1] eq "kernel/sys_ni.o") {
|
| 373 | &drop_def("kernel/sys_ni.o", $name);
|
| 374 | next;
|
| 375 | }
|
| 376 | }
|
| 377 |
|
| 378 | printf "$name is multiply defined in :-\n";
|
| 379 | foreach my $module (@{$def{$name}}) {
|
| 380 | printf "\t$module\n";
|
| 381 | }
|
| 382 | }
|
| 383 | }
|
| 384 | }
|
| 385 |
|
| 386 | sub resolve_external_references
|
| 387 | {
|
| 388 | my ($kstrtab, $ksymtab, $export);
|
| 389 |
|
| 390 | printf "\n";
|
| 391 | foreach my $object (keys(%nmdata)) {
|
| 392 | my $nmdata = $nmdata{$object};
|
| 393 | for (my $i = 0; $i <= $#{$nmdata}; ++$i) {
|
| 394 | my ($type, $name) = split(' ', $nmdata->[$i], 2);
|
| 395 | if ($type eq "U" || $type eq "w") {
|
| 396 | if (exists($def{$name}) || exists($ksymtab{$name})) {
|
| 397 | |
| 398 | $nmdata->[$i] = "$type $name $object";
|
| 399 | |
| 400 | $kstrtab = "R __kstrtab_$name";
|
| 401 | $ksymtab = "R __ksymtab_$name";
|
| 402 | $export = 0;
|
| 403 | for (my $j = 0; $j <= $#{$nmdata}; ++$j) {
|
| 404 | if ($nmdata->[$j] eq $kstrtab ||
|
| 405 | $nmdata->[$j] eq $ksymtab) {
|
| 406 | $export = 1;
|
| 407 | last;
|
| 408 | }
|
| 409 | }
|
| 410 | if ($export) {
|
| 411 | $export{$name} = "";
|
| 412 | }
|
| 413 | else {
|
| 414 | $ref{$name} = ""
|
| 415 | }
|
| 416 | }
|
| 417 | elsif ( ! $nameexception{$name}
|
| 418 | && $name !~ /^__sched_text_/
|
| 419 | && $name !~ /^__start_/
|
| 420 | && $name !~ /^__end_/
|
| 421 | && $name !~ /^__stop_/
|
| 422 | && $name !~ /^__scheduling_functions_.*_here/
|
| 423 | && $name !~ /^__.*initcall_/
|
| 424 | && $name !~ /^__.*per_cpu_start/
|
| 425 | && $name !~ /^__.*per_cpu_end/
|
| 426 | && $name !~ /^__alt_instructions/
|
| 427 | && $name !~ /^__setup_/
|
| 428 | && $name !~ /^__mod_timer/
|
| 429 | && $name !~ /^__mod_page_state/
|
| 430 | && $name !~ /^init_module/
|
| 431 | && $name !~ /^cleanup_module/
|
| 432 | ) {
|
| 433 | printf "Cannot resolve ";
|
| 434 | printf "weak " if ($type eq "w");
|
| 435 | printf "reference to $name from $object\n";
|
| 436 | }
|
| 437 | }
|
| 438 | }
|
| 439 | }
|
| 440 | }
|
| 441 |
|
| 442 | sub list_extra_externals
|
| 443 | {
|
| 444 | my %noref = ();
|
| 445 |
|
| 446 | foreach my $name (keys(%def)) {
|
| 447 | if (! exists($ref{$name})) {
|
| 448 | my @module = @{$def{$name}};
|
| 449 | foreach my $module (@module) {
|
| 450 | if (! exists($noref{$module})) {
|
| 451 | $noref{$module} = [];
|
| 452 | }
|
| 453 | push(@{$noref{$module}}, $name);
|
| 454 | }
|
| 455 | }
|
| 456 | }
|
| 457 | if (%noref) {
|
| 458 | printf "\nExternally defined symbols with no external references\n";
|
| 459 | foreach my $module (sort(keys(%noref))) {
|
| 460 | printf " $module\n";
|
| 461 | foreach (sort(@{$noref{$module}})) {
|
| 462 | my $export;
|
| 463 | if (exists($export{$_})) {
|
| 464 | $export = " (export only)";
|
| 465 | } else {
|
| 466 | $export = "";
|
| 467 | }
|
| 468 | printf " $_$export\n";
|
| 469 | }
|
| 470 | }
|
| 471 | }
|
| 472 | }
|