namespace.pl 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. #!/usr/bin/env perl
  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. use warnings;
  65. use strict;
  66. use File::Find;
  67. use File::Spec;
  68. my $nm = ($ENV{'NM'} || "nm") . " -p";
  69. my $objdump = ($ENV{'OBJDUMP'} || "objdump") . " -s -j .comment";
  70. my $srctree = File::Spec->curdir();
  71. my $objtree = File::Spec->curdir();
  72. $srctree = File::Spec->rel2abs($ENV{'srctree'}) if (exists($ENV{'srctree'}));
  73. $objtree = File::Spec->rel2abs($ENV{'objtree'}) if (exists($ENV{'objtree'}));
  74. if ($#ARGV != -1) {
  75. print STDERR "usage: $0 takes no parameters\n";
  76. die("giving up\n");
  77. }
  78. my %nmdata = (); # nm data for each object
  79. my %def = (); # all definitions for each name
  80. my %ksymtab = (); # names that appear in __ksymtab_
  81. my %ref = (); # $ref{$name} exists if there is a true external reference to $name
  82. my %export = (); # $export{$name} exists if there is an EXPORT_... of $name
  83. my %nmexception = (
  84. 'fs/ext3/bitmap' => 1,
  85. 'fs/ext4/bitmap' => 1,
  86. 'arch/x86/lib/thunk_32' => 1,
  87. 'arch/x86/lib/cmpxchg' => 1,
  88. 'arch/x86/vdso/vdso32/note' => 1,
  89. 'lib/irq_regs' => 1,
  90. 'usr/initramfs_data' => 1,
  91. 'drivers/scsi/aic94xx/aic94xx_dump' => 1,
  92. 'drivers/scsi/libsas/sas_dump' => 1,
  93. 'lib/dec_and_lock' => 1,
  94. 'drivers/ide/ide-probe-mini' => 1,
  95. 'usr/initramfs_data' => 1,
  96. 'drivers/acpi/acpia/exdump' => 1,
  97. 'drivers/acpi/acpia/rsdump' => 1,
  98. 'drivers/acpi/acpia/nsdumpdv' => 1,
  99. 'drivers/acpi/acpia/nsdump' => 1,
  100. 'arch/ia64/sn/kernel/sn2/io' => 1,
  101. 'arch/ia64/kernel/gate-data' => 1,
  102. 'security/capability' => 1,
  103. 'fs/ntfs/sysctl' => 1,
  104. 'fs/jfs/jfs_debug' => 1,
  105. );
  106. my %nameexception = (
  107. 'mod_use_count_' => 1,
  108. '__initramfs_end' => 1,
  109. '__initramfs_start' => 1,
  110. '_einittext' => 1,
  111. '_sinittext' => 1,
  112. 'kallsyms_names' => 1,
  113. 'kallsyms_num_syms' => 1,
  114. 'kallsyms_addresses'=> 1,
  115. 'kallsyms_offsets' => 1,
  116. 'kallsyms_relative_base'=> 1,
  117. '__this_module' => 1,
  118. '_etext' => 1,
  119. '_edata' => 1,
  120. '_end' => 1,
  121. '__bss_start' => 1,
  122. '_text' => 1,
  123. '_stext' => 1,
  124. '__gp' => 1,
  125. 'ia64_unw_start' => 1,
  126. 'ia64_unw_end' => 1,
  127. '__init_begin' => 1,
  128. '__init_end' => 1,
  129. '__bss_stop' => 1,
  130. '__nosave_begin' => 1,
  131. '__nosave_end' => 1,
  132. 'pg0' => 1,
  133. 'vdso_enabled' => 1,
  134. '__stack_chk_fail' => 1,
  135. 'VDSO32_PRELINK' => 1,
  136. 'VDSO32_vsyscall' => 1,
  137. 'VDSO32_rt_sigreturn'=>1,
  138. 'VDSO32_sigreturn' => 1,
  139. );
  140. &find(\&linux_objects, '.'); # find the objects and do_nm on them
  141. &list_multiply_defined();
  142. &resolve_external_references();
  143. &list_extra_externals();
  144. exit(0);
  145. sub linux_objects
  146. {
  147. # Select objects, ignoring objects which are only created by
  148. # merging other objects. Also ignore all of modules, scripts
  149. # and compressed. Most conglomerate objects are handled by do_nm,
  150. # this list only contains the special cases. These include objects
  151. # that are linked from just one other object and objects for which
  152. # there is really no permanent source file.
  153. my $basename = $_;
  154. $_ = $File::Find::name;
  155. s:^\./::;
  156. if (/.*\.o$/ &&
  157. ! (
  158. m:/built-in.a$:
  159. || m:arch/x86/vdso/:
  160. || m:arch/x86/boot/:
  161. || m:arch/ia64/ia32/ia32.o$:
  162. || m:arch/ia64/kernel/gate-syms.o$:
  163. || m:arch/ia64/lib/__divdi3.o$:
  164. || m:arch/ia64/lib/__divsi3.o$:
  165. || m:arch/ia64/lib/__moddi3.o$:
  166. || m:arch/ia64/lib/__modsi3.o$:
  167. || m:arch/ia64/lib/__udivdi3.o$:
  168. || m:arch/ia64/lib/__udivsi3.o$:
  169. || m:arch/ia64/lib/__umoddi3.o$:
  170. || m:arch/ia64/lib/__umodsi3.o$:
  171. || m:arch/ia64/scripts/check_gas_for_hint.o$:
  172. || m:arch/ia64/sn/kernel/xp.o$:
  173. || m:boot/bbootsect.o$:
  174. || m:boot/bsetup.o$:
  175. || m:/bootsect.o$:
  176. || m:/boot/setup.o$:
  177. || m:/compressed/:
  178. || m:drivers/cdrom/driver.o$:
  179. || m:drivers/char/drm/tdfx_drv.o$:
  180. || m:drivers/ide/ide-detect.o$:
  181. || m:drivers/ide/pci/idedriver-pci.o$:
  182. || m:drivers/media/media.o$:
  183. || m:drivers/scsi/sd_mod.o$:
  184. || m:drivers/video/video.o$:
  185. || m:fs/devpts/devpts.o$:
  186. || m:fs/exportfs/exportfs.o$:
  187. || m:fs/hugetlbfs/hugetlbfs.o$:
  188. || m:fs/msdos/msdos.o$:
  189. || m:fs/nls/nls.o$:
  190. || m:fs/ramfs/ramfs.o$:
  191. || m:fs/romfs/romfs.o$:
  192. || m:fs/vfat/vfat.o$:
  193. || m:init/mounts.o$:
  194. || m:^modules/:
  195. || m:net/netlink/netlink.o$:
  196. || m:net/sched/sched.o$:
  197. || m:/piggy.o$:
  198. || m:^scripts/:
  199. || m:sound/.*/snd-:
  200. || m:^.*/\.tmp_:
  201. || m:^\.tmp_:
  202. || m:/vmlinux-obj.o$:
  203. || m:^tools/:
  204. )
  205. ) {
  206. do_nm($basename, $_);
  207. }
  208. $_ = $basename; # File::Find expects $_ untouched (undocumented)
  209. }
  210. sub do_nm
  211. {
  212. my ($basename, $fullname) = @_;
  213. my ($source, $type, $name);
  214. if (! -e $basename) {
  215. printf STDERR "$basename does not exist\n";
  216. return;
  217. }
  218. if ($fullname !~ /\.o$/) {
  219. printf STDERR "$fullname is not an object file\n";
  220. return;
  221. }
  222. ($source = $basename) =~ s/\.o$//;
  223. if (-e "$source.c" || -e "$source.S") {
  224. $source = File::Spec->catfile($objtree, $File::Find::dir, $source)
  225. } else {
  226. $source = File::Spec->catfile($srctree, $File::Find::dir, $source)
  227. }
  228. if (! -e "$source.c" && ! -e "$source.S") {
  229. # No obvious source, exclude the object if it is conglomerate
  230. open(my $objdumpdata, "$objdump $basename|")
  231. or die "$objdump $fullname failed $!\n";
  232. my $comment;
  233. while (<$objdumpdata>) {
  234. chomp();
  235. if (/^In archive/) {
  236. # Archives are always conglomerate
  237. $comment = "GCC:GCC:";
  238. last;
  239. }
  240. next if (! /^[ 0-9a-f]{5,} /);
  241. $comment .= substr($_, 43);
  242. }
  243. close($objdumpdata);
  244. if (!defined($comment) || $comment !~ /GCC\:.*GCC\:/m) {
  245. printf STDERR "No source file found for $fullname\n";
  246. }
  247. return;
  248. }
  249. open (my $nmdata, "$nm $basename|")
  250. or die "$nm $fullname failed $!\n";
  251. my @nmdata;
  252. while (<$nmdata>) {
  253. chop;
  254. ($type, $name) = (split(/ +/, $_, 3))[1..2];
  255. # Expected types
  256. # A absolute symbol
  257. # B weak external reference to data that has been resolved
  258. # C global variable, uninitialised
  259. # D global variable, initialised
  260. # G global variable, initialised, small data section
  261. # R global array, initialised
  262. # S global variable, uninitialised, small bss
  263. # T global label/procedure
  264. # U external reference
  265. # W weak external reference to text that has been resolved
  266. # V similar to W, but the value of the weak symbol becomes zero with no error.
  267. # a assembler equate
  268. # b static variable, uninitialised
  269. # d static variable, initialised
  270. # g static variable, initialised, small data section
  271. # r static array, initialised
  272. # s static variable, uninitialised, small bss
  273. # t static label/procedures
  274. # w weak external reference to text that has not been resolved
  275. # v similar to w
  276. # ? undefined type, used a lot by modules
  277. if ($type !~ /^[ABCDGRSTUWVabdgrstwv?]$/) {
  278. printf STDERR "nm output for $fullname contains unknown type '$_'\n";
  279. }
  280. elsif ($name =~ /\./) {
  281. # name with '.' is local static
  282. }
  283. else {
  284. $type = 'R' if ($type eq '?'); # binutils replaced ? with R at one point
  285. # binutils keeps changing the type for exported symbols, force it to R
  286. $type = 'R' if ($name =~ /^__ksymtab/ || $name =~ /^__kstrtab/);
  287. $name =~ s/_R[a-f0-9]{8}$//; # module versions adds this
  288. if ($type =~ /[ABCDGRSTWV]/ &&
  289. $name ne 'init_module' &&
  290. $name ne 'cleanup_module' &&
  291. $name ne 'Using_Versions' &&
  292. $name !~ /^Version_[0-9]+$/ &&
  293. $name !~ /^__parm_/ &&
  294. $name !~ /^__kstrtab/ &&
  295. $name !~ /^__ksymtab/ &&
  296. $name !~ /^__kcrctab_/ &&
  297. $name !~ /^__exitcall_/ &&
  298. $name !~ /^__initcall_/ &&
  299. $name !~ /^__kdb_initcall_/ &&
  300. $name !~ /^__kdb_exitcall_/ &&
  301. $name !~ /^__module_/ &&
  302. $name !~ /^__mod_/ &&
  303. $name !~ /^__crc_/ &&
  304. $name ne '__this_module' &&
  305. $name ne 'kernel_version') {
  306. if (!exists($def{$name})) {
  307. $def{$name} = [];
  308. }
  309. push(@{$def{$name}}, $fullname);
  310. }
  311. push(@nmdata, "$type $name");
  312. if ($name =~ /^__ksymtab_/) {
  313. $name = substr($name, 10);
  314. if (!exists($ksymtab{$name})) {
  315. $ksymtab{$name} = [];
  316. }
  317. push(@{$ksymtab{$name}}, $fullname);
  318. }
  319. }
  320. }
  321. close($nmdata);
  322. if ($#nmdata < 0) {
  323. printf "No nm data for $fullname\n"
  324. unless $nmexception{$fullname};
  325. return;
  326. }
  327. $nmdata{$fullname} = \@nmdata;
  328. }
  329. sub drop_def
  330. {
  331. my ($object, $name) = @_;
  332. my $nmdata = $nmdata{$object};
  333. my ($i, $j);
  334. for ($i = 0; $i <= $#{$nmdata}; ++$i) {
  335. if ($name eq (split(' ', $nmdata->[$i], 2))[1]) {
  336. splice(@{$nmdata{$object}}, $i, 1);
  337. my $def = $def{$name};
  338. for ($j = 0; $j < $#{$def{$name}}; ++$j) {
  339. if ($def{$name}[$j] eq $object) {
  340. splice(@{$def{$name}}, $j, 1);
  341. }
  342. }
  343. last;
  344. }
  345. }
  346. }
  347. sub list_multiply_defined
  348. {
  349. foreach my $name (keys(%def)) {
  350. if ($#{$def{$name}} > 0) {
  351. # Special case for cond_syscall
  352. if ($#{$def{$name}} == 1 &&
  353. ($name =~ /^sys_/ || $name =~ /^compat_sys_/ ||
  354. $name =~ /^sys32_/)) {
  355. if($def{$name}[0] eq "kernel/sys_ni.o" ||
  356. $def{$name}[1] eq "kernel/sys_ni.o") {
  357. &drop_def("kernel/sys_ni.o", $name);
  358. next;
  359. }
  360. }
  361. printf "$name is multiply defined in :-\n";
  362. foreach my $module (@{$def{$name}}) {
  363. printf "\t$module\n";
  364. }
  365. }
  366. }
  367. }
  368. sub resolve_external_references
  369. {
  370. my ($kstrtab, $ksymtab, $export);
  371. printf "\n";
  372. foreach my $object (keys(%nmdata)) {
  373. my $nmdata = $nmdata{$object};
  374. for (my $i = 0; $i <= $#{$nmdata}; ++$i) {
  375. my ($type, $name) = split(' ', $nmdata->[$i], 2);
  376. if ($type eq "U" || $type eq "w") {
  377. if (exists($def{$name}) || exists($ksymtab{$name})) {
  378. # add the owning object to the nmdata
  379. $nmdata->[$i] = "$type $name $object";
  380. # only count as a reference if it is not EXPORT_...
  381. $kstrtab = "R __kstrtab_$name";
  382. $ksymtab = "R __ksymtab_$name";
  383. $export = 0;
  384. for (my $j = 0; $j <= $#{$nmdata}; ++$j) {
  385. if ($nmdata->[$j] eq $kstrtab ||
  386. $nmdata->[$j] eq $ksymtab) {
  387. $export = 1;
  388. last;
  389. }
  390. }
  391. if ($export) {
  392. $export{$name} = "";
  393. }
  394. else {
  395. $ref{$name} = ""
  396. }
  397. }
  398. elsif ( ! $nameexception{$name}
  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 !~ /^__mod_timer/
  410. && $name !~ /^__mod_page_state/
  411. && $name !~ /^init_module/
  412. && $name !~ /^cleanup_module/
  413. ) {
  414. printf "Cannot resolve ";
  415. printf "weak " if ($type eq "w");
  416. printf "reference to $name from $object\n";
  417. }
  418. }
  419. }
  420. }
  421. }
  422. sub list_extra_externals
  423. {
  424. my %noref = ();
  425. foreach my $name (keys(%def)) {
  426. if (! exists($ref{$name})) {
  427. my @module = @{$def{$name}};
  428. foreach my $module (@module) {
  429. if (! exists($noref{$module})) {
  430. $noref{$module} = [];
  431. }
  432. push(@{$noref{$module}}, $name);
  433. }
  434. }
  435. }
  436. if (%noref) {
  437. printf "\nExternally defined symbols with no external references\n";
  438. foreach my $module (sort(keys(%noref))) {
  439. printf " $module\n";
  440. foreach (sort(@{$noref{$module}})) {
  441. my $export;
  442. if (exists($export{$_})) {
  443. $export = " (export only)";
  444. } else {
  445. $export = "";
  446. }
  447. printf " $_$export\n";
  448. }
  449. }
  450. }
  451. }