From 933f699ac7e7ad393899afe46dba7790c75b7a73 Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Fri, 9 Sep 2011 08:11:06 +0300 Subject: [PATCH] * Started writing readelf.py * Added file with textual descriptions of enums, for readelf.py --- elftools/elf/descriptions.py | 76 ++++++++++++++++++++++++++++++ elftools/elf/elffile.py | 6 +++ elftools/elf/enums.py | 21 +++++++++ elftools/elf/sections.py | 3 ++ elftools/elf/structs.py | 6 ++- scripts/readelf.py | 90 ++++++++++++++++++++++++++++++++++++ 6 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 elftools/elf/descriptions.py create mode 100644 scripts/readelf.py diff --git a/elftools/elf/descriptions.py b/elftools/elf/descriptions.py new file mode 100644 index 0000000..c06f97f --- /dev/null +++ b/elftools/elf/descriptions.py @@ -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 '' + + +_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', +) + diff --git a/elftools/elf/elffile.py b/elftools/elf/elffile.py index b0e2b67..aee1b54 100644 --- a/elftools/elf/elffile.py +++ b/elftools/elf/elffile.py @@ -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() diff --git a/elftools/elf/enums.py b/elftools/elf/enums.py index 1cd5a9b..37ddb86 100644 --- a/elftools/elf/enums.py +++ b/elftools/elf/enums.py @@ -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, diff --git a/elftools/elf/sections.py b/elftools/elf/sections.py index fd11875..ba4805a 100644 --- a/elftools/elf/sections.py +++ b/elftools/elf/sections.py @@ -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 diff --git a/elftools/elf/structs.py b/elftools/elf/structs.py index 21ea2b7..bb685cf 100644 --- a/elftools/elf/structs.py +++ b/elftools/elf/structs.py @@ -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 index 0000000..a0eb79b --- /dev/null +++ b/scripts/readelf.py @@ -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() + -- 2.30.2