namespace.pl 13 KB

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