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@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 40use strict; 41 42# Section fields (the full list of values is in <elf.h>) 43my $SECT_NUM = 0; # section index 44my $SECT_NAME = 1; # section name 45my $SECT_TYPE = 2; # section type 46my $SECT_ADDR = 3; # section virtual address 47my $SECT_OFF = 4; # section offset in file 48my $SECT_SIZE = 5; # size of section 49my $SECT_ES = 6; # section entry size 50my $SECT_FLG = 7; # section flags 51my $SECT_LK = 8; # link to another section 52my $SECT_INF = 9; # additional section info 53my $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 59my $SYM_NUM = 0; # unique index of the symbol 60my $SYM_VALUE = 1; # value of the symbol 61my $SYM_SIZE = 2; # size of the symbol 62my $SYM_TYPE = 3; # type (NOTYPE, OBJECT, FUNC, SECTION, FILE, ...) 63my $SYM_BIND = 4; # binding/scope (LOCAL, GLOBAL, WEAK, ...) 64my $SYM_VIS = 5; # visibility (DEFAULT, INTERNAL, HIDDEN, PROTECTED) 65my $SYM_NDX = 6; # index of section the symbol is in 66my $SYM_NAME = 7; # name of the symbol 67my $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 70die "Usage: $^X <binary>\n" unless ($#ARGV >= 0); 71my $readelf = $ENV{'READELF_PROG'}; 72if (!$readelf) { 73 $readelf = 'readelf'; 74} 75open(READELF_OUTPUT, "$readelf -Ss $ARGV[0] 2>/dev/null | c++filt |") or die "readelf failed to run on $ARGV[0]\n"; 76 77my @section_list; 78my @symbol_list; 79my ($module) = ($ARGV[0] =~ /([^\/]+)$/); 80my $in_symbols = 0; 81 82while (<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 130close(READELF_OUTPUT); 131 132# spit them out in codesighs TSV format 133my $sym; 134my @section_sizes; 135$#section_sizes = $#section_list; 136foreach (@section_sizes) { $_ = 0; } 137 138foreach $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 179my $section; 180foreach $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