From: Eli Bendersky Date: Thu, 15 Sep 2011 04:07:54 +0000 (+0300) Subject: Section to segment mapping seems to be working - yay! X-Git-Tag: v0.10~124 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=58585b0339dcf032aeea5e82ce89da76acdaa90a;p=pyelftools.git Section to segment mapping seems to be working - yay! --- diff --git a/elftools/elf/elffile.py b/elftools/elf/elffile.py index 32373e9..2999cc1 100644 --- a/elftools/elf/elffile.py +++ b/elftools/elf/elffile.py @@ -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: diff --git a/elftools/elf/enums.py b/elftools/elf/enums.py index 37ddb86..8715bf1 100644 --- a/elftools/elf/enums.py +++ b/elftools/elf/enums.py @@ -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, diff --git a/elftools/elf/sections.py b/elftools/elf/sections.py index ba4805a..f9dd149 100644 --- a/elftools/elf/sections.py +++ b/elftools/elf/sections.py @@ -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. """ diff --git a/elftools/elf/segments.py b/elftools/elf/segments.py index 5e61b28..217ba08 100644 --- a/elftools/elf/segments.py +++ b/elftools/elf/segments.py @@ -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 diff --git a/scripts/readelf.py b/scripts/readelf.py index 2b21549..e6addb7 100644 --- a/scripts/readelf.py +++ b/scripts/readelf.py @@ -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('') +