Home | History | Annotate | Download | only in codesighs
      1 #!/usr/bin/perl -w
      2 # -*- Mode: perl; tab-width: 4; indent-tabs-mode: nil; -*-
      3 # ***** BEGIN LICENSE BLOCK *****
      4 # Version: MPL 1.1/GPL 2.0/LGPL 2.1
      5 #
      6 # The contents of this file are subject to the Mozilla Public License Version
      7 # 1.1 (the "License"); you may not use this file except in compliance with
      8 # the License. You may obtain a copy of the License at
      9 # http://www.mozilla.org/MPL/
     10 #
     11 # Software distributed under the License is distributed on an "AS IS" basis,
     12 # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
     13 # for the specific language governing rights and limitations under the
     14 # License.
     15 #
     16 # The Original Code is readelf_wrap.pl.
     17 #
     18 # The Initial Developer of the Original Code is
     19 # IBM Corporation.
     20 # Portions created by the Initial Developer are Copyright (C) 2003
     21 # the Initial Developer. All Rights Reserved.
     22 #
     23 # Contributor(s):
     24 #  Brian Ryner <bryner (at] brianryner.com>
     25 #
     26 # Alternatively, the contents of this file may be used under the terms of
     27 # either the GNU General Public License Version 2 or later (the "GPL"), or
     28 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
     29 # in which case the provisions of the GPL or the LGPL are applicable instead
     30 # of those above. If you wish to allow use of your version of this file only
     31 # under the terms of either the GPL or the LGPL, and not to allow others to
     32 # use your version of this file under the terms of the MPL, indicate your
     33 # decision by deleting the provisions above and replace them with the notice
     34 # and other provisions required by the GPL or the LGPL. If you do not delete
     35 # the provisions above, a recipient may use your version of this file under
     36 # the terms of any one of the MPL, the GPL or the LGPL.
     37 #
     38 # ***** END LICENSE BLOCK *****
     39 
     40 use strict;
     41 
     42 # Section fields (the full list of values is in <elf.h>)
     43 my $SECT_NUM  = 0;  # section index
     44 my $SECT_NAME = 1;  # section name
     45 my $SECT_TYPE = 2;  # section type
     46 my $SECT_ADDR = 3;  # section virtual address
     47 my $SECT_OFF  = 4;  # section offset in file
     48 my $SECT_SIZE = 5;  # size of section
     49 my $SECT_ES   = 6;  # section entry size
     50 my $SECT_FLG  = 7;  # section flags
     51 my $SECT_LK   = 8;  # link to another section
     52 my $SECT_INF  = 9;  # additional section info
     53 my $SECT_AL   = 10; # section alignment
     54 
     55 
     56 # Symbol fields (note: the full list of possible values for each field
     57 # is given in <elf.h>)
     58 
     59 my $SYM_NUM   = 0;     # unique index of the symbol
     60 my $SYM_VALUE = 1;     # value of the symbol
     61 my $SYM_SIZE  = 2;     # size of the symbol
     62 my $SYM_TYPE  = 3;     # type (NOTYPE, OBJECT, FUNC, SECTION, FILE, ...)
     63 my $SYM_BIND  = 4;     # binding/scope (LOCAL, GLOBAL, WEAK, ...)
     64 my $SYM_VIS   = 5;     # visibility (DEFAULT, INTERNAL, HIDDEN, PROTECTED)
     65 my $SYM_NDX   = 6;     # index of section the symbol is in
     66 my $SYM_NAME  = 7;     # name of the symbol
     67 my $SYM_FILE  = 8;     # (not part of readelf) file for symbol
     68 
     69 # Tell readelf to print out the list of sections and then the symbols
     70 die "Usage: $^X <binary>\n" unless ($#ARGV >= 0);
     71 my $readelf = $ENV{'READELF_PROG'};
     72 if (!$readelf) {
     73     $readelf = 'readelf';
     74 }
     75 open(READELF_OUTPUT, "$readelf -Ss $ARGV[0] 2>/dev/null | c++filt |") or die "readelf failed to run on $ARGV[0]\n";
     76 
     77 my @section_list;
     78 my @symbol_list;
     79 my ($module) = ($ARGV[0] =~ /([^\/]+)$/);
     80 my $in_symbols = 0;
     81 
     82 while (<READELF_OUTPUT>) {
     83 
     84     if (!$in_symbols) {
     85         if (/^ *\[ *(\d+)\]/) {
     86             my @section;
     87 
     88             # note that we strip off the leading '.' of section names for
     89             # readability
     90             if (! (@section = (/^ *\[ *(\d+)\] \.([\w\.\-]+) *(\w+) *(.{8}) (.{6}[0-9a-fA-F]*) (.{6}[0-9a-fA-F]*) *(\d+) ([a-zA-Z]+ +| +[a-zA-Z]+|) *(\d+) *(\w+) *(\d+)/))) {
     91                 # capture the 'null' section which has no name, so that the
     92                 # array indices are the same as the section indices.
     93 
     94                 @section = ($1, '', 'NULL', '00000000', '000000', '000000',
     95                             '00', '', '0', '0', '0');
     96             }
     97 
     98             push (@section_list, \@section);
     99         } elsif (/^Symbol table/) {
    100             $in_symbols = 1;
    101         }
    102     } else {
    103 
    104         my @sym;
    105 
    106         if (@sym = /^\s*(\d+): (\w+)\s*(\d+)\s*(\w+)\s*(\w+)\s*(\w+)\s*(\w+) (.*)/)
    107         {
    108             # Filter out types of symbols that we don't care about:
    109             #  - anything that's not of type OBJECT or FUNC
    110             #  - any undefined symbols (ndx = UND[EF])
    111             #  - any 0-size symbols
    112 
    113             if (($sym[$SYM_TYPE] !~ /^(OBJECT|FUNC)$/) ||
    114                 $sym[$SYM_NDX] eq 'UND' || $sym[$SYM_NDX] eq 'UNDEF'
    115                 || $sym[$SYM_SIZE] eq '0') {
    116                 next;
    117             }
    118             push (@symbol_list, \@sym);
    119         }
    120         elsif (/^Symbol table .*'\.symtab'/) {
    121             # We've been using .dynsym up to this point, but if we have .symtab
    122             # available, it will have everything in .dynsym and more.
    123             # So, reset our symbol list.
    124 
    125             @symbol_list = ();
    126         }
    127     }
    128 }
    129 
    130 close(READELF_OUTPUT);
    131 
    132 # spit them out in codesighs TSV format
    133 my $sym;
    134 my @section_sizes;
    135 $#section_sizes = $#section_list;
    136 foreach (@section_sizes) { $_ = 0; }
    137 
    138 foreach $sym (@symbol_list) {
    139     # size
    140     printf "%08x\t", $sym->[$SYM_SIZE];
    141 
    142     # code or data
    143     if ($sym->[$SYM_TYPE] eq 'FUNC') {
    144         print "CODE\t";
    145     } else {  # OBJECT
    146         print "DATA\t";
    147     }
    148 
    149     # scope
    150     if ($sym->[$SYM_BIND] eq 'LOCAL') {
    151         print "STATIC\t";
    152     } elsif ($sym->[$SYM_BIND] =~ /(GLOBAL|WEAK)/) {
    153         print "PUBLIC\t";
    154     } else {
    155         print "UNDEF\t";
    156     }
    157 
    158     # module name
    159 
    160     print "$module\t";
    161 
    162     # section
    163     my $section = $section_list[$sym->[$SYM_NDX]]->[$SECT_NAME];
    164     print "$section\t";
    165 
    166     # should be the object file, but for now just module/section
    167     print "UNDEF:$module:$section\t";
    168 
    169     # now the symbol name
    170     print $sym->[$SYM_NAME]."\n";
    171 
    172     # update our cumulative section sizes
    173     $section_sizes[$section_list[$sym->[$SYM_NDX]]->[$SECT_NUM]] += $sym->[$SYM_SIZE];
    174 }
    175 
    176 # Output extra entries to make the sum of the symbol sizes equal the
    177 # section size.
    178 
    179 my $section;
    180 foreach $section (@section_list) {
    181 
    182     my $diff = hex($section->[$SECT_SIZE]) - $section_sizes[$section->[$SECT_NUM]];
    183     if ($diff > 0) {
    184         my $sectname = $section->[$SECT_NAME];
    185         if ($section->[$SECT_NAME] =~ /^(rodata|data|text|bss)/) {
    186             printf "%08x", $diff;
    187             print "\tDATA\tSTATIC\t$module\t$sectname\tUNDEF:$module:$sectname\t.nosyms.$sectname\n";
    188 #        } else {
    189 #            print "ignoring $diff bytes of empty space in $sectname section\n";
    190         }
    191     }
    192 }
    193