blob: b30bd63efb2db7026c28859d117c7487351d7a17 [file] [log] [blame]
#-------------------------------------------------------------------------------
# elftools: elf/sections.py
#
# ELF sections
#
# Eli Bendersky (eliben@gmail.com)
# This code is in the public domain
#-------------------------------------------------------------------------------
from ..construct import CString
from ..common.utils import struct_parse, elf_assert
class Section(object):
""" Base class for ELF sections. Also used for all sections types that have
no special functionality.
Allows dictionary-like access to the section header. For example:
> sec = Section(...)
> sec['sh_type'] # section type
"""
def __init__(self, header, name, stream):
self.header = header
self.name = name
self.stream = stream
def data(self):
""" The section data from the file.
"""
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]
def __eq__(self, other):
return self.header == other.header
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.
"""
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']
return struct_parse(
CString(''),
self.stream,
stream_pos=table_offset + offset)
class SymbolTableSection(Section):
""" ELF symbol table section. Has an associated StringTableSection that's
passed in the constructor.
"""
def __init__(self, header, name, stream, elfstructs, stringtable):
super(SymbolTableSection, self).__init__(header, name, stream)
self.elfstructs = elfstructs
self.stringtable = stringtable
elf_assert(self['sh_entsize'] > 0,
'Expected entry size of section %s to be > 0' % name)
elf_assert(self['sh_size'] % self['sh_entsize'] == 0,
'Expected section size to be a multiple of entry size in section %s' % name)
def num_symbols(self):
""" Number of symbols in the table
"""
return self['sh_size'] // self['sh_entsize']
def get_symbol(self, n):
""" Get the symbol at index #n from the table (Symbol object)
"""
# Grab the symbol's entry from the stream
entry_offset = self['sh_offset'] + n * self['sh_entsize']
entry = struct_parse(
self.elfstructs.Elf_Sym,
self.stream,
stream_pos=entry_offset)
# Find the symbol name in the associated string table
name = self.stringtable.get_string(entry['st_name'])
return Symbol(entry, name)
def iter_symbols(self):
""" Yield all the symbols in the table
"""
for i in range(self.num_symbols()):
yield self.get_symbol(i)
class RelocationSection(Section):
def __init__(self, header, name, stream, elfstructs):
super(RelocationSection, self).__init__(header, name, stream)
self.elfstructs = elfstructs
if self.header['sh_type'] == 'SHT_REL':
expected_size = self.elfstructs.Elf_Rel.sizeof()
self.entry_struct = self.elfstructs.Elf_Rel
elif self.header['sh_type'] == 'SHT_RELA':
expected_size = self.elfstructs.Elf_Rela.sizeof()
self.entry_struct = self.elfstructs.Elf_Rela
else:
elf_assert(False, 'Unknown relocation type section')
elf_assert(
self.header['sh_entsize'] == expected_size,
'Expected sh_entsize of SHT_REL section to be %s' % expected_size)
def is_RELA(self):
""" Is this a RELA relocation section? If not, it's REL.
"""
return self.header['sh_type'] == 'SHT_RELA'
def num_relocations(self):
""" Number of relocations in the section
"""
return self['sh_size'] // self['sh_entsize']
def get_relocation(self, n):
""" Get the relocation at index #n from the section (Relocation object)
"""
entry_offset = self['sh_offset'] + n * self['sh_entsize']
entry = struct_parse(
self.entry_struct,
self.stream,
stream_pos=entry_offset)
return Relocation(entry)
def iter_relocations(self):
""" Yield all the relocations in the section
"""
for i in range(self.num_relocations()):
yield self.get_relocation(i)
class Symbol(object):
""" Symbol object - representing a single symbol entry from a symbol table
section.
Similarly to Section objects, allows dictionary-like access to the
symbol entry.
"""
def __init__(self, entry, name):
self.entry = entry
self.name = name
def __getitem__(self, name):
""" Implement dict-like access to entries
"""
return self.entry[name]
class Relocation(object):
""" Relocation object - representing a single relocation entry. Allows
dictionary-like access to the entry's fields.
Can be either a REL or RELA relocation.
"""
def __init__(self, entry):
self.entry = entry
def is_RELA(self):
""" Is this a RELA relocation? If not, it's REL.
"""
return 'r_addend' in self.entry
def __getitem__(self, name):
""" Dict-like access to entries
"""
return self.entry[name]
def __repr__(self):
return '<Relocation (%s): %s>' % (
'RELA' if self.is_RELA() else 'REL',
self.entry)
def __str__(self):
return self.__repr__()