Section to segment mapping seems to be working - yay!
authorEli Bendersky <eliben@gmail.com>
Thu, 15 Sep 2011 04:07:54 +0000 (07:07 +0300)
committerEli Bendersky <eliben@gmail.com>
Thu, 15 Sep 2011 04:07:54 +0000 (07:07 +0300)
elftools/elf/elffile.py
elftools/elf/enums.py
elftools/elf/sections.py
elftools/elf/segments.py
scripts/readelf.py

index 32373e9760a711cef4ef69dc197a5dbf123d6ec1..2999cc1e412cc7a63410c96770caf739f4ec39ee 100644 (file)
@@ -10,7 +10,8 @@ from ..common.exceptions import ELFError
 from ..common.utils import struct_parse, elf_assert
 from ..construct import ConstructError
 from .structs import ELFStructs
-from .sections import Section, StringTableSection, SymbolTableSection
+from .sections import (
+        Section, StringTableSection, SymbolTableSection, NullSection)
 from .segments import Segment, InterpSegment
 
 
@@ -153,6 +154,8 @@ class ELFFile(object):
         
         if sectype == 'SHT_STRTAB':
             return StringTableSection(section_header, name, self.stream)
+        elif sectype == 'SHT_NULL':
+            return NullSection(section_header, name, self.stream)
         elif sectype in ('SHT_SYMTAB', 'SHT_DYNSYM'):
             return self._make_symbol_table_section(section_header, name)
         else:
index 37ddb86cf202a3d27cca4761918d40c68561def7..8715bf19189839ca2e1eee1f6b4e9d6eb1b63a7f 100644 (file)
@@ -119,6 +119,7 @@ ENUM_P_TYPE = dict(
     PT_NOTE=4,
     PT_SHLIB=5,
     PT_PHDR=6,
+    PT_TLS=7,
     PT_LOPROC=0x70000000,
     PT_HIPROC=0x7fffffff,
     PT_GNU_EH_FRAME=0x6474e550,
index ba4805acfab62269e81f38ad292d04baa9c3b7a9..f9dd149f01d91d463dbb780e944f1314a3816756 100644 (file)
@@ -29,12 +29,27 @@ class Section(object):
         self.stream.seek(self['sh_offset'])
         return self.stream.read(self['sh_size'])
 
+    def is_null(self):
+        """ Is this a null section?
+        """
+        return False
+        
     def __getitem__(self, name):
         """ Implement dict-like access to header entries
         """
         return self.header[name]
 
 
+class NullSection(Section):
+    """ ELF NULL section
+    """
+    def __init__(self, header, name, stream):
+        super(NullSection, self).__init__(header, name, stream)
+
+    def is_null(self):
+        return True
+        
+
 class StringTableSection(Section):
     """ ELF string table section.
     """
index 5e61b2870d21ca7dd9bf189f8351b0d2e1467a2a..217ba085db6719dbac49fd7ab2eb2b083e1d9dd9 100644 (file)
@@ -8,6 +8,7 @@
 #-------------------------------------------------------------------------------
 from ..construct import CString
 from ..common.utils import struct_parse
+from .constants import SH_FLAGS
 
 
 class Segment(object):
@@ -26,6 +27,57 @@ class Segment(object):
         """
         return self.header[name]
 
+    def section_in_segment(self, section):
+        """ Is the given section contained in this segment?
+
+            Note: this tries to reproduce the intricate rules of the 
+            ELF_SECTION_IN_SEGMENT_STRICT macro of the header 
+            elf/include/internal.h in the source of binutils.
+        """
+        # Only the 'strict' checks from ELF_SECTION_IN_SEGMENT_1 are included
+        segtype = self['p_type']
+        sectype = section['sh_type']
+        secflags = section['sh_flags']
+
+        # Only PT_LOAD, PT_GNU_RELR0 and PT_TLS segments can contain SHF_TLS
+        # sections
+        if (    secflags & SH_FLAGS.SHF_TLS and 
+                segtype in ('PT_TLS', 'PT_GNU_RELR0', 'PT_LOAD')):
+            return False
+        # PT_TLS segment contains only SHF_TLS sections, PT_PHDR no sections
+        # at all
+        elif (  (secflags & SH_FLAGS.SHF_TLS) != 0 and
+                segtype not in ('PT_TLS', 'PT_PHDR')):
+            return False
+
+        # In ELF_SECTION_IN_SEGMENT_STRICT the flag check_vma is on, so if
+        # this is an alloc section, check whether its VMA is in bounds.
+        if secflags & SH_FLAGS.SHF_ALLOC:
+            secaddr = section['sh_addr']
+            vaddr = self['p_vaddr']
+
+            # This checks that the section is wholly contained in the segment.
+            # The third condition is the 'strict' one - an empty section will
+            # not match at the very end of the segment (unless the segment is
+            # also zero size, which is handled by the second condition).
+            if not (secaddr >= vaddr and
+                    secaddr - vaddr + section['sh_size'] <= self['p_memsz'] and 
+                    secaddr - vaddr <= self['p_memsz'] - 1):
+                return False
+
+        # If we've come this far and it's a NOBITS section, it's in the segment
+        if sectype == 'SHT_NOBITS':
+            return True
+
+        secoffset = section['sh_offset']
+        poffset = self['p_offset']
+
+        # Same logic as with secaddr vs. vaddr checks above, just on offsets in
+        # the file
+        return (secoffset >= poffset and 
+                secoffset - poffset + section['sh_size'] <= self['p_filesz'] and
+                secoffset - poffset <= self['p_filesz'] - 1)
+
 
 class InterpSegment(Segment):
     """ INTERP segment. Knows how to obtain the path to the interpreter used
index 2b21549bbde8141780d136d30838b28c83479914..e6addb77e2ec7b6c0912272317f4d35b4b6dfca0 100644 (file)
@@ -146,6 +146,25 @@ class ReadElf(object):
                 self._emitline('      [Requesting program interpreter: %s]' % 
                     segment.get_interp_name())
 
+        # Sections to segments mapping
+        #
+        if self.elffile.num_sections() == 0:
+            # No sections? We're done
+            return 
+
+        self._emitline('\n Section to Segment mapping:')
+        self._emitline('  Segment Sections...\n')
+
+        for nseg, segment in enumerate(self.elffile.iter_segments()):
+            self._emit('   %2.2d    ' % nseg)
+
+            for section in self.elffile.iter_sections():
+                if (    not section.is_null() and 
+                        segment.section_in_segment(section)):
+                    self._emit('%s ' % section.name)
+
+            self._emitline('')
+