added elfdump clone based on pyelftools, only support -y option currently
authorYann Rouillard <yann@pleiades.fr.eu.org>
Sun, 28 Apr 2013 23:39:51 +0000 (01:39 +0200)
committerYann Rouillard <yann@pleiades.fr.eu.org>
Sun, 28 Apr 2013 23:39:51 +0000 (01:39 +0200)
scripts/elfdump.py [new file with mode: 0755]
setup.py

diff --git a/scripts/elfdump.py b/scripts/elfdump.py
new file mode 100755 (executable)
index 0000000..aef365a
--- /dev/null
@@ -0,0 +1,176 @@
+#!/opt/csw/bin/python
+#-------------------------------------------------------------------------------
+# scripts/elfdump.py
+#
+# A clone of 'elfdump' in Python, based on the pyelftools library
+#
+# Eli Bendersky (eliben@gmail.com)
+# Yann Rouillard (yann@pleiades.fr.eu.org)
+# This code is in the public domain
+#-------------------------------------------------------------------------------
+import os, sys
+from optparse import OptionParser
+import string
+
+# For running from development directory. It should take precedence over the
+# installed pyelftools.
+sys.path.insert(0, '.')
+
+
+from elftools import __version__
+from elftools.common.exceptions import ELFError
+from elftools.common.py3compat import (
+        ifilter, byte2int, bytes2str, itervalues, str2bytes)
+from elftools.elf.elffile import ELFFile
+from elftools.elf.dynamic import DynamicSection, DynamicSegment
+from elftools.elf.enums import ENUM_D_TAG
+from elftools.elf.constants import SYMINF0_FLAGS
+from elftools.elf.segments import InterpSegment
+from elftools.elf.sections import SUNWSyminfoTableSection
+from elftools.elf.relocation import RelocationSection
+from elftools.elf.descriptions import (
+    describe_ei_class, describe_ei_data, describe_ei_version,
+    describe_ei_osabi, describe_e_type, describe_e_machine,
+    describe_e_version_numeric, describe_p_type, describe_p_flags,
+    describe_sh_type, describe_sh_flags,
+    describe_symbol_type, describe_symbol_bind, describe_symbol_visibility,
+    describe_symbol_shndx, describe_reloc_type, describe_dyn_tag,
+    describe_syminfo_flags,
+    )
+from elftools.dwarf.dwarfinfo import DWARFInfo
+from elftools.dwarf.descriptions import (
+    describe_reg_name, describe_attr_value, set_global_machine_arch,
+    describe_CFI_instructions, describe_CFI_register_rule,
+    describe_CFI_CFA_rule,
+    )
+from elftools.dwarf.constants import (
+    DW_LNS_copy, DW_LNS_set_file, DW_LNE_define_file)
+from elftools.dwarf.callframe import CIE, FDE
+
+
+class Elfdump(object):
+    """ display_* methods are used to emit output into the output stream
+    """
+    def __init__(self, file, output):
+        """ file:
+                stream object with the ELF file to read
+
+            output:
+                output stream to write to
+        """
+        self.elffile = ELFFile(file)
+        self.output = output
+
+    def display_syminfo_table(self):
+        """ Display the SUNW syminfo tables contained in the file
+        """
+        # The symbol table section pointed to in sh_link
+        dyntable = self.elffile.get_section_by_name('.dynamic')
+
+        for section in self.elffile.iter_sections():
+            if not isinstance(section, SUNWSyminfoTableSection):
+                continue
+
+            if section['sh_entsize'] == 0:
+                self._emitline("\nSymbol table '%s' has a sh_entsize of zero!" % (
+                    bytes2str(section.name)))
+                continue
+
+            # The symbol table section pointed to in sh_link
+            symtable = self.elffile.get_section(section['sh_link'])
+
+            self._emitline("\nSyminfo Section:  %s" % bytes2str(section.name))
+            self._emitline('     index  flags            bound to                 symbol')
+
+            for nsym, syminfo in enumerate(section.iter_symbols()):
+
+                # elfdump doesn't display anything for this kind of symbols
+                symbol = symtable.get_symbol(nsym + 1)
+                if (symbol['st_info']['type'] == 'STT_NOTYPE' and
+                        symbol['st_shndx'] == 'SHN_UNDEF'):
+                    continue
+
+                index = ''
+                if syminfo['si_flags'] & SYMINF0_FLAGS.SYMINFO_FLG_CAP:
+                    boundto = '<symbol capabilities>'
+                elif syminfo['si_boundto'] == 0xffff:
+                    boundto = '<self>'
+                elif syminfo['si_boundto'] == 0xfffe:
+                    boundto = '<parent>'
+                elif syminfo['si_boundto'] == 0xfffd:
+                    boundto = ''
+                else:
+                    boundto = bytes2str(dyntable.get_tag(syminfo['si_boundto']).needed)
+                    index = '[%d]' % syminfo['si_boundto']
+
+                # syminfo names are truncated to 25 chars, similarly to readelf
+                self._emitline('%10s  %-5s %10s %-24s %s' % (
+                    '[%d]' % (int(nsym) + 1),
+                    describe_syminfo_flags(syminfo['si_flags']),
+                    index,
+                    boundto,
+                    bytes2str(syminfo.name)))
+
+    def _emit(self, s=''):
+        """ Emit an object to output
+        """
+        self.output.write(str(s))
+
+    def _emitline(self, s=''):
+        """ Emit an object to output, followed by a newline
+        """
+        self.output.write(str(s) + '\n')
+
+
+SCRIPT_DESCRIPTION = 'Dumps selected parts of an object file'
+VERSION_STRING = '%%prog: based on pyelftools %s' % __version__
+
+
+def main(stream=None):
+    # parse the command-line arguments and invoke ReadElf
+    optparser = OptionParser(
+            usage='usage: %prog [options] <elf-file>',
+            description=SCRIPT_DESCRIPTION,
+            add_help_option=False,  # -h is a real option of readelf
+            prog='elfdump.py',
+            version=VERSION_STRING)
+    optparser.add_option('--help',
+            action='store_true', dest='help',
+            help='Display this information')
+    optparser.add_option('-y',
+            action='store_true', dest='show_syminfo',
+            help='dump the contents of the .SUNW_syminfo section')
+
+    options, args = optparser.parse_args()
+
+    if options.help or len(args) == 0:
+        optparser.print_help()
+        sys.exit(0)
+
+    with open(args[0], 'rb') as file:
+        try:
+            readelf = Elfdump(file, stream or sys.stdout)
+            if options.show_syminfo:
+                readelf.display_syminfo_table()
+        except ELFError as ex:
+            sys.stderr.write('ELF error: %s\n' % ex)
+            sys.exit(1)
+
+
+def profile_main():
+    # Run 'main' redirecting its output to readelfout.txt
+    # Saves profiling information in readelf.profile
+    PROFFILE = 'elfdump.profile'
+    import cProfile
+    cProfile.run('main(open("elfdumpout.txt", "w"))', PROFFILE)
+
+    # Dig in some profiling stats
+    import pstats
+    p = pstats.Stats(PROFFILE)
+    p.sort_stats('cumulative').print_stats(25)
+
+
+#-------------------------------------------------------------------------------
+if __name__ == '__main__':
+    main()
+    #profile_main()
index c8d54b14fb045c053173f5641eea14ab8e8e078b..9cad128224818c523c901f2f6142514b5263d110 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -44,7 +44,8 @@ setup(
         'elftools.construct', 'elftools.construct.lib',\r
         ],\r
 \r
-    scripts=['scripts/readelf.py'],\r
+    scripts=['scripts/readelf.py', \r
+             'scripts/elfdump.py']\r
 )\r
 \r
     \r