Some code reorg:
* created common/ dir and moved exceptions there (along with utils)
* moved struct_parse from elffile to utils
* moved string table functionality to its own section class
diff --git a/elftools/common/__init__.py b/elftools/common/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/elftools/common/__init__.py
diff --git a/elftools/exceptions.py b/elftools/common/exceptions.py
similarity index 91%
rename from elftools/exceptions.py
rename to elftools/common/exceptions.py
index b61b463..05fa602 100644
--- a/elftools/exceptions.py
+++ b/elftools/common/exceptions.py
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# elftools: exceptions.py
+# elftools: common/exceptions.py
#
# Exception classes for elftools
#
diff --git a/elftools/common/utils.py b/elftools/common/utils.py
new file mode 100644
index 0000000..716bebd
--- /dev/null
+++ b/elftools/common/utils.py
@@ -0,0 +1,25 @@
+#-------------------------------------------------------------------------------
+# elftools: common/utils.py
+#
+# Miscellaneous utilities for elftools
+#
+# Eli Bendersky (eliben@gmail.com)
+# This code is in the public domain
+#-------------------------------------------------------------------------------
+from .exceptions import ELFParseError
+
+
+def struct_parse(struct, stream, stream_pos=None):
+ """ Convenience function for using the given struct to parse a stream (at
+ its current location).
+ If stream_pos is provided, the stream is seeked to this position before
+ the parsing is done.
+ Wraps the error thrown by construct with our own error.
+ """
+ try:
+ if stream_pos is not None:
+ stream.seek(stream_pos)
+ return struct.parse_stream(stream)
+ except ConstructError as e:
+ raise ELFParseError(e.message)
+
diff --git a/elftools/elf/elffile.py b/elftools/elf/elffile.py
index 01be519..7d134b9 100644
--- a/elftools/elf/elffile.py
+++ b/elftools/elf/elffile.py
@@ -6,13 +6,11 @@
# Eli Bendersky (eliben@gmail.com)
# This code is in the public domain
#-------------------------------------------------------------------------------
-
-from cStringIO import StringIO
-
-from ..exceptions import ELFError, ELFParseError
-from ..construct import ConstructError, CString
+from ..common.exceptions import ELFError
+from ..common.utils import struct_parse
+from ..construct import ConstructError
from .structs import ELFStructs
-from .sections import Section
+from .sections import Section, StringTableSection
from .segments import Segment
@@ -35,7 +33,8 @@
little_endian=self.little_endian,
elfclass=self.elfclass)
self.header = self._parse_elf_header()
- self._stringtable = self._get_stringtable()
+
+ self._file_stringtable_section = self._get_file_stringtable()
def num_sections(self):
""" Number of sections in the file
@@ -119,51 +118,40 @@
def _get_section_header(self, n):
""" Find the header of section #n, parse it and return the struct
"""
- self.stream.seek(self._section_offset(n))
- return self._struct_parse(self.structs.Elf_Shdr)
+ return struct_parse(
+ self.structs.Elf_Shdr,
+ self.stream,
+ stream_pos=self._section_offset(n))
+ def _get_section_name(self, section_header):
+ """ Given a section header, find this section's name in the file's
+ string table
+ """
+ name_offset = section_header['sh_name']
+ return self._file_stringtable_section.get_string(name_offset)
+
def _get_segment_header(self, n):
""" Find the header of segment #n, parse it and return the struct
"""
- self.stream.seek(self._segment_offset(n))
- return self._struct_parse(self.structs.Elf_Phdr)
+ return struct_parse(
+ self.structs.Elf_Phdr,
+ self.stream,
+ stream_pos=self._segment_offset(n))
- def _get_section_name(self, section_header):
- """ Given a section header, find this section's name in the file's
- string table, and return it as a normal Python string.
+ def _get_file_stringtable(self):
+ """ Find the file's string table section
"""
- offset = section_header['sh_name']
- self._stringtable.seek(offset)
- return CString('').parse_stream(self._stringtable)
-
- def _get_stringtable(self):
- """ Find the file's string table section, read it and return the string
- table as a StringIO object pointing to the section's contents.
- """
- # Find the section header for the stringtable header, and read the
- # section's contents from it
- #
stringtable_section_num = self['e_shstrndx']
- stringtable_header = self._get_section_header(stringtable_section_num)
- self.stream.seek(stringtable_header['sh_offset'])
- return StringIO(self.stream.read(stringtable_header['sh_size']))
+ return StringTableSection(
+ header=self._get_section_header(stringtable_section_num),
+ name='',
+ stream=self.stream)
def _parse_elf_header(self):
""" Parses the ELF file header and assigns the result to attributes
of this object.
"""
- self.stream.seek(0)
- return self._struct_parse(self.structs.Elf_Ehdr)
-
- def _struct_parse(self, struct):
- """ Convenience method for parsing at the current stream location with
- the given struct. Also wraps the error thrown by construct with our
- own error.
- """
- try:
- return struct.parse_stream(self.stream)
- except ConstructError as e:
- raise ELFParseError(e.message)
+ return struct_parse(self.structs.Elf_Ehdr, self.stream, stream_pos=0)
def _assert(self, cond, msg=''):
""" Assert that cond is True, otherwise raise ELFError(msg)
diff --git a/elftools/elf/sections.py b/elftools/elf/sections.py
index 4fb4249..502b69f 100644
--- a/elftools/elf/sections.py
+++ b/elftools/elf/sections.py
@@ -6,6 +6,8 @@
# Eli Bendersky (eliben@gmail.com)
# This code is in the public domain
#-------------------------------------------------------------------------------
+from ..construct import CString
+
class Section(object):
def __init__(self, header, name, stream):
@@ -24,3 +26,18 @@
"""
return self.header[name]
+
+class StringTableSection(Section):
+ def __init__(self, header, name, stream):
+ super(StringTableSection, self).__init__(header, name, stream)
+
+ def get_string(self, offset):
+ """ Get the string stored at the given offset in this string table.
+ """
+ table_offset = self['sh_offset']
+ self.stream.seek(table_offset + offset)
+ return CString('').parse_stream(self.stream)
+
+
+
+
diff --git a/z.py b/z.py
index 9f208d3..adcfd6c 100644
--- a/z.py
+++ b/z.py
@@ -9,6 +9,9 @@
efile = ELFFile(stream)
+print '===> %s sections!' % efile.num_sections()
+print '===> %s segments!' % efile.num_segments()
+
for sec in efile.iter_sections():
print sec.name