blob: 824cb78a9913268bd9d60d1cb7fdf5f2bf9a25d5 [file] [log] [blame]
# elftools: elf/
# ELF Dynamic Tags
# Mike Frysinger (
# This code is in the public domain
import itertools
from .sections import Section
from .segments import Segment
from ..common.utils import struct_parse, parse_cstring_from_stream
from .enums import ENUM_D_TAG
class _DynamicStringTable(object):
""" Bare string table based on values found via ELF dynamic tags and
loadable segments only. Good enough for get_string() only.
def __init__(self, stream, table_offset):
self._stream = stream
self._table_offset = table_offset
def get_string(self, offset):
""" Get the string stored at the given offset in this string table.
return parse_cstring_from_stream(self._stream,
self._table_offset + offset)
class DynamicTag(object):
""" Dynamic Tag object - representing a single dynamic tag entry from a
dynamic section.
Allows dictionary-like access to the dynamic structure. For special
tags (those listed in the _HANDLED_TAGS set below), creates additional
attributes for convenience. For example, .soname will contain the actual
value of DT_SONAME (fetched from the dynamic symbol table).
_HANDLED_TAGS = frozenset(
def __init__(self, entry, dynstr):
self.entry = entry
if entry.d_tag in self._HANDLED_TAGS and dynstr:
setattr(self, entry.d_tag[3:].lower(),
def __getitem__(self, name):
""" Implement dict-like access to entries
return self.entry[name]
def __repr__(self):
return '<DynamicTag (%s): %r>' % (self.entry.d_tag, self.entry)
def __str__(self):
if self.entry.d_tag in self._HANDLED_TAGS:
s = '"%s"' % getattr(self, self.entry.d_tag[3:].lower())
s = '%#x' % self.entry.d_ptr
return '<DynamicTag (%s) %s>' % (self.entry.d_tag, s)
class Dynamic(object):
""" Shared functionality between dynamic sections and segments.
def __init__(self, stream, elffile, position):
self._stream = stream
self._elffile = elffile
self._elfstructs = elffile.structs
self._num_tags = -1
self._offset = position
self._tagsize = self._elfstructs.Elf_Dyn.sizeof()
self.__string_table = None
def _string_table(self):
""" Return a string table for looking up dynamic tag related strings.
This won't be a "full" string table object, but will at least support
the get_string() function.
if self.__string_table:
return self.__string_table
# If the ELF has stripped its section table (which is unusual, but
# perfectly valid), we need to use the dynamic tags to locate the
# dynamic string table.
strtab = None
for tag in self._iter_tags(type='DT_STRTAB'):
strtab = tag['d_val']
# If we found a dynamic string table, locate the offset in the file
# by using the program headers.
if strtab:
for segment in self._elffile.iter_segments():
if (strtab >= segment['p_vaddr'] and
strtab < segment['p_vaddr'] + segment['p_filesz']):
self.__string_table = _DynamicStringTable(
segment['p_offset'] + (strtab - segment['p_vaddr']))
return self.__string_table
# That didn't work for some reason. Let's use the section header
# even though this ELF is super weird.
self.__string_table = self._elffile.get_section_by_name(b'.dynstr')
return self.__string_table
def _iter_tags(self, type=None):
""" Yield all raw tags (limit to |type| if specified)
for n in itertools.count():
tag = self._get_tag(n)
if type is None or tag['d_tag'] == type:
yield tag
if tag['d_tag'] == 'DT_NULL':
def iter_tags(self, type=None):
""" Yield all tags (limit to |type| if specified)
for tag in self._iter_tags(type=type):
yield DynamicTag(tag, self._string_table)
def _get_tag(self, n):
""" Get the raw tag at index #n from the file
offset = self._offset + n * self._tagsize
return struct_parse(
def get_tag(self, n):
""" Get the tag at index #n from the file (DynamicTag object)
return DynamicTag(self._get_tag(n), self._string_table)
def num_tags(self):
""" Number of dynamic tags in the file
if self._num_tags != -1:
return self._num_tags
for n in itertools.count():
tag = self.get_tag(n)
if tag.entry.d_tag == 'DT_NULL':
self._num_tags = n + 1
return self._num_tags
class DynamicSection(Section, Dynamic):
""" ELF dynamic table section. Knows how to process the list of tags.
def __init__(self, header, name, stream, elffile):
Section.__init__(self, header, name, stream)
Dynamic.__init__(self, stream, elffile, self['sh_offset'])
class DynamicSegment(Segment, Dynamic):
""" ELF dynamic table segment. Knows how to process the list of tags.
def __init__(self, header, stream, elffile):
Segment.__init__(self, header, stream)
Dynamic.__init__(self, stream, elffile, self['p_offset'])