You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

symcheck.pl 4.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. #!/usr/bin/perl -w
  2. use strict;
  3. use warnings;
  4. use constant WARNING_SIZE => 512;
  5. my $symtab = {};
  6. # Scan output of "nm -o -S bin/blib.a" and build up symbol table
  7. #
  8. while ( <> ) {
  9. chomp;
  10. ( my $object, undef, my $value, undef, my $size, my $type, my $symbol )
  11. = /^.*?:(.*?\.o):((\S+)(\s+(\S+))?)?\s+(\S)\s+(\S+)$/;
  12. $symtab->{$object}->{$symbol} = {
  13. global => ( $type eq uc $type ),
  14. type => ( $type ),
  15. value => ( $value ? hex ( $value ) : 0 ),
  16. size => ( $size ? hex ( $size ) : 0 ),
  17. };
  18. }
  19. # Add symbols that we know will be generated or required by the linker
  20. #
  21. foreach my $object ( keys %$symtab ) {
  22. my $obj_symbol = "obj_$object";
  23. $obj_symbol =~ s/\.o$//;
  24. $obj_symbol =~ s/\W/_/g;
  25. $symtab->{LINKER}->{$obj_symbol} = {
  26. global => 1,
  27. type => 'U',
  28. value => 0,
  29. size => 0,
  30. };
  31. }
  32. foreach my $link_sym qw ( _prefix _eprefix _decompress _edecompress _text
  33. _etext _data _edata _bss _ebss _end ) {
  34. $symtab->{LINKER}->{$link_sym} = {
  35. global => 1,
  36. type => 'A',
  37. value => 0,
  38. size => 0,
  39. };
  40. }
  41. # Build up requires, provides and shares symbol tables for global
  42. # symbols
  43. #
  44. my $globals = {};
  45. while ( ( my $object, my $symbols ) = each %$symtab ) {
  46. while ( ( my $symbol, my $info ) = each %$symbols ) {
  47. if ( $info->{global} ) {
  48. my $category = ( ( $info->{type} eq 'U' ? "requires" :
  49. ( $info->{type} eq 'C' ? "shares" : "provides" ) ) );
  50. $globals->{$symbol}->{$category}->{$object} = 1;
  51. }
  52. }
  53. }
  54. # Check for multiply defined, never-defined and unused global symbols
  55. #
  56. my $problems = {};
  57. while ( ( my $symbol, my $info ) = each %$globals ) {
  58. my @provides = keys %{$info->{provides}};
  59. my @requires = keys %{$info->{requires}};
  60. my @shares = keys %{$info->{shares}};
  61. if ( ( @provides == 0 ) && ( @shares == 1 ) ) {
  62. # A symbol "shared" by just a single file is actually being
  63. # provided by that file; it just doesn't have an initialiser.
  64. @provides = @shares;
  65. @shares = ();
  66. }
  67. if ( ( @requires > 0 ) && ( @provides == 0 ) ) {
  68. # No object provides this symbol, but some objects require it.
  69. $problems->{$_}->{nonexistent}->{$symbol} = 1 foreach @requires;
  70. }
  71. if ( ( @requires == 0 ) && ( @provides > 0 ) ) {
  72. # No object requires this symbol, but some objects provide it.
  73. $problems->{$_}->{unused}->{$symbol} = 1 foreach @provides;
  74. }
  75. if ( ( @shares > 0 ) && ( @requires > 0 ) ) {
  76. # A shared symbol is being referenced from another object
  77. $problems->{$_}->{shared}->{$symbol} = 1 foreach @requires;
  78. }
  79. if ( ( @shares > 0 ) && ( @provides > 0 ) ) {
  80. # A shared symbol is being initialised by an object
  81. $problems->{$_}->{shared}->{$symbol} = 1 foreach @provides;
  82. }
  83. if ( ( @shares > 0 ) && ! ( $symbol =~ /^_shared_/ ) ) {
  84. # A shared symbol is not declared via __shared
  85. $problems->{$_}->{shared}->{$symbol} = 1 foreach @shares;
  86. }
  87. if ( @provides > 1 ) {
  88. # A non-shared symbol is defined in multiple objects
  89. $problems->{$_}->{multiples}->{$symbol} = 1 foreach @provides;
  90. }
  91. }
  92. # Check for excessively large local symbols. Text and rodata symbols
  93. # are exempt from this check
  94. #
  95. while ( ( my $object, my $symbols ) = each %$symtab ) {
  96. while ( ( my $symbol, my $info ) = each %$symbols ) {
  97. if ( ( ! $info->{global} ) &&
  98. ( ! ( $info->{type} =~ /^(t|r)$/ ) ) &&
  99. ( $info->{size} >= WARNING_SIZE ) ) {
  100. $problems->{$object}->{large}->{$symbol} = 1;
  101. }
  102. }
  103. }
  104. # Print out error messages
  105. #
  106. my $errors = 0;
  107. my $warnings = 0;
  108. foreach my $object ( sort keys %$problems ) {
  109. my @nonexistent = sort keys %{$problems->{$object}->{nonexistent}};
  110. my @multiples = sort keys %{$problems->{$object}->{multiples}};
  111. my @unused = sort keys %{$problems->{$object}->{unused}};
  112. my @shared = sort keys %{$problems->{$object}->{shared}};
  113. my @large = sort keys %{$problems->{$object}->{large}};
  114. print "WARN $object provides unused symbol $_\n" foreach @unused;
  115. $warnings += @unused;
  116. print "WARN $object has large static symbol $_\n" foreach @large;
  117. $warnings += @large;
  118. print "ERR $object requires non-existent symbol $_\n" foreach @nonexistent;
  119. $errors += @nonexistent;
  120. foreach my $symbol ( @multiples ) {
  121. my @other_objects = sort grep { $_ ne $object }
  122. keys %{$globals->{$symbol}->{provides}};
  123. print "ERR $object provides symbol $symbol"
  124. ." (also provided by @other_objects)\n";
  125. }
  126. $errors += @multiples;
  127. print "ERR $object misuses shared symbol $_\n" foreach @shared;
  128. }
  129. print "$errors error(s), $warnings warning(s)\n";
  130. exit ( $errors ? 1 : 0 );