+++ /dev/null
-From b3157177bde20a2b0d0ada7b2ba44144ee5aea6f Mon Sep 17 00:00:00 2001
-From: Mike Frysinger <vapier@gentoo.org>
-Date: Sun, 9 Jun 2013 18:42:40 -0400
-Subject: [PATCH] support parsing of dynamic ELFs w/out section headers
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-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.
-
-You can see this in action:
-$ eu-strip -g --strip-sections a.out
-$ readelf -S a.out
-<nothing>
-$ lddtree.py ./a.out
-a.out (interpreter => /lib64/ld-linux-x86-64.so.2)
- libïäöëß.so => None
- libc.so.6 => /lib64/libc.so.6
-
-Signed-off-by: Mike Frysinger <vapier@gentoo.org>
----
- elftools/elf/dynamic.py | 81 ++++++++++++++++++---
- test/test_dynamic.py | 28 ++++++-
- .../aarch64_super_stripped.elf | Bin 0 -> 4136 bytes
- 3 files changed, 97 insertions(+), 12 deletions(-)
- create mode 100755 test/testfiles_for_unittests/aarch64_super_stripped.elf
-
-diff --git a/elftools/elf/dynamic.py b/elftools/elf/dynamic.py
-index d9db870..ad5111f 100644
---- a/elftools/elf/dynamic.py
-+++ b/elftools/elf/dynamic.py
-@@ -11,9 +11,22 @@ import itertools
- from .sections import Section
- from .segments import Segment
- from ..common.exceptions import ELFError
--from ..common.utils import struct_parse
--
--from .enums import ENUM_D_TAG
-+from ..common.utils import struct_parse, parse_cstring_from_stream
-+
-+
-+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):
-@@ -61,27 +76,71 @@ class Dynamic(object):
- self._num_tags = -1
- self._offset = position
- self._tagsize = self._elfstructs.Elf_Dyn.sizeof()
-- self._stringtable = stringtable
-+ self.__stringtable = stringtable
-
-- def iter_tags(self, type=None):
-- """ Yield all tags (limit to |type| if specified)
-+ @property
-+ def _stringtable(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.__stringtable:
-+ return self.__stringtable
-+
-+ # 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.__stringtable = _DynamicStringTable(
-+ self._stream,
-+ segment['p_offset'] + (strtab - segment['p_vaddr']))
-+ return self.__stringtable
-+
-+ # That didn't work for some reason. Let's use the section header
-+ # even though this ELF is super weird.
-+ self.__stringtable = self._elffile.get_section_by_name(b'.dynstr')
-+
-+ return self.__stringtable
-+
-+ 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.entry.d_tag == type:
-+ tag = self._get_tag(n)
-+ if type is None or tag['d_tag'] == type:
- yield tag
-- if tag.entry.d_tag == 'DT_NULL':
-+ if tag['d_tag'] == 'DT_NULL':
- break
-
-- def get_tag(self, n):
-- """ Get the tag at index #n from the file (DynamicTag object)
-+ 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._stringtable)
-+
-+ def _get_tag(self, n):
-+ """ Get the raw tag at index #n from the file
- """
- offset = self._offset + n * self._tagsize
-- entry = struct_parse(
-+ return struct_parse(
- self._elfstructs.Elf_Dyn,
- self._stream,
- stream_pos=offset)
-- return DynamicTag(entry, self._stringtable)
-+
-+ def get_tag(self, n):
-+ """ Get the tag at index #n from the file (DynamicTag object)
-+ """
-+ return DynamicTag(self._get_tag(n), self._stringtable)
-
- def num_tags(self):
- """ Number of dynamic tags in the file
---
-2.0.0
-
+++ /dev/null
-From 80305ad20ebd481dde19fa7ff2d90249269aa588 Mon Sep 17 00:00:00 2001
-From: Eli Bendersky <eliben@gmail.com>
-Date: Wed, 23 Apr 2014 16:44:11 -0700
-Subject: [PATCH] Issue #29: Fail more gracefully when no string table is found
- for dynamic.
-
----
- elftools/elf/dynamic.py | 4 ++++
- test/test_dynamic.py | 25 +++++++++++++++++++++++++
- 2 files changed, 29 insertions(+)
- create mode 100644 test/test_dynamic.py
-
-diff --git a/elftools/elf/dynamic.py b/elftools/elf/dynamic.py
-index e36598e..6f88bf9 100644
---- a/elftools/elf/dynamic.py
-+++ b/elftools/elf/dynamic.py
-@@ -10,6 +10,7 @@ import itertools
-
- from .sections import Section
- from .segments import Segment
-+from ..common.exceptions import ELFError
- from ..common.utils import struct_parse
-
- from .enums import ENUM_D_TAG
-@@ -29,6 +30,8 @@ class DynamicTag(object):
- 'DT_SUNW_FILTER'])
-
- def __init__(self, entry, stringtable):
-+ if stringtable is None:
-+ raise ELFError('Creating DynamicTag without string table')
- self.entry = entry
- if entry.d_tag in self._HANDLED_TAGS:
- setattr(self, entry.d_tag[3:].lower(),
-@@ -114,6 +117,7 @@ class DynamicSegment(Segment, Dynamic):
- # So we must look for the dynamic section contained in the dynamic
- # segment, we do so by searching for the dynamic section whose content
- # is located at the same offset as the dynamic segment
-+ stringtable = None
- for section in elffile.iter_sections():
- if (isinstance(section, DynamicSection) and
- section['sh_offset'] == header['p_offset']):
-diff --git a/test/test_dynamic.py b/test/test_dynamic.py
-new file mode 100644
-index 0000000..0ee9b35
---- /dev/null
-+++ b/test/test_dynamic.py
-@@ -0,0 +1,25 @@
-+#-------------------------------------------------------------------------------
-+# elftools tests
-+#
-+# Eli Bendersky (eliben@gmail.com)
-+# This code is in the public domain
-+#-------------------------------------------------------------------------------
-+try:
-+ import unittest2 as unittest
-+except ImportError:
-+ import unittest
-+import os
-+
-+from utils import setup_syspath; setup_syspath()
-+from elftools.common.exceptions import ELFError
-+from elftools.elf.dynamic import DynamicTag
-+
-+
-+class TestDynamicTag(unittest.TestCase):
-+ def test_requires_stringtable(self):
-+ with self.assertRaises(ELFError):
-+ dt = DynamicTag('', None)
-+
-+
-+if __name__ == '__main__':
-+ unittest.main()
---
-2.0.0
-