15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/perl -w
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# -*- Mode: perl; tab-width: 4; indent-tabs-mode: nil; -*-
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# ***** BEGIN LICENSE BLOCK *****
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Version: MPL 1.1/GPL 2.0/LGPL 2.1
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# The contents of this file are subject to the Mozilla Public License Version
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 1.1 (the "License"); you may not use this file except in compliance with
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# the License. You may obtain a copy of the License at
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# http://www.mozilla.org/MPL/
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Software distributed under the License is distributed on an "AS IS" basis,
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# for the specific language governing rights and limitations under the
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# License.
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# The Original Code is readelf_wrap.pl.
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# The Initial Developer of the Original Code is
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# IBM Corporation.
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Portions created by the Initial Developer are Copyright (C) 2003
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# the Initial Developer. All Rights Reserved.
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Contributor(s):
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#  Brian Ryner <bryner@brianryner.com>
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Alternatively, the contents of this file may be used under the terms of
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# either the GNU General Public License Version 2 or later (the "GPL"), or
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# in which case the provisions of the GPL or the LGPL are applicable instead
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# of those above. If you wish to allow use of your version of this file only
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# under the terms of either the GPL or the LGPL, and not to allow others to
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# use your version of this file under the terms of the MPL, indicate your
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# decision by deleting the provisions above and replace them with the notice
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# and other provisions required by the GPL or the LGPL. If you do not delete
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# the provisions above, a recipient may use your version of this file under
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# the terms of any one of the MPL, the GPL or the LGPL.
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# ***** END LICENSE BLOCK *****
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)use strict;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Section fields (the full list of values is in <elf.h>)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my $SECT_NUM  = 0;  # section index
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my $SECT_NAME = 1;  # section name
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my $SECT_TYPE = 2;  # section type
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my $SECT_ADDR = 3;  # section virtual address
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my $SECT_OFF  = 4;  # section offset in file
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my $SECT_SIZE = 5;  # size of section
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my $SECT_ES   = 6;  # section entry size
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my $SECT_FLG  = 7;  # section flags
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my $SECT_LK   = 8;  # link to another section
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my $SECT_INF  = 9;  # additional section info
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my $SECT_AL   = 10; # section alignment
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Symbol fields (note: the full list of possible values for each field
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# is given in <elf.h>)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my $SYM_NUM   = 0;     # unique index of the symbol
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my $SYM_VALUE = 1;     # value of the symbol
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my $SYM_SIZE  = 2;     # size of the symbol
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my $SYM_TYPE  = 3;     # type (NOTYPE, OBJECT, FUNC, SECTION, FILE, ...)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my $SYM_BIND  = 4;     # binding/scope (LOCAL, GLOBAL, WEAK, ...)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my $SYM_VIS   = 5;     # visibility (DEFAULT, INTERNAL, HIDDEN, PROTECTED)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my $SYM_NDX   = 6;     # index of section the symbol is in
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my $SYM_NAME  = 7;     # name of the symbol
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my $SYM_FILE  = 8;     # (not part of readelf) file for symbol
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Tell readelf to print out the list of sections and then the symbols
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)die "Usage: $^X <binary>\n" unless ($#ARGV >= 0);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my $readelf = $ENV{'READELF_PROG'};
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if (!$readelf) {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    $readelf = 'readelf';
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)open(READELF_OUTPUT, "$readelf -Ss $ARGV[0] 2>/dev/null | c++filt |") or die "readelf failed to run on $ARGV[0]\n";
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my @section_list;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my @symbol_list;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my ($module) = ($ARGV[0] =~ /([^\/]+)$/);
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my $in_symbols = 0;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)while (<READELF_OUTPUT>) {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!$in_symbols) {
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (/^ *\[ *(\d+)\]/) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            my @section;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # note that we strip off the leading '.' of section names for
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # readability
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            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+)/))) {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                # capture the 'null' section which has no name, so that the
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                # array indices are the same as the section indices.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                @section = ($1, '', 'NULL', '00000000', '000000', '000000',
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            '00', '', '0', '0', '0');
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            push (@section_list, \@section);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } elsif (/^Symbol table/) {
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            $in_symbols = 1;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        my @sym;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (@sym = /^\s*(\d+): (\w+)\s*(\d+)\s*(\w+)\s*(\w+)\s*(\w+)\s*(\w+) (.*)/)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        {
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # Filter out types of symbols that we don't care about:
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            #  - anything that's not of type OBJECT or FUNC
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            #  - any undefined symbols (ndx = UND[EF])
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            #  - any 0-size symbols
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (($sym[$SYM_TYPE] !~ /^(OBJECT|FUNC)$/) ||
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                $sym[$SYM_NDX] eq 'UND' || $sym[$SYM_NDX] eq 'UNDEF'
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                || $sym[$SYM_SIZE] eq '0') {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                next;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            push (@symbol_list, \@sym);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        elsif (/^Symbol table .*'\.symtab'/) {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # We've been using .dynsym up to this point, but if we have .symtab
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # available, it will have everything in .dynsym and more.
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # So, reset our symbol list.
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            @symbol_list = ();
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)close(READELF_OUTPUT);
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# spit them out in codesighs TSV format
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my $sym;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my @section_sizes;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$#section_sizes = $#section_list;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)foreach (@section_sizes) { $_ = 0; }
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)foreach $sym (@symbol_list) {
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # size
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    printf "%08x\t", $sym->[$SYM_SIZE];
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # code or data
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ($sym->[$SYM_TYPE] eq 'FUNC') {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        print "CODE\t";
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {  # OBJECT
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        print "DATA\t";
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # scope
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ($sym->[$SYM_BIND] eq 'LOCAL') {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        print "STATIC\t";
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } elsif ($sym->[$SYM_BIND] =~ /(GLOBAL|WEAK)/) {
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        print "PUBLIC\t";
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        print "UNDEF\t";
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # module name
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print "$module\t";
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # section
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    my $section = $section_list[$sym->[$SYM_NDX]]->[$SECT_NAME];
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print "$section\t";
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # should be the object file, but for now just module/section
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print "UNDEF:$module:$section\t";
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # now the symbol name
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print $sym->[$SYM_NAME]."\n";
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # update our cumulative section sizes
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    $section_sizes[$section_list[$sym->[$SYM_NDX]]->[$SECT_NUM]] += $sym->[$SYM_SIZE];
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Output extra entries to make the sum of the symbol sizes equal the
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# section size.
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my $section;
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)foreach $section (@section_list) {
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    my $diff = hex($section->[$SECT_SIZE]) - $section_sizes[$section->[$SECT_NUM]];
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ($diff > 0) {
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        my $sectname = $section->[$SECT_NAME];
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if ($section->[$SECT_NAME] =~ /^(rodata|data|text|bss)/) {
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            printf "%08x", $diff;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            print "\tDATA\tSTATIC\t$module\t$sectname\tUNDEF:$module:$sectname\t.nosyms.$sectname\n";
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#        } else {
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#            print "ignoring $diff bytes of empty space in $sectname section\n";
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
193