namespace.pl 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  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. 'vdso_enabled' => 1,
  131. '__stack_chk_fail' => 1,
  132. 'VDSO32_PRELINK' => 1,
  133. 'VDSO32_vsyscall' => 1,
  134. 'VDSO32_rt_sigreturn'=>1,
  135. 'VDSO32_sigreturn' => 1,
  136. );
  137. &find(\&linux_objects, '.'); # find the objects and do_nm on them
  138. &list_multiply_defined();
  139. &resolve_external_references();
  140. &list_extra_externals();
  141. exit(0);
  142. sub linux_objects
  143. {
  144. # Select objects, ignoring objects which are only created by
  145. # merging other objects. Also ignore all of modules, scripts
  146. # and compressed. Most conglomerate objects are handled by do_nm,
  147. # this list only contains the special cases. These include objects
  148. # that are linked from just one other object and objects for which
  149. # there is really no permanent source file.
  150. my $basename = $_;
  151. $_ = $File::Find::name;
  152. s:^\./::;
  153. if (/.*\.o$/ &&
  154. ! (
  155. m:/built-in.o$:
  156. || m:arch/x86/vdso/:
  157. || m:arch/x86/boot/:
  158. || m:arch/ia64/ia32/ia32.o$:
  159. || m:arch/ia64/kernel/gate-syms.o$:
  160. || m:arch/ia64/lib/__divdi3.o$:
  161. || m:arch/ia64/lib/__divsi3.o$:
  162. || m:arch/ia64/lib/__moddi3.o$:
  163. || m:arch/ia64/lib/__modsi3.o$:
  164. || m:arch/ia64/lib/__udivdi3.o$:
  165. || m:arch/ia64/lib/__udivsi3.o$:
  166. || m:arch/ia64/lib/__umoddi3.o$:
  167. || m:arch/ia64/lib/__umodsi3.o$:
  168. || m:arch/ia64/scripts/check_gas_for_hint.o$:
  169. || m:arch/ia64/sn/kernel/xp.o$:
  170. || m:boot/bbootsect.o$:
  171. || m:boot/bsetup.o$:
  172. || m:/bootsect.o$:
  173. || m:/boot/setup.o$:
  174. || m:/compressed/:
  175. || m:drivers/cdrom/driver.o$:
  176. || m:drivers/char/drm/tdfx_drv.o$:
  177. || m:drivers/ide/ide-detect.o$:
  178. || m:drivers/ide/pci/idedriver-pci.o$:
  179. || m:drivers/media/media.o$:
  180. || m:drivers/scsi/sd_mod.o$:
  181. || m:drivers/video/video.o$:
  182. || m:fs/devpts/devpts.o$:
  183. || m:fs/exportfs/exportfs.o$:
  184. || m:fs/hugetlbfs/hugetlbfs.o$:
  185. || m:fs/msdos/msdos.o$:
  186. || m:fs/nls/nls.o$:
  187. || m:fs/ramfs/ramfs.o$:
  188. || m:fs/romfs/romfs.o$:
  189. || m:fs/vfat/vfat.o$:
  190. || m:init/mounts.o$:
  191. || m:^modules/:
  192. || m:net/netlink/netlink.o$:
  193. || m:net/sched/sched.o$:
  194. || m:/piggy.o$:
  195. || m:^scripts/:
  196. || m:sound/.*/snd-:
  197. || m:^.*/\.tmp_:
  198. || m:^\.tmp_:
  199. || m:/vmlinux-obj.o$:
  200. || m:^tools/:
  201. )
  202. ) {
  203. do_nm($basename, $_);
  204. }
  205. $_ = $basename; # File::Find expects $_ untouched (undocumented)
  206. }
  207. sub do_nm
  208. {
  209. my ($basename, $fullname) = @_;
  210. my ($source, $type, $name);
  211. if (! -e $basename) {
  212. printf STDERR "$basename does not exist\n";
  213. return;
  214. }
  215. if ($fullname !~ /\.o$/) {
  216. printf STDERR "$fullname is not an object file\n";
  217. return;
  218. }
  219. ($source = $basename) =~ s/\.o$//;
  220. if (-e "$source.c" || -e "$source.S") {
  221. $source = "$objtree$File::Find::dir/$source";
  222. } else {
  223. $source = "$srctree$File::Find::dir/$source";
  224. }
  225. if (! -e "$source.c" && ! -e "$source.S") {
  226. # No obvious source, exclude the object if it is conglomerate
  227. open(my $objdumpdata, "$objdump $basename|")
  228. or die "$objdump $fullname failed $!\n";
  229. my $comment;
  230. while (<$objdumpdata>) {
  231. chomp();
  232. if (/^In archive/) {
  233. # Archives are always conglomerate
  234. $comment = "GCC:GCC:";
  235. last;
  236. }
  237. next if (! /^[ 0-9a-f]{5,} /);
  238. $comment .= substr($_, 43);
  239. }
  240. close($objdumpdata);
  241. if (!defined($comment) || $comment !~ /GCC\:.*GCC\:/m) {
  242. printf STDERR "No source file found for $fullname\n";
  243. }
  244. return;
  245. }
  246. open (my $nmdata, "$nm $basename|")
  247. or die "$nm $fullname failed $!\n";
  248. my @nmdata;
  249. while (<$nmdata>) {
  250. chop;
  251. ($type, $name) = (split(/ +/, $_, 3))[1..2];
  252. # Expected types
  253. # A absolute symbol
  254. # B weak external reference to data that has been resolved
  255. # C global variable, uninitialised
  256. # D global variable, initialised
  257. # G global variable, initialised, small data section
  258. # R global array, initialised
  259. # S global variable, uninitialised, small bss
  260. # T global label/procedure
  261. # U external reference
  262. # W weak external reference to text that has been resolved
  263. # V similar to W, but the value of the weak symbol becomes zero with no error.
  264. # a assembler equate
  265. # b static variable, uninitialised
  266. # d static variable, initialised
  267. # g static variable, initialised, small data section
  268. # r static array, initialised
  269. # s static variable, uninitialised, small bss
  270. # t static label/procedures
  271. # w weak external reference to text that has not been resolved
  272. # v similar to w
  273. # ? undefined type, used a lot by modules
  274. if ($type !~ /^[ABCDGRSTUWVabdgrstwv?]$/) {
  275. printf STDERR "nm output for $fullname contains unknown type '$_'\n";
  276. }
  277. elsif ($name =~ /\./) {
  278. # name with '.' is local static
  279. }
  280. else {
  281. $type = 'R' if ($type eq '?'); # binutils replaced ? with R at one point
  282. # binutils keeps changing the type for exported symbols, force it to R
  283. $type = 'R' if ($name =~ /^__ksymtab/ || $name =~ /^__kstrtab/);
  284. $name =~ s/_R[a-f0-9]{8}$//; # module versions adds this
  285. if ($type =~ /[ABCDGRSTWV]/ &&
  286. $name ne 'init_module' &&
  287. $name ne 'cleanup_module' &&
  288. $name ne 'Using_Versions' &&
  289. $name !~ /^Version_[0-9]+$/ &&
  290. $name !~ /^__parm_/ &&
  291. $name !~ /^__kstrtab/ &&
  292. $name !~ /^__ksymtab/ &&
  293. $name !~ /^__kcrctab_/ &&
  294. $name !~ /^__exitcall_/ &&
  295. $name !~ /^__initcall_/ &&
  296. $name !~ /^__kdb_initcall_/ &&
  297. $name !~ /^__kdb_exitcall_/ &&
  298. $name !~ /^__module_/ &&
  299. $name !~ /^__mod_/ &&
  300. $name !~ /^__crc_/ &&
  301. $name ne '__this_module' &&
  302. $name ne 'kernel_version') {
  303. if (!exists($def{$name})) {
  304. $def{$name} = [];
  305. }
  306. push(@{$def{$name}}, $fullname);
  307. }
  308. push(@nmdata, "$type $name");
  309. if ($name =~ /^__ksymtab_/) {
  310. $name = substr($name, 10);
  311. if (!exists($ksymtab{$name})) {
  312. $ksymtab{$name} = [];
  313. }
  314. push(@{$ksymtab{$name}}, $fullname);
  315. }
  316. }
  317. }
  318. close($nmdata);
  319. if ($#nmdata < 0) {
  320. printf "No nm data for $fullname\n"
  321. unless $nmexception{$fullname};
  322. return;
  323. }
  324. $nmdata{$fullname} = \@nmdata;
  325. }
  326. sub drop_def
  327. {
  328. my ($object, $name) = @_;
  329. my $nmdata = $nmdata{$object};
  330. my ($i, $j);
  331. for ($i = 0; $i <= $#{$nmdata}; ++$i) {
  332. if ($name eq (split(' ', $nmdata->[$i], 2))[1]) {
  333. splice(@{$nmdata{$object}}, $i, 1);
  334. my $def = $def{$name};
  335. for ($j = 0; $j < $#{$def{$name}}; ++$j) {
  336. if ($def{$name}[$j] eq $object) {
  337. splice(@{$def{$name}}, $j, 1);
  338. }
  339. }
  340. last;
  341. }
  342. }
  343. }
  344. sub list_multiply_defined
  345. {
  346. foreach my $name (keys(%def)) {
  347. if ($#{$def{$name}} > 0) {
  348. # Special case for cond_syscall
  349. if ($#{$def{$name}} == 1 &&
  350. ($name =~ /^sys_/ || $name =~ /^compat_sys_/ ||
  351. $name =~ /^sys32_/)) {
  352. if($def{$name}[0] eq "kernel/sys_ni.o" ||
  353. $def{$name}[1] eq "kernel/sys_ni.o") {
  354. &drop_def("kernel/sys_ni.o", $name);
  355. next;
  356. }
  357. }
  358. printf "$name is multiply defined in :-\n";
  359. foreach my $module (@{$def{$name}}) {
  360. printf "\t$module\n";
  361. }
  362. }
  363. }
  364. }
  365. sub resolve_external_references
  366. {
  367. my ($kstrtab, $ksymtab, $export);
  368. printf "\n";
  369. foreach my $object (keys(%nmdata)) {
  370. my $nmdata = $nmdata{$object};
  371. for (my $i = 0; $i <= $#{$nmdata}; ++$i) {
  372. my ($type, $name) = split(' ', $nmdata->[$i], 2);
  373. if ($type eq "U" || $type eq "w") {
  374. if (exists($def{$name}) || exists($ksymtab{$name})) {
  375. # add the owning object to the nmdata
  376. $nmdata->[$i] = "$type $name $object";
  377. # only count as a reference if it is not EXPORT_...
  378. $kstrtab = "R __kstrtab_$name";
  379. $ksymtab = "R __ksymtab_$name";
  380. $export = 0;
  381. for (my $j = 0; $j <= $#{$nmdata}; ++$j) {
  382. if ($nmdata->[$j] eq $kstrtab ||
  383. $nmdata->[$j] eq $ksymtab) {
  384. $export = 1;
  385. last;
  386. }
  387. }
  388. if ($export) {
  389. $export{$name} = "";
  390. }
  391. else {
  392. $ref{$name} = ""
  393. }
  394. }
  395. elsif ( ! $nameexception{$name}
  396. && $name !~ /^__sched_text_/
  397. && $name !~ /^__start_/
  398. && $name !~ /^__end_/
  399. && $name !~ /^__stop_/
  400. && $name !~ /^__scheduling_functions_.*_here/
  401. && $name !~ /^__.*initcall_/
  402. && $name !~ /^__.*per_cpu_start/
  403. && $name !~ /^__.*per_cpu_end/
  404. && $name !~ /^__alt_instructions/
  405. && $name !~ /^__setup_/
  406. && $name !~ /^__mod_timer/
  407. && $name !~ /^__mod_page_state/
  408. && $name !~ /^init_module/
  409. && $name !~ /^cleanup_module/
  410. ) {
  411. printf "Cannot resolve ";
  412. printf "weak " if ($type eq "w");
  413. printf "reference to $name from $object\n";
  414. }
  415. }
  416. }
  417. }
  418. }
  419. sub list_extra_externals
  420. {
  421. my %noref = ();
  422. foreach my $name (keys(%def)) {
  423. if (! exists($ref{$name})) {
  424. my @module = @{$def{$name}};
  425. foreach my $module (@module) {
  426. if (! exists($noref{$module})) {
  427. $noref{$module} = [];
  428. }
  429. push(@{$noref{$module}}, $name);
  430. }
  431. }
  432. }
  433. if (%noref) {
  434. printf "\nExternally defined symbols with no external references\n";
  435. foreach my $module (sort(keys(%noref))) {
  436. printf " $module\n";
  437. foreach (sort(@{$noref{$module}})) {
  438. my $export;
  439. if (exists($export{$_})) {
  440. $export = " (export only)";
  441. } else {
  442. $export = "";
  443. }
  444. printf " $_$export\n";
  445. }
  446. }
  447. }
  448. }