return self.encoding[obj]\r
except (KeyError, TypeError):\r
if self.encdefault is NotImplemented:\r
- raise MappingError("no encoding mapping for %r" % (obj,))\r
+ raise MappingError("no encoding mapping for %r [%s]" % (\r
+ obj, self.subcon.name))\r
if self.encdefault is Pass:\r
return obj\r
return self.encdefault\r
return self.decoding[obj]\r
except (KeyError, TypeError):\r
if self.decdefault is NotImplemented:\r
- raise MappingError("no decoding mapping for %r" % (obj,))\r
+ raise MappingError("no decoding mapping for %r [%s]" % (\r
+ obj, self.subcon.name))\r
if self.decdefault is Pass:\r
return obj\r
return self.decdefault\r
+#-------------------------------------------------------------------------------\r
+# elftools: elf/constants.py\r
+#\r
# Constants and flags, placed into classes for namespacing\r
+#\r
+# Eli Bendersky (eliben@gmail.com)\r
+# This code is in the public domain\r
+#-------------------------------------------------------------------------------\r
\r
class SHN_INDICES(object):\r
""" Special section indices
--- /dev/null
+#-------------------------------------------------------------------------------\r
+# elftools: elf/elffile.py\r
+#\r
+# ELFFile - main class for accessing ELF files\r
+#\r
+# Eli Bendersky (eliben@gmail.com)\r
+# This code is in the public domain\r
+#-------------------------------------------------------------------------------\r
+\r
+from .structs import ELFStructs\r
+from ..exceptions import ELFError, ELFParseError\r
+from ..construct import ConstructError\r
+\r
+\r
+class ELFFile(object):\r
+ """ Accessible attributes:\r
+ \r
+ elfclass: \r
+ 32 or 64 - specifies the word size of the target machine\r
+ \r
+ little_endian:\r
+ boolean - specifies the target machine's endianness \r
+\r
+ header:\r
+ the complete ELF file header
+ """
+ def __init__(self, stream):
+ self.stream = stream\r
+ self._identify_file()\r
+ self.structs = ELFStructs(\r
+ little_endian=self.little_endian,\r
+ elfclass=self.elfclass)\r
+ self.header = self._parse_elf_header()\r
+ \r
+ def __getitem__(self, name):
+ """ Implement dict-like access to header entries
+ """\r
+ return self.header[name]\r
+ \r
+ def _identify_file(self):
+ """ Verify the ELF file and identify its class and endianness.
+ """\r
+ # Note: this code reads the stream directly, without using ELFStructs,\r
+ # since we don't yet know its exact format. ELF was designed to be \r
+ # read like this - its e_ident field is word-size and endian agnostic.\r
+ #\r
+ self.stream.seek(0)\r
+ magic = self.stream.read(4)\r
+ self._assert(magic == '\x7fELF', 'Magic number does not match')\r
+ \r
+ ei_class = self.stream.read(1)\r
+ if ei_class == '\x01':\r
+ self.elfclass = 32\r
+ elif ei_class == '\x02':\r
+ self.elfclass = 64\r
+ else:\r
+ raise ELFError('Invalid EI_CLASS %s' % repr(ei_class))\r
+ \r
+ ei_data = self.stream.read(1)\r
+ if ei_data == '\x01':\r
+ self.little_endian = True\r
+ elif ei_data == '\x02':\r
+ self.little_endian = False\r
+ else:\r
+ raise ELFError('Invalid EI_DATA %s' % repr(ei_data))\r
+ \r
+ def _parse_elf_header(self):
+ """ Parses the ELF file header and assigns the result to attributes\r
+ of this object.
+ """\r
+ self.stream.seek(0)\r
+ return self._struct_parse(self.structs.Elf_Ehdr)\r
+ \r
+ def _struct_parse(self, struct):
+ """ Convenience method for parsing at the current stream location with\r
+ the given struct. Also wraps the error thrown by construct with our\r
+ own error.
+ """\r
+ try:\r
+ return struct.parse_stream(self.stream)\r
+ except ConstructError as e:\r
+ raise ELFParseError(e.message)\r
+ \r
+ def _assert(self, cond, msg=''):
+ """ Assert that cond is True, otherwise raise ELFError(msg)
+ """\r
+ if not cond:\r
+ raise ELFError(msg)\r
+\r
-# Mappings of enum names<->values to be inserted into construct's Enum adapter\r
+#-------------------------------------------------------------------------------\r
+# elftools: elf/enums.py\r
#\r
+# Mappings of enum names to values\r
+#\r
+# Eli Bendersky (eliben@gmail.com)\r
+# This code is in the public domain\r
+#-------------------------------------------------------------------------------\r
\r
# e_ident[EI_CLASS] in the ELF header\r
ENUM_EI_CLASS = dict(\r
+#-------------------------------------------------------------------------------\r
+# elftools: elf/structs.py\r
+#\r
+# Encapsulation of Construct structs for parsing an ELF file, adjusted for\r
+# correct endianness and word-size.\r
+#\r
+# Eli Bendersky (eliben@gmail.com)\r
+# This code is in the public domain\r
+#-------------------------------------------------------------------------------\r
+\r
from ..construct import (\r
UBInt8, UBInt16, UBInt32, UBInt64,\r
ULInt8, ULInt16, ULInt32, ULInt64,\r
from .enums import *\r
\r
\r
-class ELFStructs(object):
+class ELFStructs(object):\r
+ """ Accessible attributes:\r
+ \r
+ Elf_{byte|half|word|addr|offset|sword|xword|xsword}:\r
+ Data chunks, as specified by the ELF standard, adjusted for \r
+ correct endianness and word-size.\r
+ \r
+ Elf_Ehdr:\r
+ ELF file header\r
+ \r
+ Elf_Phdr:\r
+ Program header\r
+ \r
+ Elf_Shdr:\r
+ Section header\r
+ \r
+ Elf_Sym:\r
+ Symbol table entry
+ """
def __init__(self, little_endian=True, elfclass=32):\r
assert elfclass == 32 or elfclass == 64\r
self.little_endian = little_endian\r
--- /dev/null
+#-------------------------------------------------------------------------------\r
+# elftools: exceptions.py\r
+#\r
+# Exception classes for elftools\r
+#\r
+# Eli Bendersky (eliben@gmail.com)\r
+# This code is in the public domain\r
+#-------------------------------------------------------------------------------\r
+\r
+class ELFError(Exception): \r
+ pass
+\r
+class ELFParseError(ELFError):\r
+ pass\r
+\r
import sys\r
from elftools.elf.structs import ELFStructs\r
+from elftools.elf.elffile import ELFFile\r
\r
# read a little-endian, 64-bit file\r
es = ELFStructs(True, 64)\r
\r
stream = open('binfiles/z.elf', 'rb')\r
-eheader = es.Elf_Ehdr.parse_stream(stream)\r
\r
-print eheader\r
+efile = ELFFile(stream)\r
\r
-shtable_offset = eheader.e_shoff\r
-strtable_section_offset = shtable_offset + eheader.e_shstrndx * eheader.e_shentsize\r
+#~ print efile.header\r
+#~ print dir(efile)\r
+#~ print efile['e_type']\r
+\r
+shtable_offset = efile['e_shoff']\r
+strtable_section_offset = shtable_offset + efile['e_shstrndx'] * efile['e_shentsize']\r
\r
# get to the section header for the sh string table\r
print strtable_section_offset\r