X-Git-Url: http://git.etherboot.org/people/indolent/gpxe.git/.git/blobdiff_plain/d94cb571434ab1339a7906893826f744327cb826..c3290aae5406e334830009cf5ce8d64d551e0f58:/src/util/symcheck.pl diff --git a/src/util/symcheck.pl b/src/util/symcheck.pl index 5fb3c954..6e46ae46 100755 --- a/src/util/symcheck.pl +++ b/src/util/symcheck.pl @@ -3,47 +3,141 @@ use strict; use warnings; -my $symbols = {}; +use constant WARNING_SIZE => 512; -# Scan output of "nm -o -g bin/blib.a" and build up symbol cross-ref table +my $symtab = {}; + +# Scan output of "objdump -w -t bin/blib.a" and build up symbol table # +my $object; while ( <> ) { chomp; - ( my $object, my $type, my $symbol ) = /^.*?:(.*?\.o):.*?\s(\S)\s(.*)$/; - my $category = $type eq 'U' ? "requires" : "provides"; - $symbols->{$symbol}->{$category}->{$object} = 1; + if ( /^In archive/ ) { + # Do nothing + } elsif ( /^$/ ) { + # Do nothing + } elsif ( /^(\S+\.o):\s+file format/ ) { + $object = $1; + } elsif ( /^SYMBOL TABLE:/ ) { + # Do nothing + } elsif ( /^([0-9a-fA-F]+)\s(l|g|\s)......\s(\S+)\s+([0-9a-fA-F]+)\s+(\S+)$/ ) { + my $value = $1; + my $scope = $2; + my $section = $3; + my $size = $4; + my $symbol = $5; + $symtab->{$object}->{$symbol} = { + global => ( $scope ne "l" ), + section => ( $section eq "*UND*" ? undef : $section ), + value => ( $value ? hex ( $value ) : 0 ), + size => ( $size ? hex ( $size ) : 0 ), + }; + } else { + die "Unrecognized line \"$_\""; + } } # Add symbols that we know will be generated or required by the linker # -while ( ( my $symbol, my $info ) = each %$symbols ) { - $info->{requires}->{LINKER} = 1 if $symbol =~ /^obj_/; +foreach my $object ( keys %$symtab ) { + my $obj_symbol = "obj_$object"; + $obj_symbol =~ s/\.o$//; + $obj_symbol =~ s/\W/_/g; + $symtab->{LINKER}->{$obj_symbol} = { + global => 1, + section => undef, + value => 0, + size => 0, + }; +} +foreach my $link_sym qw ( __prefix _prefix _prefix_load_offset + _prefix_size _prefix_progbits_size _prefix_size_pgh + __text16 _text16 _text16_load_offset + _text16_size _text16_progbits_size _text16_size_pgh + __data16 _data16 _data16_load_offset + _data16_size _data16_progbits_size _data16_size_pgh + __text _text __data _data _textdata_load_offset + _textdata_size _textdata_progbits_size + __rodata __bss _end + _payload_offset _max_align + _load_size _load_size_pgh _load_size_sect + pci_vendor_id pci_device_id ) { + $symtab->{LINKER}->{$link_sym} = { + global => 1, + section => '*ABS*', + value => 0, + size => 0, + }; +} + +# Build up requires, provides and shares symbol tables for global +# symbols +# +my $globals = {}; +while ( ( my $object, my $symbols ) = each %$symtab ) { + while ( ( my $symbol, my $info ) = each %$symbols ) { + if ( $info->{global} ) { + my $category; + if ( ! defined $info->{section} ) { + $category = "requires"; + } elsif ( $info->{section} eq "*COM*" ) { + $category = "shares"; + } else { + $category = "provides"; + } + $globals->{$symbol}->{$category}->{$object} = $info->{section}; + } + } } -$symbols->{$_}->{provides}->{LINKER} = 1 - foreach qw ( _prefix _eprefix _decompress _edecompress _text - _etext _data _edata _bss _ebss _end device_drivers - device_drivers_end bus_drivers bus_drivers_end - type_drivers type_drivers_end console_drivers - console_drivers_end post_reloc_fns post_reloc_fns_end - init_fns init_fns_end ); -# Check for multiply defined, never-defined and unused symbols +# Check for multiply defined, never-defined and unused global symbols # my $problems = {}; -while ( ( my $symbol, my $info ) = each %$symbols ) { +while ( ( my $symbol, my $info ) = each %$globals ) { my @provides = keys %{$info->{provides}}; my @requires = keys %{$info->{requires}}; + my @shares = keys %{$info->{shares}}; - if ( @provides == 0 ) { - # No object provides this symbol + if ( ( @requires > 0 ) && ( @provides == 0 ) && ( @shares == 0 ) ) { + # No object provides this symbol, but some objects require it. $problems->{$_}->{nonexistent}->{$symbol} = 1 foreach @requires; - } elsif ( @provides > 1 ) { - # Symbol defined in multiple objects + } + + if ( ( @requires == 0 ) && ( @provides > 0 ) ) { + # No object requires this symbol, but some objects provide it. + foreach my $provide ( @provides ) { + if ( $provide eq "LINKER" ) { + # Linker-provided symbols are exempt from this check. + } elsif ( $info->{provides}->{$provide} =~ /^\.tbl\./ ) { + # Linker tables are exempt from this check. + } else { + $problems->{$provide}->{unused}->{$symbol} = 1; + } + } + } + + if ( ( @shares > 0 ) && ( @provides > 0 ) ) { + # A shared symbol is being initialised by an object + $problems->{$_}->{shared}->{$symbol} = 1 foreach @provides; + } + + if ( @provides > 1 ) { + # A non-shared symbol is defined in multiple objects $problems->{$_}->{multiples}->{$symbol} = 1 foreach @provides; } - if ( @requires == 0 ) { - # Symbol not required - $problems->{$_}->{unused}->{$symbol} = 1 foreach @provides; +} + +# Check for excessively large local symbols. Text and rodata symbols +# are exempt from this check +# +while ( ( my $object, my $symbols ) = each %$symtab ) { + while ( ( my $symbol, my $info ) = each %$symbols ) { + if ( ( ! $info->{global} ) && + ( ( defined $info->{section} ) && + ! ( $info->{section} =~ /^(\.text|\.rodata)/ ) ) && + ( $info->{size} >= WARNING_SIZE ) ) { + $problems->{$object}->{large}->{$symbol} = 1; + } } } @@ -55,18 +149,23 @@ foreach my $object ( sort keys %$problems ) { my @nonexistent = sort keys %{$problems->{$object}->{nonexistent}}; my @multiples = sort keys %{$problems->{$object}->{multiples}}; my @unused = sort keys %{$problems->{$object}->{unused}}; + my @shared = sort keys %{$problems->{$object}->{shared}}; + my @large = sort keys %{$problems->{$object}->{large}}; print "WARN $object provides unused symbol $_\n" foreach @unused; $warnings += @unused; + print "WARN $object has large static symbol $_\n" foreach @large; + $warnings += @large; print "ERR $object requires non-existent symbol $_\n" foreach @nonexistent; $errors += @nonexistent; foreach my $symbol ( @multiples ) { my @other_objects = sort grep { $_ ne $object } - keys %{$symbols->{$symbol}->{provides}}; + keys %{$globals->{$symbol}->{provides}}; print "ERR $object provides symbol $symbol" ." (also provided by @other_objects)\n"; } $errors += @multiples; + print "ERR $object misuses shared symbol $_\n" foreach @shared; } print "$errors error(s), $warnings warning(s)\n";