add Elf_Dyn support
This adds support for Elf_Dyn tags. Pull request sent to upstream:
https://bitbucket.org/eliben/pyelftools/pull-request/5/add-support-for-parsing-of-the-dynamic/diff
BUG=chromium-os:36453
TEST=lddtree.py works
Change-Id: Iaf383eacc45adccb4dfc33e275028a8e7f58ff1e
Reviewed-on: https://gerrit.chromium.org/gerrit/38667
Reviewed-by: David James <davidjames@chromium.org>
Commit-Ready: Mike Frysinger <vapier@chromium.org>
Tested-by: Mike Frysinger <vapier@chromium.org>
diff --git a/elftools/elf/dynamic.py b/elftools/elf/dynamic.py
new file mode 100644
index 0000000..2292470
--- /dev/null
+++ b/elftools/elf/dynamic.py
@@ -0,0 +1,106 @@
+#-------------------------------------------------------------------------------
+# elftools: elf/dynamic.py
+#
+# ELF Dynamic Tags
+#
+# Mike Frysinger (vapier@gentoo.org)
+# This code is in the public domain
+#-------------------------------------------------------------------------------
+import itertools
+
+from .sections import Section
+from .segments import Segment
+from ..common.utils import struct_parse
+
+from enums import ENUM_D_TAG
+
+
+class DynamicTag(object):
+ """ Dynamic Tag object - representing a single dynamic tag entry from a
+ dynamic section.
+
+ Similarly to Section objects, allows dictionary-like access to the
+ dynamic tag.
+ """
+
+ _HANDLED_TAGS = frozenset(['DT_NEEDED', 'DT_RPATH', 'DT_RUNPATH'])
+
+ def __init__(self, entry, elffile):
+ self.entry = entry
+ if entry.d_tag in self._HANDLED_TAGS:
+ dynstr = elffile.get_section_by_name('.dynstr')
+ setattr(self, entry.d_tag[3:].lower(), dynstr.get_string(self.entry.d_val))
+
+ 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())
+ else:
+ s = '%#x' % self.entry.d_ptr
+ return '<DynamicTag (%s) %s>' % (self.entry.d_tag, s)
+
+
+class Dynamic(object):
+ 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()
+
+ 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
+
+ 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)
+
+ @property
+ 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
+ return n
+
+
+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'])
diff --git a/elftools/elf/elffile.py b/elftools/elf/elffile.py
index bda6cae..e2bd904 100644
--- a/elftools/elf/elffile.py
+++ b/elftools/elf/elffile.py
@@ -13,6 +13,7 @@
from .structs import ELFStructs
from .sections import (
Section, StringTableSection, SymbolTableSection, NullSection)
+from .dynamic import DynamicSection, DynamicSegment
from .relocation import RelocationSection, RelocationHandler
from .segments import Segment, InterpSegment
from .enums import ENUM_RELOC_TYPE_i386, ENUM_RELOC_TYPE_x64
@@ -208,6 +209,8 @@
segtype = segment_header['p_type']
if segtype == 'PT_INTERP':
return InterpSegment(segment_header, self.stream)
+ elif segtype == 'PT_DYNAMIC':
+ return DynamicSegment(segment_header, self.stream, self)
else:
return Segment(segment_header, self.stream)
@@ -241,6 +244,8 @@
elif sectype in ('SHT_REL', 'SHT_RELA'):
return RelocationSection(
section_header, name, self.stream, self)
+ elif sectype == 'SHT_DYNAMIC':
+ return DynamicSection(section_header, name, self.stream, self)
else:
return Section(section_header, name, self.stream)
diff --git a/elftools/elf/enums.py b/elftools/elf/enums.py
index 78302ae..804fc45 100644
--- a/elftools/elf/enums.py
+++ b/elftools/elf/enums.py
@@ -186,6 +186,82 @@
_default_=Pass,
)
+# d_tag
+ENUM_D_TAG = dict(
+ DT_NULL=0,
+ DT_NEEDED=1,
+ DT_PLTRELSZ=2,
+ DT_PLTGOT=3,
+ DT_HASH=4,
+ DT_STRTAB=5,
+ DT_SYMTAB=6,
+ DT_RELA=7,
+ DT_RELASZ=8,
+ DT_RELAENT=9,
+ DT_STRSZ=10,
+ DT_SYMENT=11,
+ DT_INIT=12,
+ DT_FINI=13,
+ DT_SONAME=14,
+ DT_RPATH=15,
+ DT_SYMBOLIC=16,
+ DT_REL=17,
+ DT_RELSZ=18,
+ DT_RELENT=19,
+ DT_PLTREL=20,
+ DT_DEBUG=21,
+ DT_TEXTREL=22,
+ DT_JMPREL=23,
+ DT_BIND_NOW=24,
+ DT_INIT_ARRAY=25,
+ DT_FINI_ARRAY=26,
+ DT_INIT_ARRAYSZ=27,
+ DT_FINI_ARRAYSZ=28,
+ DT_RUNPATH=29,
+ DT_FLAGS=30,
+ DT_ENCODING=32,
+ DT_PREINIT_ARRAY=32,
+ DT_PREINIT_ARRAYSZ=33,
+ DT_NUM=34,
+ DT_LOOS=0x6000000d,
+ DT_HIOS=0x6ffff000,
+ DT_LOPROC=0x70000000,
+ DT_HIPROC=0x7fffffff,
+ DT_PROCNUM=0x35,
+ DT_VALRNGLO=0x6ffffd00,
+ DT_GNU_PRELINKED=0x6ffffdf5,
+ DT_GNU_CONFLICTSZ=0x6ffffdf6,
+ DT_GNU_LIBLISTSZ=0x6ffffdf7,
+ DT_CHECKSUM=0x6ffffdf8,
+ DT_PLTPADSZ=0x6ffffdf9,
+ DT_MOVEENT=0x6ffffdfa,
+ DT_MOVESZ=0x6ffffdfb,
+ DT_SYMINSZ=0x6ffffdfe,
+ DT_SYMINENT=0x6ffffdff,
+ DT_GNU_HASH=0x6ffffef5,
+ DT_TLSDESC_PLT=0x6ffffef6,
+ DT_TLSDESC_GOT=0x6ffffef7,
+ DT_GNU_CONFLICT=0x6ffffef8,
+ DT_GNU_LIBLIST=0x6ffffef9,
+ DT_CONFIG=0x6ffffefa,
+ DT_DEPAUDIT=0x6ffffefb,
+ DT_AUDIT=0x6ffffefc,
+ DT_PLTPAD=0x6ffffefd,
+ DT_MOVETAB=0x6ffffefe,
+ DT_SYMINFO=0x6ffffeff,
+ DT_VERSYM=0x6ffffff0,
+ DT_RELACOUNT=0x6ffffff9,
+ DT_RELCOUNT=0x6ffffffa,
+ DT_FLAGS_1=0x6ffffffb,
+ DT_VERDEF=0x6ffffffc,
+ DT_VERDEFNUM=0x6ffffffd,
+ DT_VERNEED=0x6ffffffe,
+ DT_VERNEEDNUM=0x6fffffff,
+ DT_AUXILIARY=0x7ffffffd,
+ DT_FILTER=0x7fffffff,
+ _default_=Pass,
+)
+
ENUM_RELOC_TYPE_i386 = dict(
R_386_NONE=0,
R_386_32=1,
diff --git a/elftools/elf/structs.py b/elftools/elf/structs.py
index 2c55d5b..08567de 100644
--- a/elftools/elf/structs.py
+++ b/elftools/elf/structs.py
@@ -72,6 +72,7 @@
self._create_shdr()
self._create_sym()
self._create_rel()
+ self._create_dyn()
def _create_ehdr(self):
self.Elf_Ehdr = Struct('Elf_Ehdr',
@@ -165,6 +166,13 @@
self.Elf_sxword('r_addend'),
)
+ def _create_dyn(self):
+ self.Elf_Dyn = Struct('Elf_Dyn',
+ Enum(self.Elf_sxword('d_tag'), **ENUM_D_TAG),
+ self.Elf_xword('d_val'),
+ Value('d_ptr', lambda ctx: ctx['d_val']),
+ )
+
def _create_sym(self):
# st_info is hierarchical. To access the type, use
# container['st_info']['type']