You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
gentoo-overlay/dev-python/pyelftools/files/pyelftools-0.21-dyntable.patch

144 lines
5.2 KiB

changeset: 207:92736c403d53
tag: tip
user: Mike Frysinger <vapier@gentoo.org>
date: Mon Apr 22 19:02:21 2013 -0400
summary: support parsing of dynamic ELFs w/out section headers
At runtime, ELFs do not use the section headers at all. Instead, only
the program segments and dynamic tags get used. This means you can
strip the section table completely from an ELF and have it still work.
In practice, people rarely do this, but it's not unheard of. Make the
Dynamic tags work even in these cases by loading the strings table the
same way the runtime loader does:
- parse the symtab address from DT_STRTAB
- locate the file offset via the program segments
In order to avoid circular deps (parsing a dyntag requires walking parsed
dyntags), add a set of internal funcs for returning the raw values.
diff --git a/elftools/elf/dynamic.py b/elftools/elf/dynamic.py
--- a/elftools/elf/dynamic.py
+++ b/elftools/elf/dynamic.py
@@ -10,11 +10,26 @@
from .sections import Section
from .segments import Segment
-from ..common.utils import struct_parse
+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.
@@ -27,10 +42,9 @@
_HANDLED_TAGS = frozenset(
['DT_NEEDED', 'DT_RPATH', 'DT_RUNPATH', 'DT_SONAME'])
- def __init__(self, entry, elffile):
+ def __init__(self, entry, dynstr):
self.entry = entry
- if entry.d_tag in self._HANDLED_TAGS:
- dynstr = elffile.get_section_by_name(b'.dynstr')
+ if entry.d_tag in self._HANDLED_TAGS and dynstr:
setattr(self, entry.d_tag[3:].lower(),
dynstr.get_string(self.entry.d_val))
@@ -60,26 +74,66 @@
self._num_tags = -1
self._offset = position
self._tagsize = self._elfstructs.Elf_Dyn.sizeof()
+ self.__string_table = None
+
+ @property
+ def _string_table(self):
+ 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']
+ break
+ # 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(
+ self._stream,
+ 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':
+ break
def iter_tags(self, type=None):
""" Yield all tags (limit to |type| if specified)
"""
- for n in itertools.count():
- tag = self.get_tag(n)
- if type is None or tag.entry.d_tag == type:
- yield tag
- if tag.entry.d_tag == 'DT_NULL':
- break
+ 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(
+ self._elfstructs.Elf_Dyn,
+ self._stream,
+ stream_pos=offset)
def get_tag(self, n):
""" Get the tag at index #n from the file (DynamicTag object)
"""
- offset = self._offset + n * self._tagsize
- entry = struct_parse(
- self._elfstructs.Elf_Dyn,
- self._stream,
- stream_pos=offset)
- return DynamicTag(entry, self._elffile)
+ return DynamicTag(self._get_tag(n), self._string_table)
def num_tags(self):
""" Number of dynamic tags in the file