* Started writing readelf.py
authorEli Bendersky <eliben@gmail.com>
Fri, 9 Sep 2011 05:11:06 +0000 (08:11 +0300)
committerEli Bendersky <eliben@gmail.com>
Fri, 9 Sep 2011 05:11:06 +0000 (08:11 +0300)
* Added file with textual descriptions of enums, for readelf.py

elftools/elf/descriptions.py [new file with mode: 0644]
elftools/elf/elffile.py
elftools/elf/enums.py
elftools/elf/sections.py
elftools/elf/structs.py
scripts/readelf.py [new file with mode: 0644]

diff --git a/elftools/elf/descriptions.py b/elftools/elf/descriptions.py
new file mode 100644 (file)
index 0000000..c06f97f
--- /dev/null
@@ -0,0 +1,76 @@
+#-------------------------------------------------------------------------------
+# elftools: elf/descriptions.py
+#
+# Textual descriptions of the various enums and flags of ELF
+#
+# Eli Bendersky (eliben@gmail.com)
+# This code is in the public domain
+#-------------------------------------------------------------------------------
+from .enums import ENUM_E_VERSION
+
+
+def describe_ei_class(x):
+    return _DESCR_EI_CLASS.get(x, _unknown())
+
+def describe_ei_data(x):
+    return _DESCR_EI_DATA.get(x, _unknown())
+
+def describe_ei_version(x):
+    s = '%d' % ENUM_E_VERSION[x]
+    if x == 'EV_CURRENT':
+        s += ' (current)'
+    return s
+    
+def describe_ei_osabi(x):
+    return _DESCR_EI_OSABI.get(x, _unknown())
+
+def describe_e_type(x):
+    return _DESCR_E_TYPE.get(x, _unknown())
+
+
+#-------------------------------------------------------------------------------
+def _unknown():
+    return '<unknown>'
+
+    
+_DESCR_EI_CLASS = dict(
+    ELFCLASSNONE='none',
+    ELFCLASS32='ELF32',
+    ELFCLASS64='ELF64',
+)
+
+_DESCR_EI_DATA = dict(
+    ELFDATANONE='none',
+    ELFDATA2LSB="2's complement, little endian",
+    ELFDATA2MSB="2's complement, big endian",
+)
+
+_DESCR_EI_OSABI = dict(
+    ELFOSABI_SYSV='UNIX - System V',
+    ELFOSABI_HPUX='UNIX - HP-UX',
+    ELFOSABI_NETBSD='UNIX - NetBSD',
+    ELFOSABI_LINUX='UNIX - Linux',
+    ELFOSABI_HURD='UNIX - GNU/Hurd',
+    ELFOSABI_SOLARIS='UNIX - Solaris',
+    ELFOSABI_AIX='UNIX - AIX',
+    ELFOSABI_IRIX='UNIX - IRIX',
+    ELFOSABI_FREEBSD='UNIX - FreeBSD',
+    ELFOSABI_TRU64='UNIX - TRU64',
+    ELFOSABI_MODESTO='Novell - Modesto',
+    ELFOSABI_OPENBSD='UNIX - OpenBSD',
+    ELFOSABI_OPENVMS='VMS - OpenVMS',
+    ELFOSABI_NSK='HP - Non-Stop Kernel',
+    ELFOSABI_AROS='AROS',
+    ELFOSABI_ARM='ARM',
+    ELFOSABI_STANDALONE='Standalone App',
+)
+
+_DESCR_E_TYPE = dict(
+    ET_NONE='NONE (None)',
+    ET_REL='REL (Relocatable file)',
+    ET_EXEC='EXEC (Executable file)',
+    ET_DYN='DYN (Shared object file)',
+    ET_CORE='CORE (Core file)',
+    PROC_SPECIFIC='Processor Specific',
+)
+
index b0e2b674ba522a428ab352b4b6dcfb00f4c07570..aee1b5434097008329bde7d645ef1a9f960d9fd1 100644 (file)
@@ -25,6 +25,9 @@ class ELFFile(object):
 
             header:
                 the complete ELF file header
+
+            e_ident_raw:
+                the raw e_ident field of the header
     """
     def __init__(self, stream):
         self.stream = stream
@@ -33,6 +36,9 @@ class ELFFile(object):
             little_endian=self.little_endian,
             elfclass=self.elfclass)
         self.header = self._parse_elf_header()
+
+        self.stream.seek(0)
+        self.e_ident_raw = self.stream.read(16)
         
         self._file_stringtable_section = self._get_file_stringtable()
     
index 1cd5a9b6c363cf62b10eec2534fce883d733cefa..37ddb86cf202a3d27cca4761918d40c68561def7 100644 (file)
@@ -27,6 +27,27 @@ ENUM_E_VERSION = dict(
     EV_CURRENT=1
 )
 
+# e_ident[EI_OSABI] in the ELF header
+ENUM_EI_OSABI = dict(
+    ELFOSABI_SYSV=0,
+    ELFOSABI_HPUX=1,
+    ELFOSABI_NETBSD=2,
+    ELFOSABI_LINUX=3,
+    ELFOSABI_HURD=4,
+    ELFOSABI_SOLARIS=6,
+    ELFOSABI_AIX=7,
+    ELFOSABI_IRIX=8,
+    ELFOSABI_FREEBSD=9,
+    ELFOSABI_TRU64=10,
+    ELFOSABI_MODESTO=11,
+    ELFOSABI_OPENBSD=12,
+    ELFOSABI_OPENVMS=13,
+    ELFOSABI_NSK=14,
+    ELFOSABI_AROS=15,
+    ELFOSABI_ARM=97,
+    ELFOSABI_STANDALONE=255,
+)
+
 # e_type in the ELF header
 ENUM_E_TYPE = dict(
     ET_NONE=0,
index fd11875ff72d6d0145037e23ed4a36cc968e7ffa..ba4805acfab62269e81f38ad292d04baa9c3b7a9 100644 (file)
@@ -92,6 +92,9 @@ class SymbolTableSection(Section):
 class Symbol(object):
     """ Symbol object - representing a single symbol entry from a symbol table
         section.
+
+        Similarly to Section objects, allows dictionary-like access to the
+        symbol entry.
     """
     def __init__(self, entry, name):
         self.entry = entry
index 21ea2b7c996b6b64b3b0b434ceffd775cf739e06..bb685cf3ef553b76c42b93795aacd8827db27b77 100644 (file)
@@ -74,7 +74,9 @@ class ELFStructs(object):
                 Enum(self.Elf_byte('EI_CLASS'), **ENUM_EI_CLASS),
                 Enum(self.Elf_byte('EI_DATA'), **ENUM_EI_DATA),
                 Enum(self.Elf_byte('EI_VERSION'), **ENUM_E_VERSION),
-                Padding(9)                
+                Enum(self.Elf_byte('EI_OSABI'), **ENUM_EI_OSABI),
+                self.Elf_byte('EI_ABIVERSION'),
+                Padding(7)
             ),
             Enum(self.Elf_half('e_type'), **ENUM_E_TYPE),
             Enum(self.Elf_half('e_machine'), **ENUM_E_MACHINE),
@@ -130,6 +132,8 @@ class ELFStructs(object):
         )
     
     def _create_sym(self):
+        # Note that st_info is hierarchical. To access the type, use
+        # container['st_info']['type']
         st_info_struct = BitStruct('st_info',
             Enum(BitField('bind', 4), **ENUM_ST_INFO_BIND),
             Enum(BitField('type', 4), **ENUM_ST_INFO_TYPE))
diff --git a/scripts/readelf.py b/scripts/readelf.py
new file mode 100644 (file)
index 0000000..a0eb79b
--- /dev/null
@@ -0,0 +1,90 @@
+#-------------------------------------------------------------------------------
+# readelf.py
+#
+# A clone of 'readelf' in Python, based on the pyelftools library
+#
+# Eli Bendersky (eliben@gmail.com)
+# This code is in the public domain
+#-------------------------------------------------------------------------------
+import sys
+from optparse import OptionParser
+
+# If elftools is not installed, maybe we're running from the root or scripts
+# dir of the source distribution
+#
+try:
+    import elftools
+except ImportError:
+    sys.path.extend(['.', '..'])
+
+from elftools.common.exceptions import ELFError
+from elftools.elf.elffile import ELFFile
+from elftools.elf.descriptions import (
+    describe_ei_class, describe_ei_data, describe_ei_version,
+    describe_ei_osabi, describe_e_type,
+    )
+
+
+class ReadElf(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_file_header(self):
+        """ Display the ELF file header
+        """
+        self._emitline('ELF Header:')
+        self._emit('  Magic:   ')
+        self._emitline(' '.join('%2.2x' % ord(b) 
+                                    for b in self.elffile.e_ident_raw))
+        header = self.elffile.header
+        e_ident = header['e_ident']
+        self._emitline('  Class:                             %s' % 
+                describe_ei_class(e_ident['EI_CLASS']))
+        self._emitline('  Data:                              %s' % 
+                describe_ei_data(e_ident['EI_DATA']))
+        self._emitline('  Version:                           %s' % 
+                describe_ei_version(e_ident['EI_VERSION']))
+        self._emitline('  OS/ABI:                            %s' %
+                describe_ei_osabi(e_ident['EI_OSABI']))
+        self._emitline('  ABI Version:                       %d' % 
+                e_ident['EI_ABIVERSION'])
+        self._emitline('  Type:                              %s' %
+                describe_e_type(header['e_type']))
+
+    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')
+
+
+def main():
+    optparser = OptionParser()
+    options, args = optparser.parse_args()
+
+    with open(args[0], 'rb') as file:
+        try:
+            readelf = ReadElf(file, sys.stdout)
+            readelf.display_file_header()
+        except ELFError as ex:
+            sys.stderr.write('ELF read error: %s\n' % ex)
+            sys.exit(1)
+
+
+#-------------------------------------------------------------------------------
+if __name__ == '__main__':
+    main()
+