namespace.pl 13 KB

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