# HG changeset patch # User Mike Frysinger # Date 1352755639 18000 # Node ID a9c9b2f9ec964e6750dd6f9a96767fe2e9201d85 # Parent f3408c7b954910aa3a58e88196efba4954c0cc55 add support for parsing of the dynamic section/segment and its tags diff -r f3408c7b9549 -r a9c9b2f9ec96 elftools/elf/dynamic.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/elftools/elf/dynamic.py Mon Nov 12 16:27:19 2012 -0500 @@ -0,0 +1,115 @@ +#------------------------------------------------------------------------------- +# elftools: elf/dynamic.py +# +# ELF Dynamic Tags +# +# Mike Frysinger (vapier@gentoo.org) +# This code is in the public domain +#------------------------------------------------------------------------------- +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. + """ + def __init__(self, entry, elffile): + self.entry = entry + if entry.d_tag == 'DT_NEEDED' or \ + entry.d_tag == 'DT_RPATH' or \ + entry.d_tag == 'DT_RUNPATH': + 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 '' % (self.entry.d_tag, self.entry) + + def __str__(self): + if self.entry.d_tag == 'DT_NEEDED' or \ + self.entry.d_tag == 'DT_RPATH' or \ + self.entry.d_tag == 'DT_RUNPATH': + s = '"%s"' % getattr(self, self.entry.d_tag[3:].lower()) + else: + s = '%#x' % self.entry.d_ptr + return '' % (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) + """ + offset = self._offset - self._tagsize + for i in range(self.num_tags): + offset += self._tagsize + entry = struct_parse( + self._elfstructs.Elf_Dyn, + self._stream, + stream_pos=offset) + if type is not None and entry.d_tag != type: + continue + yield DynamicTag(entry, self._elffile) + + 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 + + offset = self._offset + while True: + entry = struct_parse( + self._elfstructs.Elf_Dyn, + self._stream, + stream_pos=offset) + if entry.d_tag == 'DT_NULL': + self._num_tags = ((offset - self._offset) // self._tagsize) + 1 + break + offset += self._tagsize + 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']) diff -r f3408c7b9549 -r a9c9b2f9ec96 elftools/elf/elffile.py --- a/elftools/elf/elffile.py Thu Jul 05 06:32:09 2012 +0300 +++ b/elftools/elf/elffile.py Mon Nov 12 16:27:19 2012 -0500 @@ -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 -r f3408c7b9549 -r a9c9b2f9ec96 elftools/elf/enums.py --- a/elftools/elf/enums.py Thu Jul 05 06:32:09 2012 +0300 +++ b/elftools/elf/enums.py Mon Nov 12 16:27:19 2012 -0500 @@ -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 -r f3408c7b9549 -r a9c9b2f9ec96 elftools/elf/structs.py --- a/elftools/elf/structs.py Thu Jul 05 06:32:09 2012 +0300 +++ b/elftools/elf/structs.py Mon Nov 12 16:27:19 2012 -0500 @@ -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']