namespace.pl 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  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. # V similar to W, but the value of the weak symbol becomes zero with no error.
  256. # a assembler equate
  257. # b static variable, uninitialised
  258. # d static variable, initialised
  259. # g static variable, initialised, small data section
  260. # r static array, initialised
  261. # s static variable, uninitialised, small bss
  262. # t static label/procedures
  263. # w weak external reference to text that has not been resolved
  264. # v similar to w
  265. # ? undefined type, used a lot by modules
  266. if ($type !~ /^[ABCDGRSTUWVabdgrstwv?]$/) {
  267. printf STDERR "nm output for $fullname contains unknown type '$_'\n";
  268. }
  269. elsif ($name =~ /\./) {
  270. # name with '.' is local static
  271. }
  272. else {
  273. $type = 'R' if ($type eq '?'); # binutils replaced ? with R at one point
  274. # binutils keeps changing the type for exported symbols, force it to R
  275. $type = 'R' if ($name =~ /^__ksymtab/ || $name =~ /^__kstrtab/);
  276. $name =~ s/_R[a-f0-9]{8}$//; # module versions adds this
  277. if ($type =~ /[ABCDGRSTWV]/ &&
  278. $name ne 'init_module' &&
  279. $name ne 'cleanup_module' &&
  280. $name ne 'Using_Versions' &&
  281. $name !~ /^Version_[0-9]+$/ &&
  282. $name !~ /^__parm_/ &&
  283. $name !~ /^__kstrtab/ &&
  284. $name !~ /^__ksymtab/ &&
  285. $name !~ /^__kcrctab_/ &&
  286. $name !~ /^__exitcall_/ &&
  287. $name !~ /^__initcall_/ &&
  288. $name !~ /^__kdb_initcall_/ &&
  289. $name !~ /^__kdb_exitcall_/ &&
  290. $name !~ /^__module_/ &&
  291. $name !~ /^__mod_/ &&
  292. $name !~ /^__crc_/ &&
  293. $name ne '__this_module' &&
  294. $name ne 'kernel_version') {
  295. if (!exists($def{$name})) {
  296. $def{$name} = [];
  297. }
  298. push(@{$def{$name}}, $fullname);
  299. }
  300. push(@nmdata, "$type $name");
  301. if ($name =~ /^__ksymtab_/) {
  302. $name = substr($name, 10);
  303. if (!exists($ksymtab{$name})) {
  304. $ksymtab{$name} = [];
  305. }
  306. push(@{$ksymtab{$name}}, $fullname);
  307. }
  308. }
  309. }
  310. close($nmdata);
  311. if ($#nmdata < 0) {
  312. printf "No nm data for $fullname\n"
  313. unless $nmexception{$fullname};
  314. return;
  315. }
  316. $nmdata{$fullname} = \@nmdata;
  317. }
  318. sub drop_def
  319. {
  320. my ($object, $name) = @_;
  321. my $nmdata = $nmdata{$object};
  322. my ($i, $j);
  323. for ($i = 0; $i <= $#{$nmdata}; ++$i) {
  324. if ($name eq (split(' ', $nmdata->[$i], 2))[1]) {
  325. splice(@{$nmdata{$object}}, $i, 1);
  326. my $def = $def{$name};
  327. for ($j = 0; $j < $#{$def{$name}}; ++$j) {
  328. if ($def{$name}[$j] eq $object) {
  329. splice(@{$def{$name}}, $j, 1);
  330. }
  331. }
  332. last;
  333. }
  334. }
  335. }
  336. sub list_multiply_defined
  337. {
  338. foreach my $name (keys(%def)) {
  339. if ($#{$def{$name}} > 0) {
  340. # Special case for cond_syscall
  341. if ($#{$def{$name}} == 1 && $name =~ /^sys_/) {
  342. if($def{$name}[0] eq "kernel/sys_ni.o" ||
  343. $def{$name}[1] eq "kernel/sys_ni.o") {
  344. &drop_def("kernel/sys_ni.o", $name);
  345. next;
  346. }
  347. }
  348. # Special case for i386 entry code
  349. if ($#{$def{$name}} == 1 && $name =~ /^__kernel_/ &&
  350. $def{$name}[0] eq "arch/x86/kernel/vsyscall-int80_32.o" &&
  351. $def{$name}[1] eq "arch/x86/kernel/vsyscall-sysenter_32.o") {
  352. &drop_def("arch/x86/kernel/vsyscall-sysenter_32.o", $name);
  353. next;
  354. }
  355. printf "$name is multiply defined in :-\n";
  356. foreach my $module (@{$def{$name}}) {
  357. printf "\t$module\n";
  358. }
  359. }
  360. }
  361. }
  362. sub resolve_external_references
  363. {
  364. my ($kstrtab, $ksymtab, $export);
  365. printf "\n";
  366. foreach my $object (keys(%nmdata)) {
  367. my $nmdata = $nmdata{$object};
  368. for (my $i = 0; $i <= $#{$nmdata}; ++$i) {
  369. my ($type, $name) = split(' ', $nmdata->[$i], 2);
  370. if ($type eq "U" || $type eq "w") {
  371. if (exists($def{$name}) || exists($ksymtab{$name})) {
  372. # add the owning object to the nmdata
  373. $nmdata->[$i] = "$type $name $object";
  374. # only count as a reference if it is not EXPORT_...
  375. $kstrtab = "R __kstrtab_$name";
  376. $ksymtab = "R __ksymtab_$name";
  377. $export = 0;
  378. for (my $j = 0; $j <= $#{$nmdata}; ++$j) {
  379. if ($nmdata->[$j] eq $kstrtab ||
  380. $nmdata->[$j] eq $ksymtab) {
  381. $export = 1;
  382. last;
  383. }
  384. }
  385. if ($export) {
  386. $export{$name} = "";
  387. }
  388. else {
  389. $ref{$name} = ""
  390. }
  391. }
  392. elsif ( ! $nameexception{$name}
  393. && $name !~ /^__sched_text_/
  394. && $name !~ /^__start_/
  395. && $name !~ /^__end_/
  396. && $name !~ /^__stop_/
  397. && $name !~ /^__scheduling_functions_.*_here/
  398. && $name !~ /^__.*initcall_/
  399. && $name !~ /^__.*per_cpu_start/
  400. && $name !~ /^__.*per_cpu_end/
  401. && $name !~ /^__alt_instructions/
  402. && $name !~ /^__setup_/
  403. && $name !~ /^__mod_timer/
  404. && $name !~ /^__mod_page_state/
  405. && $name !~ /^init_module/
  406. && $name !~ /^cleanup_module/
  407. ) {
  408. printf "Cannot resolve ";
  409. printf "weak " if ($type eq "w");
  410. printf "reference to $name from $object\n";
  411. }
  412. }
  413. }
  414. }
  415. }
  416. sub list_extra_externals
  417. {
  418. my %noref = ();
  419. foreach my $name (keys(%def)) {
  420. if (! exists($ref{$name})) {
  421. my @module = @{$def{$name}};
  422. foreach my $module (@module) {
  423. if (! exists($noref{$module})) {
  424. $noref{$module} = [];
  425. }
  426. push(@{$noref{$module}}, $name);
  427. }
  428. }
  429. }
  430. if (%noref) {
  431. printf "\nExternally defined symbols with no external references\n";
  432. foreach my $module (sort(keys(%noref))) {
  433. printf " $module\n";
  434. foreach (sort(@{$noref{$module}})) {
  435. my $export;
  436. if (exists($export{$_})) {
  437. $export = " (export only)";
  438. } else {
  439. $export = "";
  440. }
  441. printf " $_$export\n";
  442. }
  443. }
  444. }
  445. }