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