reference_init.pl 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. #!/usr/bin/perl -w
  2. #
  3. # reference_init.pl (C) Keith Owens 2002 <kaos@ocs.com.au>
  4. #
  5. # List references to vmlinux init sections from non-init sections.
  6. # Unfortunately I had to exclude references from read only data to .init
  7. # sections, almost all of these are false positives, they are created by
  8. # gcc. The downside of excluding rodata is that there really are some
  9. # user references from rodata to init code, e.g. drivers/video/vgacon.c
  10. #
  11. # const struct consw vga_con = {
  12. # con_startup: vgacon_startup,
  13. #
  14. # where vgacon_startup is __init. If you want to wade through the false
  15. # positives, take out the check for rodata.
  16. use strict;
  17. die($0 . " takes no arguments\n") if($#ARGV >= 0);
  18. my %object;
  19. my $object;
  20. my $line;
  21. my $ignore;
  22. $| = 1;
  23. printf("Finding objects, ");
  24. open(OBJDUMP_LIST, "find . -name '*.o' | xargs objdump -h |") || die "getting objdump list failed";
  25. while (defined($line = <OBJDUMP_LIST>)) {
  26. chomp($line);
  27. if ($line =~ /:\s+file format/) {
  28. ($object = $line) =~ s/:.*//;
  29. $object{$object}->{'module'} = 0;
  30. $object{$object}->{'size'} = 0;
  31. $object{$object}->{'off'} = 0;
  32. }
  33. if ($line =~ /^\s*\d+\s+\.modinfo\s+/) {
  34. $object{$object}->{'module'} = 1;
  35. }
  36. if ($line =~ /^\s*\d+\s+\.comment\s+/) {
  37. ($object{$object}->{'size'}, $object{$object}->{'off'}) = (split(' ', $line))[2,5];
  38. }
  39. }
  40. close(OBJDUMP_LIST);
  41. printf("%d objects, ", scalar keys(%object));
  42. $ignore = 0;
  43. foreach $object (keys(%object)) {
  44. if ($object{$object}->{'module'}) {
  45. ++$ignore;
  46. delete($object{$object});
  47. }
  48. }
  49. printf("ignoring %d module(s)\n", $ignore);
  50. # Ignore conglomerate objects, they have been built from multiple objects and we
  51. # only care about the individual objects. If an object has more than one GCC:
  52. # string in the comment section then it is conglomerate. This does not filter
  53. # out conglomerates that consist of exactly one object, can't be helped.
  54. printf("Finding conglomerates, ");
  55. $ignore = 0;
  56. foreach $object (keys(%object)) {
  57. if (exists($object{$object}->{'off'})) {
  58. my ($off, $size, $comment, $l);
  59. $off = hex($object{$object}->{'off'});
  60. $size = hex($object{$object}->{'size'});
  61. open(OBJECT, "<$object") || die "cannot read $object";
  62. seek(OBJECT, $off, 0) || die "seek to $off in $object failed";
  63. $l = read(OBJECT, $comment, $size);
  64. die "read $size bytes from $object .comment failed" if ($l != $size);
  65. close(OBJECT);
  66. if ($comment =~ /GCC\:.*GCC\:/m || $object =~ /built-in\.o/) {
  67. ++$ignore;
  68. delete($object{$object});
  69. }
  70. }
  71. }
  72. printf("ignoring %d conglomerate(s)\n", $ignore);
  73. printf("Scanning objects\n");
  74. foreach $object (sort(keys(%object))) {
  75. my $from;
  76. open(OBJDUMP, "objdump -r $object|") || die "cannot objdump -r $object";
  77. while (defined($line = <OBJDUMP>)) {
  78. chomp($line);
  79. if ($line =~ /RELOCATION RECORDS FOR /) {
  80. ($from = $line) =~ s/.*\[([^]]*).*/$1/;
  81. }
  82. if (($line =~ /\.init$/ || $line =~ /\.init\./) &&
  83. ($from !~ /\.init$/ &&
  84. $from !~ /\.init\./ &&
  85. $from !~ /\.stab$/ &&
  86. $from !~ /\.rodata$/ &&
  87. $from !~ /\.text\.lock$/ &&
  88. $from !~ /\.pci_fixup_header$/ &&
  89. $from !~ /\.pci_fixup_final$/ &&
  90. $from !~ /\.pdr$/ &&
  91. $from !~ /\__param$/ &&
  92. $from !~ /\.altinstructions/ &&
  93. $from !~ /\.eh_frame/ &&
  94. $from !~ /\.debug_/)) {
  95. printf("Error: %s %s refers to %s\n", $object, $from, $line);
  96. }
  97. }
  98. close(OBJDUMP);
  99. }
  100. printf("Done\n");