08c3a6
commit 3e0a91b79b409a6a4113a0fdb08221c0bb29cfce
08c3a6
Author: Florian Weimer <fweimer@redhat.com>
08c3a6
Date:   Mon Apr 11 11:28:08 2022 +0200
08c3a6
08c3a6
    scripts: Add glibcelf.py module
08c3a6
    
08c3a6
    Hopefully, this will lead to tests that are easier to maintain.  The
08c3a6
    current approach of parsing readelf -W output using regular expressions
08c3a6
    is not necessarily easier than parsing the ELF data directly.
08c3a6
    
08c3a6
    This module is still somewhat incomplete (e.g., coverage of relocation
08c3a6
    types and versioning information is missing), but it is sufficient to
08c3a6
    perform basic symbol analysis or program header analysis.
08c3a6
    
08c3a6
    The EM_* mapping for architecture-specific constant classes (e.g.,
08c3a6
    SttX86_64) is not yet implemented.  The classes are defined for the
08c3a6
    benefit of elf/tst-glibcelf.py.
08c3a6
    
08c3a6
    Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
08c3a6
    (cherry picked from commit 30035d67728a846fa39749cd162afd278ac654c4)
08c3a6
08c3a6
diff --git a/elf/Makefile b/elf/Makefile
08c3a6
index 8e2dd91c583f9a62..8afbe3f6ab259331 100644
08c3a6
--- a/elf/Makefile
08c3a6
+++ b/elf/Makefile
08c3a6
@@ -1053,6 +1053,13 @@ CFLAGS-tst-prelink.c += -fno-pie
08c3a6
 tst-prelink-no-pie = yes
08c3a6
 endif
08c3a6
 
08c3a6
+tests-special += $(objpfx)tst-glibcelf.out
08c3a6
+$(objpfx)tst-glibcelf.out: tst-glibcelf.py elf.h $(..)/scripts/glibcelf.py \
08c3a6
+  $(..)/scripts/glibcextract.py
08c3a6
+	PYTHONPATH=$(..)scripts $(PYTHON) tst-glibcelf.py \
08c3a6
+          --cc="$(CC) $(patsubst -DMODULE_NAME=%,-DMODULE_NAME=testsuite,$(CPPFLAGS))" \
08c3a6
+	  < /dev/null > $@ 2>&1; $(evaluate-test)
08c3a6
+
08c3a6
 # The test requires shared _and_ PIE because the executable
08c3a6
 # unit test driver must be able to link with the shared object
08c3a6
 # that is going to eventually go into an installed DSO.
08c3a6
diff --git a/elf/tst-glibcelf.py b/elf/tst-glibcelf.py
08c3a6
new file mode 100644
08c3a6
index 0000000000000000..bf15a3bad4479e08
08c3a6
--- /dev/null
08c3a6
+++ b/elf/tst-glibcelf.py
08c3a6
@@ -0,0 +1,260 @@
08c3a6
+#!/usr/bin/python3
08c3a6
+# Verify scripts/glibcelf.py contents against elf/elf.h.
08c3a6
+# Copyright (C) 2022 Free Software Foundation, Inc.
08c3a6
+# This file is part of the GNU C Library.
08c3a6
+#
08c3a6
+# The GNU C Library is free software; you can redistribute it and/or
08c3a6
+# modify it under the terms of the GNU Lesser General Public
08c3a6
+# License as published by the Free Software Foundation; either
08c3a6
+# version 2.1 of the License, or (at your option) any later version.
08c3a6
+#
08c3a6
+# The GNU C Library is distributed in the hope that it will be useful,
08c3a6
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
08c3a6
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
08c3a6
+# Lesser General Public License for more details.
08c3a6
+#
08c3a6
+# You should have received a copy of the GNU Lesser General Public
08c3a6
+# License along with the GNU C Library; if not, see
08c3a6
+# <https://www.gnu.org/licenses/>.
08c3a6
+
08c3a6
+import argparse
08c3a6
+import enum
08c3a6
+import sys
08c3a6
+
08c3a6
+import glibcelf
08c3a6
+import glibcextract
08c3a6
+
08c3a6
+errors_encountered = 0
08c3a6
+
08c3a6
+def error(message):
08c3a6
+    global errors_encountered
08c3a6
+    sys.stdout.write('error: {}\n'.format(message))
08c3a6
+    errors_encountered += 1
08c3a6
+
08c3a6
+# The enum constants in glibcelf are expected to have exactly these
08c3a6
+# prefixes.
08c3a6
+expected_constant_prefixes = tuple(
08c3a6
+    'ELFCLASS ELFDATA EM_ ET_ DT_ PF_ PT_ SHF_ SHN_ SHT_ STB_ STT_'.split())
08c3a6
+
08c3a6
+def find_constant_prefix(name):
08c3a6
+    """Returns a matching prefix from expected_constant_prefixes or None."""
08c3a6
+    for prefix in expected_constant_prefixes:
08c3a6
+        if name.startswith(prefix):
08c3a6
+            return prefix
08c3a6
+    return None
08c3a6
+
08c3a6
+def find_enum_types():
08c3a6
+    """A generator for OpenIntEnum and IntFlag classes in glibcelf."""
08c3a6
+    for obj in vars(glibcelf).values():
08c3a6
+        if isinstance(obj, type) and obj.__bases__[0] in (
08c3a6
+                glibcelf._OpenIntEnum, enum.Enum, enum.IntFlag):
08c3a6
+            yield obj
08c3a6
+
08c3a6
+def check_duplicates():
08c3a6
+    """Verifies that enum types do not have duplicate values.
08c3a6
+
08c3a6
+    Different types must have different member names, too.
08c3a6
+
08c3a6
+    """
08c3a6
+    global_seen = {}
08c3a6
+    for typ in find_enum_types():
08c3a6
+        seen = {}
08c3a6
+        last = None
08c3a6
+        for (name, e) in typ.__members__.items():
08c3a6
+            if e.value in seen:
08c3a6
+                error('{} has {}={} and {}={}'.format(
08c3a6
+                    typ, seen[e.value], e.value, name, e.value))
08c3a6
+                last = e
08c3a6
+            else:
08c3a6
+                seen[e.value] = name
08c3a6
+                if last is not None and last.value > e.value:
08c3a6
+                    error('{} has {}={} after {}={}'.format(
08c3a6
+                        typ, name, e.value, last.name, last.value))
08c3a6
+                if name in global_seen:
08c3a6
+                    error('{} used in {} and {}'.format(
08c3a6
+                        name, global_seen[name], typ))
08c3a6
+                else:
08c3a6
+                    global_seen[name] = typ
08c3a6
+
08c3a6
+def check_constant_prefixes():
08c3a6
+    """Check that the constant prefixes match expected_constant_prefixes."""
08c3a6
+    seen = set()
08c3a6
+    for typ in find_enum_types():
08c3a6
+        typ_prefix = None
08c3a6
+        for val in typ:
08c3a6
+            prefix = find_constant_prefix(val.name)
08c3a6
+            if prefix is None:
08c3a6
+                error('constant {!r} for {} has unknown prefix'.format(
08c3a6
+                    val, typ))
08c3a6
+                break
08c3a6
+            elif typ_prefix is None:
08c3a6
+                typ_prefix = prefix
08c3a6
+                seen.add(typ_prefix)
08c3a6
+            elif prefix != typ_prefix:
08c3a6
+                error('prefix {!r} for constant {!r}, expected {!r}'.format(
08c3a6
+                    prefix, val, typ_prefix))
08c3a6
+        if typ_prefix is None:
08c3a6
+            error('empty enum type {}'.format(typ))
08c3a6
+
08c3a6
+    for prefix in sorted(set(expected_constant_prefixes) - seen):
08c3a6
+        error('missing constant prefix {!r}'.format(prefix))
08c3a6
+    # Reverse difference is already covered inside the loop.
08c3a6
+
08c3a6
+def find_elf_h_constants(cc):
08c3a6
+    """Returns a dictionary of relevant constants from <elf.h>."""
08c3a6
+    return glibcextract.compute_macro_consts(
08c3a6
+        source_text='#include <elf.h>',
08c3a6
+        cc=cc,
08c3a6
+        macro_re='|'.join(
08c3a6
+            prefix + '.*' for prefix in expected_constant_prefixes))
08c3a6
+
08c3a6
+# The first part of the pair is a name of an <elf.h> constant that is
08c3a6
+# dropped from glibcelf.  The second part is the constant as it is
08c3a6
+# used in <elf.h>.
08c3a6
+glibcelf_skipped_aliases = (
08c3a6
+    ('EM_ARC_A5', 'EM_ARC_COMPACT'),
08c3a6
+    ('PF_PARISC_SBP', 'PF_HP_SBP')
08c3a6
+)
08c3a6
+
08c3a6
+# Constants that provide little value and are not included in
08c3a6
+# glibcelf: *LO*/*HI* range constants, *NUM constants counting the
08c3a6
+# number of constants.  Also includes the alias names from
08c3a6
+# glibcelf_skipped_aliases.
08c3a6
+glibcelf_skipped_constants = frozenset(
08c3a6
+    [e[0] for e in glibcelf_skipped_aliases]) | frozenset("""
08c3a6
+DT_AARCH64_NUM
08c3a6
+DT_ADDRNUM
08c3a6
+DT_ADDRRNGHI
08c3a6
+DT_ADDRRNGLO
08c3a6
+DT_ALPHA_NUM
08c3a6
+DT_ENCODING
08c3a6
+DT_EXTRANUM
08c3a6
+DT_HIOS
08c3a6
+DT_HIPROC
08c3a6
+DT_IA_64_NUM
08c3a6
+DT_LOOS
08c3a6
+DT_LOPROC
08c3a6
+DT_MIPS_NUM
08c3a6
+DT_NUM
08c3a6
+DT_PPC64_NUM
08c3a6
+DT_PPC_NUM
08c3a6
+DT_PROCNUM
08c3a6
+DT_SPARC_NUM
08c3a6
+DT_VALNUM
08c3a6
+DT_VALRNGHI
08c3a6
+DT_VALRNGLO
08c3a6
+DT_VERSIONTAGNUM
08c3a6
+ELFCLASSNUM
08c3a6
+ELFDATANUM
08c3a6
+ET_HIOS
08c3a6
+ET_HIPROC
08c3a6
+ET_LOOS
08c3a6
+ET_LOPROC
08c3a6
+ET_NUM
08c3a6
+PF_MASKOS
08c3a6
+PF_MASKPROC
08c3a6
+PT_HIOS
08c3a6
+PT_HIPROC
08c3a6
+PT_HISUNW
08c3a6
+PT_LOOS
08c3a6
+PT_LOPROC
08c3a6
+PT_LOSUNW
08c3a6
+SHF_MASKOS
08c3a6
+SHF_MASKPROC
08c3a6
+SHN_HIOS
08c3a6
+SHN_HIPROC
08c3a6
+SHN_HIRESERVE
08c3a6
+SHN_LOOS
08c3a6
+SHN_LOPROC
08c3a6
+SHN_LORESERVE
08c3a6
+SHT_HIOS
08c3a6
+SHT_HIPROC
08c3a6
+SHT_HIPROC
08c3a6
+SHT_HISUNW
08c3a6
+SHT_HIUSER
08c3a6
+SHT_LOOS
08c3a6
+SHT_LOPROC
08c3a6
+SHT_LOSUNW
08c3a6
+SHT_LOUSER
08c3a6
+SHT_NUM
08c3a6
+STB_HIOS
08c3a6
+STB_HIPROC
08c3a6
+STB_LOOS
08c3a6
+STB_LOPROC
08c3a6
+STB_NUM
08c3a6
+STT_HIOS
08c3a6
+STT_HIPROC
08c3a6
+STT_LOOS
08c3a6
+STT_LOPROC
08c3a6
+STT_NUM
08c3a6
+""".strip().split())
08c3a6
+
08c3a6
+def check_constant_values(cc):
08c3a6
+    """Checks the values of <elf.h> constants against glibcelf."""
08c3a6
+
08c3a6
+    glibcelf_constants = {
08c3a6
+        e.name: e for typ in find_enum_types() for e in typ}
08c3a6
+    elf_h_constants = find_elf_h_constants(cc=cc)
08c3a6
+
08c3a6
+    missing_in_glibcelf = (set(elf_h_constants) - set(glibcelf_constants)
08c3a6
+                           - glibcelf_skipped_constants)
08c3a6
+    for name in sorted(missing_in_glibcelf):
08c3a6
+        error('constant {} is missing from glibcelf'.format(name))
08c3a6
+
08c3a6
+    unexpected_in_glibcelf = \
08c3a6
+        set(glibcelf_constants) & glibcelf_skipped_constants
08c3a6
+    for name in sorted(unexpected_in_glibcelf):
08c3a6
+        error('constant {} is supposed to be filtered from glibcelf'.format(
08c3a6
+            name))
08c3a6
+
08c3a6
+    missing_in_elf_h = set(glibcelf_constants) - set(elf_h_constants)
08c3a6
+    for name in sorted(missing_in_elf_h):
08c3a6
+        error('constant {} is missing from <elf.h>'.format(name))
08c3a6
+
08c3a6
+    expected_in_elf_h = glibcelf_skipped_constants - set(elf_h_constants)
08c3a6
+    for name in expected_in_elf_h:
08c3a6
+        error('filtered constant {} is missing from <elf.h>'.format(name))
08c3a6
+
08c3a6
+    for alias_name, name_in_glibcelf in glibcelf_skipped_aliases:
08c3a6
+        if name_in_glibcelf not in glibcelf_constants:
08c3a6
+            error('alias value {} for {} not in glibcelf'.format(
08c3a6
+                name_in_glibcelf, alias_name))
08c3a6
+        elif (int(elf_h_constants[alias_name])
08c3a6
+              != glibcelf_constants[name_in_glibcelf].value):
08c3a6
+            error('<elf.h> has {}={}, glibcelf has {}={}'.format(
08c3a6
+                alias_name, elf_h_constants[alias_name],
08c3a6
+                name_in_glibcelf, glibcelf_constants[name_in_glibcelf]))
08c3a6
+
08c3a6
+    # Check for value mismatches:
08c3a6
+    for name in sorted(set(glibcelf_constants) & set(elf_h_constants)):
08c3a6
+        glibcelf_value = glibcelf_constants[name].value
08c3a6
+        elf_h_value = int(elf_h_constants[name])
08c3a6
+        # On 32-bit architectures <elf.h> as some constants that are
08c3a6
+        # parsed as signed, while they are unsigned in glibcelf.  So
08c3a6
+        # far, this only affects some flag constants, so special-case
08c3a6
+        # them here.
08c3a6
+        if (glibcelf_value != elf_h_value
08c3a6
+            and not (isinstance(glibcelf_constants[name], enum.IntFlag)
08c3a6
+                     and glibcelf_value == 1 << 31
08c3a6
+                     and elf_h_value == -(1 << 31))):
08c3a6
+            error('{}: glibcelf has {!r}, <elf.h> has {!r}'.format(
08c3a6
+                name, glibcelf_value, elf_h_value))
08c3a6
+
08c3a6
+def main():
08c3a6
+    """The main entry point."""
08c3a6
+    parser = argparse.ArgumentParser(
08c3a6
+        description="Check glibcelf.py and elf.h against each other.")
08c3a6
+    parser.add_argument('--cc', metavar='CC',
08c3a6
+                        help='C compiler (including options) to use')
08c3a6
+    args = parser.parse_args()
08c3a6
+
08c3a6
+    check_duplicates()
08c3a6
+    check_constant_prefixes()
08c3a6
+    check_constant_values(cc=args.cc)
08c3a6
+
08c3a6
+    if errors_encountered > 0:
08c3a6
+        print("note: errors encountered:", errors_encountered)
08c3a6
+        sys.exit(1)
08c3a6
+
08c3a6
+if __name__ == '__main__':
08c3a6
+    main()
08c3a6
diff --git a/scripts/glibcelf.py b/scripts/glibcelf.py
08c3a6
new file mode 100644
08c3a6
index 0000000000000000..8f7d0ca184845714
08c3a6
--- /dev/null
08c3a6
+++ b/scripts/glibcelf.py
08c3a6
@@ -0,0 +1,1135 @@
08c3a6
+#!/usr/bin/python3
08c3a6
+# ELF support functionality for Python.
08c3a6
+# Copyright (C) 2022 Free Software Foundation, Inc.
08c3a6
+# This file is part of the GNU C Library.
08c3a6
+#
08c3a6
+# The GNU C Library is free software; you can redistribute it and/or
08c3a6
+# modify it under the terms of the GNU Lesser General Public
08c3a6
+# License as published by the Free Software Foundation; either
08c3a6
+# version 2.1 of the License, or (at your option) any later version.
08c3a6
+#
08c3a6
+# The GNU C Library is distributed in the hope that it will be useful,
08c3a6
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
08c3a6
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
08c3a6
+# Lesser General Public License for more details.
08c3a6
+#
08c3a6
+# You should have received a copy of the GNU Lesser General Public
08c3a6
+# License along with the GNU C Library; if not, see
08c3a6
+# <https://www.gnu.org/licenses/>.
08c3a6
+
08c3a6
+"""Basic ELF parser.
08c3a6
+
08c3a6
+Use Image.readfile(path) to read an ELF file into memory and begin
08c3a6
+parsing it.
08c3a6
+
08c3a6
+"""
08c3a6
+
08c3a6
+import collections
08c3a6
+import enum
08c3a6
+import struct
08c3a6
+
08c3a6
+class _OpenIntEnum(enum.IntEnum):
08c3a6
+    """Integer enumeration that supports arbitrary int values."""
08c3a6
+    @classmethod
08c3a6
+    def _missing_(cls, value):
08c3a6
+        # See enum.IntFlag._create_pseudo_member_.  This allows
08c3a6
+        # creating of enum constants with arbitrary integer values.
08c3a6
+        pseudo_member = int.__new__(cls, value)
08c3a6
+        pseudo_member._name_ = None
08c3a6
+        pseudo_member._value_ = value
08c3a6
+        return pseudo_member
08c3a6
+
08c3a6
+    def __repr__(self):
08c3a6
+        name = self._name_
08c3a6
+        if name is not None:
08c3a6
+            # The names have prefixes like SHT_, implying their type.
08c3a6
+            return name
08c3a6
+        return '{}({})'.format(self.__class__.__name__, self._value_)
08c3a6
+
08c3a6
+    def __str__(self):
08c3a6
+        name = self._name_
08c3a6
+        if name is not None:
08c3a6
+            return name
08c3a6
+        return str(self._value_)
08c3a6
+
08c3a6
+class ElfClass(_OpenIntEnum):
08c3a6
+    """ELF word size.  Type of EI_CLASS values."""
08c3a6
+    ELFCLASSNONE = 0
08c3a6
+    ELFCLASS32 = 1
08c3a6
+    ELFCLASS64 = 2
08c3a6
+
08c3a6
+class ElfData(_OpenIntEnum):
08c3a6
+    """ELF endianess.  Type of EI_DATA values."""
08c3a6
+    ELFDATANONE = 0
08c3a6
+    ELFDATA2LSB = 1
08c3a6
+    ELFDATA2MSB = 2
08c3a6
+
08c3a6
+class Machine(_OpenIntEnum):
08c3a6
+    """ELF machine type.  Type of values in Ehdr.e_machine field."""
08c3a6
+    EM_NONE = 0
08c3a6
+    EM_M32 = 1
08c3a6
+    EM_SPARC = 2
08c3a6
+    EM_386 = 3
08c3a6
+    EM_68K = 4
08c3a6
+    EM_88K = 5
08c3a6
+    EM_IAMCU = 6
08c3a6
+    EM_860 = 7
08c3a6
+    EM_MIPS = 8
08c3a6
+    EM_S370 = 9
08c3a6
+    EM_MIPS_RS3_LE = 10
08c3a6
+    EM_PARISC = 15
08c3a6
+    EM_VPP500 = 17
08c3a6
+    EM_SPARC32PLUS = 18
08c3a6
+    EM_960 = 19
08c3a6
+    EM_PPC = 20
08c3a6
+    EM_PPC64 = 21
08c3a6
+    EM_S390 = 22
08c3a6
+    EM_SPU = 23
08c3a6
+    EM_V800 = 36
08c3a6
+    EM_FR20 = 37
08c3a6
+    EM_RH32 = 38
08c3a6
+    EM_RCE = 39
08c3a6
+    EM_ARM = 40
08c3a6
+    EM_FAKE_ALPHA = 41
08c3a6
+    EM_SH = 42
08c3a6
+    EM_SPARCV9 = 43
08c3a6
+    EM_TRICORE = 44
08c3a6
+    EM_ARC = 45
08c3a6
+    EM_H8_300 = 46
08c3a6
+    EM_H8_300H = 47
08c3a6
+    EM_H8S = 48
08c3a6
+    EM_H8_500 = 49
08c3a6
+    EM_IA_64 = 50
08c3a6
+    EM_MIPS_X = 51
08c3a6
+    EM_COLDFIRE = 52
08c3a6
+    EM_68HC12 = 53
08c3a6
+    EM_MMA = 54
08c3a6
+    EM_PCP = 55
08c3a6
+    EM_NCPU = 56
08c3a6
+    EM_NDR1 = 57
08c3a6
+    EM_STARCORE = 58
08c3a6
+    EM_ME16 = 59
08c3a6
+    EM_ST100 = 60
08c3a6
+    EM_TINYJ = 61
08c3a6
+    EM_X86_64 = 62
08c3a6
+    EM_PDSP = 63
08c3a6
+    EM_PDP10 = 64
08c3a6
+    EM_PDP11 = 65
08c3a6
+    EM_FX66 = 66
08c3a6
+    EM_ST9PLUS = 67
08c3a6
+    EM_ST7 = 68
08c3a6
+    EM_68HC16 = 69
08c3a6
+    EM_68HC11 = 70
08c3a6
+    EM_68HC08 = 71
08c3a6
+    EM_68HC05 = 72
08c3a6
+    EM_SVX = 73
08c3a6
+    EM_ST19 = 74
08c3a6
+    EM_VAX = 75
08c3a6
+    EM_CRIS = 76
08c3a6
+    EM_JAVELIN = 77
08c3a6
+    EM_FIREPATH = 78
08c3a6
+    EM_ZSP = 79
08c3a6
+    EM_MMIX = 80
08c3a6
+    EM_HUANY = 81
08c3a6
+    EM_PRISM = 82
08c3a6
+    EM_AVR = 83
08c3a6
+    EM_FR30 = 84
08c3a6
+    EM_D10V = 85
08c3a6
+    EM_D30V = 86
08c3a6
+    EM_V850 = 87
08c3a6
+    EM_M32R = 88
08c3a6
+    EM_MN10300 = 89
08c3a6
+    EM_MN10200 = 90
08c3a6
+    EM_PJ = 91
08c3a6
+    EM_OPENRISC = 92
08c3a6
+    EM_ARC_COMPACT = 93
08c3a6
+    EM_XTENSA = 94
08c3a6
+    EM_VIDEOCORE = 95
08c3a6
+    EM_TMM_GPP = 96
08c3a6
+    EM_NS32K = 97
08c3a6
+    EM_TPC = 98
08c3a6
+    EM_SNP1K = 99
08c3a6
+    EM_ST200 = 100
08c3a6
+    EM_IP2K = 101
08c3a6
+    EM_MAX = 102
08c3a6
+    EM_CR = 103
08c3a6
+    EM_F2MC16 = 104
08c3a6
+    EM_MSP430 = 105
08c3a6
+    EM_BLACKFIN = 106
08c3a6
+    EM_SE_C33 = 107
08c3a6
+    EM_SEP = 108
08c3a6
+    EM_ARCA = 109
08c3a6
+    EM_UNICORE = 110
08c3a6
+    EM_EXCESS = 111
08c3a6
+    EM_DXP = 112
08c3a6
+    EM_ALTERA_NIOS2 = 113
08c3a6
+    EM_CRX = 114
08c3a6
+    EM_XGATE = 115
08c3a6
+    EM_C166 = 116
08c3a6
+    EM_M16C = 117
08c3a6
+    EM_DSPIC30F = 118
08c3a6
+    EM_CE = 119
08c3a6
+    EM_M32C = 120
08c3a6
+    EM_TSK3000 = 131
08c3a6
+    EM_RS08 = 132
08c3a6
+    EM_SHARC = 133
08c3a6
+    EM_ECOG2 = 134
08c3a6
+    EM_SCORE7 = 135
08c3a6
+    EM_DSP24 = 136
08c3a6
+    EM_VIDEOCORE3 = 137
08c3a6
+    EM_LATTICEMICO32 = 138
08c3a6
+    EM_SE_C17 = 139
08c3a6
+    EM_TI_C6000 = 140
08c3a6
+    EM_TI_C2000 = 141
08c3a6
+    EM_TI_C5500 = 142
08c3a6
+    EM_TI_ARP32 = 143
08c3a6
+    EM_TI_PRU = 144
08c3a6
+    EM_MMDSP_PLUS = 160
08c3a6
+    EM_CYPRESS_M8C = 161
08c3a6
+    EM_R32C = 162
08c3a6
+    EM_TRIMEDIA = 163
08c3a6
+    EM_QDSP6 = 164
08c3a6
+    EM_8051 = 165
08c3a6
+    EM_STXP7X = 166
08c3a6
+    EM_NDS32 = 167
08c3a6
+    EM_ECOG1X = 168
08c3a6
+    EM_MAXQ30 = 169
08c3a6
+    EM_XIMO16 = 170
08c3a6
+    EM_MANIK = 171
08c3a6
+    EM_CRAYNV2 = 172
08c3a6
+    EM_RX = 173
08c3a6
+    EM_METAG = 174
08c3a6
+    EM_MCST_ELBRUS = 175
08c3a6
+    EM_ECOG16 = 176
08c3a6
+    EM_CR16 = 177
08c3a6
+    EM_ETPU = 178
08c3a6
+    EM_SLE9X = 179
08c3a6
+    EM_L10M = 180
08c3a6
+    EM_K10M = 181
08c3a6
+    EM_AARCH64 = 183
08c3a6
+    EM_AVR32 = 185
08c3a6
+    EM_STM8 = 186
08c3a6
+    EM_TILE64 = 187
08c3a6
+    EM_TILEPRO = 188
08c3a6
+    EM_MICROBLAZE = 189
08c3a6
+    EM_CUDA = 190
08c3a6
+    EM_TILEGX = 191
08c3a6
+    EM_CLOUDSHIELD = 192
08c3a6
+    EM_COREA_1ST = 193
08c3a6
+    EM_COREA_2ND = 194
08c3a6
+    EM_ARCV2 = 195
08c3a6
+    EM_OPEN8 = 196
08c3a6
+    EM_RL78 = 197
08c3a6
+    EM_VIDEOCORE5 = 198
08c3a6
+    EM_78KOR = 199
08c3a6
+    EM_56800EX = 200
08c3a6
+    EM_BA1 = 201
08c3a6
+    EM_BA2 = 202
08c3a6
+    EM_XCORE = 203
08c3a6
+    EM_MCHP_PIC = 204
08c3a6
+    EM_INTELGT = 205
08c3a6
+    EM_KM32 = 210
08c3a6
+    EM_KMX32 = 211
08c3a6
+    EM_EMX16 = 212
08c3a6
+    EM_EMX8 = 213
08c3a6
+    EM_KVARC = 214
08c3a6
+    EM_CDP = 215
08c3a6
+    EM_COGE = 216
08c3a6
+    EM_COOL = 217
08c3a6
+    EM_NORC = 218
08c3a6
+    EM_CSR_KALIMBA = 219
08c3a6
+    EM_Z80 = 220
08c3a6
+    EM_VISIUM = 221
08c3a6
+    EM_FT32 = 222
08c3a6
+    EM_MOXIE = 223
08c3a6
+    EM_AMDGPU = 224
08c3a6
+    EM_RISCV = 243
08c3a6
+    EM_BPF = 247
08c3a6
+    EM_CSKY = 252
08c3a6
+    EM_NUM = 253
08c3a6
+    EM_ALPHA = 0x9026
08c3a6
+
08c3a6
+class Et(_OpenIntEnum):
08c3a6
+    """ELF file type.  Type of ET_* values and the Ehdr.e_type field."""
08c3a6
+    ET_NONE = 0
08c3a6
+    ET_REL = 1
08c3a6
+    ET_EXEC = 2
08c3a6
+    ET_DYN = 3
08c3a6
+    ET_CORE = 4
08c3a6
+
08c3a6
+class Shn(_OpenIntEnum):
08c3a6
+    """ELF reserved section indices."""
08c3a6
+    SHN_UNDEF = 0
08c3a6
+    SHN_BEFORE = 0xff00
08c3a6
+    SHN_AFTER = 0xff01
08c3a6
+    SHN_ABS = 0xfff1
08c3a6
+    SHN_COMMON = 0xfff2
08c3a6
+    SHN_XINDEX = 0xffff
08c3a6
+
08c3a6
+class ShnMIPS(enum.Enum):
08c3a6
+    """Supplemental SHN_* constants for EM_MIPS."""
08c3a6
+    SHN_MIPS_ACOMMON = 0xff00
08c3a6
+    SHN_MIPS_TEXT = 0xff01
08c3a6
+    SHN_MIPS_DATA = 0xff02
08c3a6
+    SHN_MIPS_SCOMMON = 0xff03
08c3a6
+    SHN_MIPS_SUNDEFINED = 0xff04
08c3a6
+
08c3a6
+class ShnPARISC(enum.Enum):
08c3a6
+    """Supplemental SHN_* constants for EM_PARISC."""
08c3a6
+    SHN_PARISC_ANSI_COMMON = 0xff00
08c3a6
+    SHN_PARISC_HUGE_COMMON = 0xff01
08c3a6
+
08c3a6
+class Sht(_OpenIntEnum):
08c3a6
+    """ELF section types.  Type of SHT_* values."""
08c3a6
+    SHT_NULL = 0
08c3a6
+    SHT_PROGBITS = 1
08c3a6
+    SHT_SYMTAB = 2
08c3a6
+    SHT_STRTAB = 3
08c3a6
+    SHT_RELA = 4
08c3a6
+    SHT_HASH = 5
08c3a6
+    SHT_DYNAMIC = 6
08c3a6
+    SHT_NOTE = 7
08c3a6
+    SHT_NOBITS = 8
08c3a6
+    SHT_REL = 9
08c3a6
+    SHT_SHLIB = 10
08c3a6
+    SHT_DYNSYM = 11
08c3a6
+    SHT_INIT_ARRAY = 14
08c3a6
+    SHT_FINI_ARRAY = 15
08c3a6
+    SHT_PREINIT_ARRAY = 16
08c3a6
+    SHT_GROUP = 17
08c3a6
+    SHT_SYMTAB_SHNDX = 18
08c3a6
+    SHT_GNU_ATTRIBUTES = 0x6ffffff5
08c3a6
+    SHT_GNU_HASH = 0x6ffffff6
08c3a6
+    SHT_GNU_LIBLIST = 0x6ffffff7
08c3a6
+    SHT_CHECKSUM = 0x6ffffff8
08c3a6
+    SHT_SUNW_move = 0x6ffffffa
08c3a6
+    SHT_SUNW_COMDAT = 0x6ffffffb
08c3a6
+    SHT_SUNW_syminfo = 0x6ffffffc
08c3a6
+    SHT_GNU_verdef = 0x6ffffffd
08c3a6
+    SHT_GNU_verneed = 0x6ffffffe
08c3a6
+    SHT_GNU_versym = 0x6fffffff
08c3a6
+
08c3a6
+class ShtALPHA(enum.Enum):
08c3a6
+    """Supplemental SHT_* constants for EM_ALPHA."""
08c3a6
+    SHT_ALPHA_DEBUG = 0x70000001
08c3a6
+    SHT_ALPHA_REGINFO = 0x70000002
08c3a6
+
08c3a6
+class ShtARM(enum.Enum):
08c3a6
+    """Supplemental SHT_* constants for EM_ARM."""
08c3a6
+    SHT_ARM_EXIDX = 0x70000001
08c3a6
+    SHT_ARM_PREEMPTMAP = 0x70000002
08c3a6
+    SHT_ARM_ATTRIBUTES = 0x70000003
08c3a6
+
08c3a6
+class ShtCSKY(enum.Enum):
08c3a6
+    """Supplemental SHT_* constants for EM_CSKY."""
08c3a6
+    SHT_CSKY_ATTRIBUTES = 0x70000001
08c3a6
+
08c3a6
+class ShtIA_64(enum.Enum):
08c3a6
+    """Supplemental SHT_* constants for EM_IA_64."""
08c3a6
+    SHT_IA_64_EXT = 0x70000000
08c3a6
+    SHT_IA_64_UNWIND = 0x70000001
08c3a6
+
08c3a6
+class ShtMIPS(enum.Enum):
08c3a6
+    """Supplemental SHT_* constants for EM_MIPS."""
08c3a6
+    SHT_MIPS_LIBLIST = 0x70000000
08c3a6
+    SHT_MIPS_MSYM = 0x70000001
08c3a6
+    SHT_MIPS_CONFLICT = 0x70000002
08c3a6
+    SHT_MIPS_GPTAB = 0x70000003
08c3a6
+    SHT_MIPS_UCODE = 0x70000004
08c3a6
+    SHT_MIPS_DEBUG = 0x70000005
08c3a6
+    SHT_MIPS_REGINFO = 0x70000006
08c3a6
+    SHT_MIPS_PACKAGE = 0x70000007
08c3a6
+    SHT_MIPS_PACKSYM = 0x70000008
08c3a6
+    SHT_MIPS_RELD = 0x70000009
08c3a6
+    SHT_MIPS_IFACE = 0x7000000b
08c3a6
+    SHT_MIPS_CONTENT = 0x7000000c
08c3a6
+    SHT_MIPS_OPTIONS = 0x7000000d
08c3a6
+    SHT_MIPS_SHDR = 0x70000010
08c3a6
+    SHT_MIPS_FDESC = 0x70000011
08c3a6
+    SHT_MIPS_EXTSYM = 0x70000012
08c3a6
+    SHT_MIPS_DENSE = 0x70000013
08c3a6
+    SHT_MIPS_PDESC = 0x70000014
08c3a6
+    SHT_MIPS_LOCSYM = 0x70000015
08c3a6
+    SHT_MIPS_AUXSYM = 0x70000016
08c3a6
+    SHT_MIPS_OPTSYM = 0x70000017
08c3a6
+    SHT_MIPS_LOCSTR = 0x70000018
08c3a6
+    SHT_MIPS_LINE = 0x70000019
08c3a6
+    SHT_MIPS_RFDESC = 0x7000001a
08c3a6
+    SHT_MIPS_DELTASYM = 0x7000001b
08c3a6
+    SHT_MIPS_DELTAINST = 0x7000001c
08c3a6
+    SHT_MIPS_DELTACLASS = 0x7000001d
08c3a6
+    SHT_MIPS_DWARF = 0x7000001e
08c3a6
+    SHT_MIPS_DELTADECL = 0x7000001f
08c3a6
+    SHT_MIPS_SYMBOL_LIB = 0x70000020
08c3a6
+    SHT_MIPS_EVENTS = 0x70000021
08c3a6
+    SHT_MIPS_TRANSLATE = 0x70000022
08c3a6
+    SHT_MIPS_PIXIE = 0x70000023
08c3a6
+    SHT_MIPS_XLATE = 0x70000024
08c3a6
+    SHT_MIPS_XLATE_DEBUG = 0x70000025
08c3a6
+    SHT_MIPS_WHIRL = 0x70000026
08c3a6
+    SHT_MIPS_EH_REGION = 0x70000027
08c3a6
+    SHT_MIPS_XLATE_OLD = 0x70000028
08c3a6
+    SHT_MIPS_PDR_EXCEPTION = 0x70000029
08c3a6
+    SHT_MIPS_XHASH = 0x7000002b
08c3a6
+
08c3a6
+class ShtPARISC(enum.Enum):
08c3a6
+    """Supplemental SHT_* constants for EM_PARISC."""
08c3a6
+    SHT_PARISC_EXT = 0x70000000
08c3a6
+    SHT_PARISC_UNWIND = 0x70000001
08c3a6
+    SHT_PARISC_DOC = 0x70000002
08c3a6
+
08c3a6
+class Pf(enum.IntFlag):
08c3a6
+    """Program header flags.  Type of Phdr.p_flags values."""
08c3a6
+    PF_X = 1
08c3a6
+    PF_W = 2
08c3a6
+    PF_R = 4
08c3a6
+
08c3a6
+class PfARM(enum.IntFlag):
08c3a6
+    """Supplemental PF_* flags for EM_ARM."""
08c3a6
+    PF_ARM_SB = 0x10000000
08c3a6
+    PF_ARM_PI = 0x20000000
08c3a6
+    PF_ARM_ABS = 0x40000000
08c3a6
+
08c3a6
+class PfPARISC(enum.IntFlag):
08c3a6
+    """Supplemental PF_* flags for EM_PARISC."""
08c3a6
+    PF_HP_PAGE_SIZE = 0x00100000
08c3a6
+    PF_HP_FAR_SHARED = 0x00200000
08c3a6
+    PF_HP_NEAR_SHARED = 0x00400000
08c3a6
+    PF_HP_CODE = 0x01000000
08c3a6
+    PF_HP_MODIFY = 0x02000000
08c3a6
+    PF_HP_LAZYSWAP = 0x04000000
08c3a6
+    PF_HP_SBP = 0x08000000
08c3a6
+
08c3a6
+class PfIA_64(enum.IntFlag):
08c3a6
+    """Supplemental PF_* flags for EM_IA_64."""
08c3a6
+    PF_IA_64_NORECOV = 0x80000000
08c3a6
+
08c3a6
+class PfMIPS(enum.IntFlag):
08c3a6
+    """Supplemental PF_* flags for EM_MIPS."""
08c3a6
+    PF_MIPS_LOCAL = 0x10000000
08c3a6
+
08c3a6
+class Shf(enum.IntFlag):
08c3a6
+    """Section flags.  Type of Shdr.sh_type values."""
08c3a6
+    SHF_WRITE = 1 << 0
08c3a6
+    SHF_ALLOC = 1 << 1
08c3a6
+    SHF_EXECINSTR = 1 << 2
08c3a6
+    SHF_MERGE = 1 << 4
08c3a6
+    SHF_STRINGS = 1 << 5
08c3a6
+    SHF_INFO_LINK = 1 << 6
08c3a6
+    SHF_LINK_ORDER = 1 << 7
08c3a6
+    SHF_OS_NONCONFORMING = 256
08c3a6
+    SHF_GROUP = 1 << 9
08c3a6
+    SHF_TLS = 1 << 10
08c3a6
+    SHF_COMPRESSED = 1 << 11
08c3a6
+    SHF_GNU_RETAIN = 1 << 21
08c3a6
+    SHF_ORDERED = 1 << 30
08c3a6
+    SHF_EXCLUDE = 1 << 31
08c3a6
+
08c3a6
+class ShfALPHA(enum.IntFlag):
08c3a6
+    """Supplemental SHF_* constants for EM_ALPHA."""
08c3a6
+    SHF_ALPHA_GPREL = 0x10000000
08c3a6
+
08c3a6
+class ShfARM(enum.IntFlag):
08c3a6
+    """Supplemental SHF_* constants for EM_ARM."""
08c3a6
+    SHF_ARM_ENTRYSECT = 0x10000000
08c3a6
+    SHF_ARM_COMDEF = 0x80000000
08c3a6
+
08c3a6
+class ShfIA_64(enum.IntFlag):
08c3a6
+    """Supplemental SHF_* constants for EM_IA_64."""
08c3a6
+    SHF_IA_64_SHORT  = 0x10000000
08c3a6
+    SHF_IA_64_NORECOV = 0x20000000
08c3a6
+
08c3a6
+class ShfMIPS(enum.IntFlag):
08c3a6
+    """Supplemental SHF_* constants for EM_MIPS."""
08c3a6
+    SHF_MIPS_GPREL = 0x10000000
08c3a6
+    SHF_MIPS_MERGE = 0x20000000
08c3a6
+    SHF_MIPS_ADDR = 0x40000000
08c3a6
+    SHF_MIPS_STRINGS = 0x80000000
08c3a6
+    SHF_MIPS_NOSTRIP = 0x08000000
08c3a6
+    SHF_MIPS_LOCAL = 0x04000000
08c3a6
+    SHF_MIPS_NAMES = 0x02000000
08c3a6
+    SHF_MIPS_NODUPE = 0x01000000
08c3a6
+
08c3a6
+class ShfPARISC(enum.IntFlag):
08c3a6
+    """Supplemental SHF_* constants for EM_PARISC."""
08c3a6
+    SHF_PARISC_SHORT = 0x20000000
08c3a6
+    SHF_PARISC_HUGE = 0x40000000
08c3a6
+    SHF_PARISC_SBP = 0x80000000
08c3a6
+
08c3a6
+class Stb(_OpenIntEnum):
08c3a6
+    """ELF symbol binding type."""
08c3a6
+    STB_LOCAL = 0
08c3a6
+    STB_GLOBAL = 1
08c3a6
+    STB_WEAK = 2
08c3a6
+    STB_GNU_UNIQUE = 10
08c3a6
+    STB_MIPS_SPLIT_COMMON = 13
08c3a6
+
08c3a6
+class Stt(_OpenIntEnum):
08c3a6
+    """ELF symbol type."""
08c3a6
+    STT_NOTYPE = 0
08c3a6
+    STT_OBJECT = 1
08c3a6
+    STT_FUNC = 2
08c3a6
+    STT_SECTION = 3
08c3a6
+    STT_FILE = 4
08c3a6
+    STT_COMMON = 5
08c3a6
+    STT_TLS = 6
08c3a6
+    STT_GNU_IFUNC = 10
08c3a6
+
08c3a6
+class SttARM(enum.Enum):
08c3a6
+    """Supplemental STT_* constants for EM_ARM."""
08c3a6
+    STT_ARM_TFUNC = 13
08c3a6
+    STT_ARM_16BIT = 15
08c3a6
+
08c3a6
+class SttPARISC(enum.Enum):
08c3a6
+    """Supplemental STT_* constants for EM_PARISC."""
08c3a6
+    STT_HP_OPAQUE = 11
08c3a6
+    STT_HP_STUB = 12
08c3a6
+    STT_PARISC_MILLICODE = 13
08c3a6
+
08c3a6
+class SttSPARC(enum.Enum):
08c3a6
+    """Supplemental STT_* constants for EM_SPARC."""
08c3a6
+    STT_SPARC_REGISTER = 13
08c3a6
+
08c3a6
+class SttX86_64(enum.Enum):
08c3a6
+    """Supplemental STT_* constants for EM_X86_64."""
08c3a6
+    SHT_X86_64_UNWIND = 0x70000001
08c3a6
+
08c3a6
+class Pt(_OpenIntEnum):
08c3a6
+    """ELF program header types.  Type of Phdr.p_type."""
08c3a6
+    PT_NULL = 0
08c3a6
+    PT_LOAD = 1
08c3a6
+    PT_DYNAMIC = 2
08c3a6
+    PT_INTERP = 3
08c3a6
+    PT_NOTE = 4
08c3a6
+    PT_SHLIB = 5
08c3a6
+    PT_PHDR = 6
08c3a6
+    PT_TLS = 7
08c3a6
+    PT_NUM = 8
08c3a6
+    PT_GNU_EH_FRAME = 0x6474e550
08c3a6
+    PT_GNU_STACK = 0x6474e551
08c3a6
+    PT_GNU_RELRO = 0x6474e552
08c3a6
+    PT_GNU_PROPERTY = 0x6474e553
08c3a6
+    PT_SUNWBSS = 0x6ffffffa
08c3a6
+    PT_SUNWSTACK = 0x6ffffffb
08c3a6
+
08c3a6
+class PtARM(enum.Enum):
08c3a6
+    """Supplemental PT_* constants for EM_ARM."""
08c3a6
+    PT_ARM_EXIDX = 0x70000001
08c3a6
+
08c3a6
+class PtIA_64(enum.Enum):
08c3a6
+    """Supplemental PT_* constants for EM_IA_64."""
08c3a6
+    PT_IA_64_HP_OPT_ANOT = 0x60000012
08c3a6
+    PT_IA_64_HP_HSL_ANOT = 0x60000013
08c3a6
+    PT_IA_64_HP_STACK = 0x60000014
08c3a6
+    PT_IA_64_ARCHEXT = 0x70000000
08c3a6
+    PT_IA_64_UNWIND = 0x70000001
08c3a6
+
08c3a6
+class PtMIPS(enum.Enum):
08c3a6
+    """Supplemental PT_* constants for EM_MIPS."""
08c3a6
+    PT_MIPS_REGINFO = 0x70000000
08c3a6
+    PT_MIPS_RTPROC = 0x70000001
08c3a6
+    PT_MIPS_OPTIONS = 0x70000002
08c3a6
+    PT_MIPS_ABIFLAGS = 0x70000003
08c3a6
+
08c3a6
+class PtPARISC(enum.Enum):
08c3a6
+    """Supplemental PT_* constants for EM_PARISC."""
08c3a6
+    PT_HP_TLS = 0x60000000
08c3a6
+    PT_HP_CORE_NONE = 0x60000001
08c3a6
+    PT_HP_CORE_VERSION = 0x60000002
08c3a6
+    PT_HP_CORE_KERNEL = 0x60000003
08c3a6
+    PT_HP_CORE_COMM = 0x60000004
08c3a6
+    PT_HP_CORE_PROC = 0x60000005
08c3a6
+    PT_HP_CORE_LOADABLE = 0x60000006
08c3a6
+    PT_HP_CORE_STACK = 0x60000007
08c3a6
+    PT_HP_CORE_SHM = 0x60000008
08c3a6
+    PT_HP_CORE_MMF = 0x60000009
08c3a6
+    PT_HP_PARALLEL = 0x60000010
08c3a6
+    PT_HP_FASTBIND = 0x60000011
08c3a6
+    PT_HP_OPT_ANNOT = 0x60000012
08c3a6
+    PT_HP_HSL_ANNOT = 0x60000013
08c3a6
+    PT_HP_STACK = 0x60000014
08c3a6
+    PT_PARISC_ARCHEXT = 0x70000000
08c3a6
+    PT_PARISC_UNWIND = 0x70000001
08c3a6
+
08c3a6
+class Dt(_OpenIntEnum):
08c3a6
+    """ELF dynamic segment tags.  Type of Dyn.d_val."""
08c3a6
+    DT_NULL = 0
08c3a6
+    DT_NEEDED = 1
08c3a6
+    DT_PLTRELSZ = 2
08c3a6
+    DT_PLTGOT = 3
08c3a6
+    DT_HASH = 4
08c3a6
+    DT_STRTAB = 5
08c3a6
+    DT_SYMTAB = 6
08c3a6
+    DT_RELA = 7
08c3a6
+    DT_RELASZ = 8
08c3a6
+    DT_RELAENT = 9
08c3a6
+    DT_STRSZ = 10
08c3a6
+    DT_SYMENT = 11
08c3a6
+    DT_INIT = 12
08c3a6
+    DT_FINI = 13
08c3a6
+    DT_SONAME = 14
08c3a6
+    DT_RPATH = 15
08c3a6
+    DT_SYMBOLIC = 16
08c3a6
+    DT_REL = 17
08c3a6
+    DT_RELSZ = 18
08c3a6
+    DT_RELENT = 19
08c3a6
+    DT_PLTREL = 20
08c3a6
+    DT_DEBUG = 21
08c3a6
+    DT_TEXTREL = 22
08c3a6
+    DT_JMPREL = 23
08c3a6
+    DT_BIND_NOW = 24
08c3a6
+    DT_INIT_ARRAY = 25
08c3a6
+    DT_FINI_ARRAY = 26
08c3a6
+    DT_INIT_ARRAYSZ = 27
08c3a6
+    DT_FINI_ARRAYSZ = 28
08c3a6
+    DT_RUNPATH = 29
08c3a6
+    DT_FLAGS = 30
08c3a6
+    DT_PREINIT_ARRAY = 32
08c3a6
+    DT_PREINIT_ARRAYSZ = 33
08c3a6
+    DT_SYMTAB_SHNDX = 34
08c3a6
+    DT_GNU_PRELINKED = 0x6ffffdf5
08c3a6
+    DT_GNU_CONFLICTSZ = 0x6ffffdf6
08c3a6
+    DT_GNU_LIBLISTSZ = 0x6ffffdf7
08c3a6
+    DT_CHECKSUM = 0x6ffffdf8
08c3a6
+    DT_PLTPADSZ = 0x6ffffdf9
08c3a6
+    DT_MOVEENT = 0x6ffffdfa
08c3a6
+    DT_MOVESZ = 0x6ffffdfb
08c3a6
+    DT_FEATURE_1 = 0x6ffffdfc
08c3a6
+    DT_POSFLAG_1 = 0x6ffffdfd
08c3a6
+    DT_SYMINSZ = 0x6ffffdfe
08c3a6
+    DT_SYMINENT = 0x6ffffdff
08c3a6
+    DT_GNU_HASH = 0x6ffffef5
08c3a6
+    DT_TLSDESC_PLT = 0x6ffffef6
08c3a6
+    DT_TLSDESC_GOT = 0x6ffffef7
08c3a6
+    DT_GNU_CONFLICT = 0x6ffffef8
08c3a6
+    DT_GNU_LIBLIST = 0x6ffffef9
08c3a6
+    DT_CONFIG = 0x6ffffefa
08c3a6
+    DT_DEPAUDIT = 0x6ffffefb
08c3a6
+    DT_AUDIT = 0x6ffffefc
08c3a6
+    DT_PLTPAD = 0x6ffffefd
08c3a6
+    DT_MOVETAB = 0x6ffffefe
08c3a6
+    DT_SYMINFO = 0x6ffffeff
08c3a6
+    DT_VERSYM = 0x6ffffff0
08c3a6
+    DT_RELACOUNT = 0x6ffffff9
08c3a6
+    DT_RELCOUNT = 0x6ffffffa
08c3a6
+    DT_FLAGS_1 = 0x6ffffffb
08c3a6
+    DT_VERDEF = 0x6ffffffc
08c3a6
+    DT_VERDEFNUM = 0x6ffffffd
08c3a6
+    DT_VERNEED = 0x6ffffffe
08c3a6
+    DT_VERNEEDNUM = 0x6fffffff
08c3a6
+    DT_AUXILIARY = 0x7ffffffd
08c3a6
+    DT_FILTER = 0x7fffffff
08c3a6
+
08c3a6
+class DtAARCH64(enum.Enum):
08c3a6
+    """Supplemental DT_* constants for EM_AARCH64."""
08c3a6
+    DT_AARCH64_BTI_PLT = 0x70000001
08c3a6
+    DT_AARCH64_PAC_PLT = 0x70000003
08c3a6
+    DT_AARCH64_VARIANT_PCS = 0x70000005
08c3a6
+
08c3a6
+class DtALPHA(enum.Enum):
08c3a6
+    """Supplemental DT_* constants for EM_ALPHA."""
08c3a6
+    DT_ALPHA_PLTRO = 0x70000000
08c3a6
+
08c3a6
+class DtALTERA_NIOS2(enum.Enum):
08c3a6
+    """Supplemental DT_* constants for EM_ALTERA_NIOS2."""
08c3a6
+    DT_NIOS2_GP = 0x70000002
08c3a6
+
08c3a6
+class DtIA_64(enum.Enum):
08c3a6
+    """Supplemental DT_* constants for EM_IA_64."""
08c3a6
+    DT_IA_64_PLT_RESERVE = 0x70000000
08c3a6
+
08c3a6
+class DtMIPS(enum.Enum):
08c3a6
+    """Supplemental DT_* constants for EM_MIPS."""
08c3a6
+    DT_MIPS_RLD_VERSION = 0x70000001
08c3a6
+    DT_MIPS_TIME_STAMP = 0x70000002
08c3a6
+    DT_MIPS_ICHECKSUM = 0x70000003
08c3a6
+    DT_MIPS_IVERSION = 0x70000004
08c3a6
+    DT_MIPS_FLAGS = 0x70000005
08c3a6
+    DT_MIPS_BASE_ADDRESS = 0x70000006
08c3a6
+    DT_MIPS_MSYM = 0x70000007
08c3a6
+    DT_MIPS_CONFLICT = 0x70000008
08c3a6
+    DT_MIPS_LIBLIST = 0x70000009
08c3a6
+    DT_MIPS_LOCAL_GOTNO = 0x7000000a
08c3a6
+    DT_MIPS_CONFLICTNO = 0x7000000b
08c3a6
+    DT_MIPS_LIBLISTNO = 0x70000010
08c3a6
+    DT_MIPS_SYMTABNO = 0x70000011
08c3a6
+    DT_MIPS_UNREFEXTNO = 0x70000012
08c3a6
+    DT_MIPS_GOTSYM = 0x70000013
08c3a6
+    DT_MIPS_HIPAGENO = 0x70000014
08c3a6
+    DT_MIPS_RLD_MAP = 0x70000016
08c3a6
+    DT_MIPS_DELTA_CLASS = 0x70000017
08c3a6
+    DT_MIPS_DELTA_CLASS_NO = 0x70000018
08c3a6
+    DT_MIPS_DELTA_INSTANCE = 0x70000019
08c3a6
+    DT_MIPS_DELTA_INSTANCE_NO = 0x7000001a
08c3a6
+    DT_MIPS_DELTA_RELOC = 0x7000001b
08c3a6
+    DT_MIPS_DELTA_RELOC_NO = 0x7000001c
08c3a6
+    DT_MIPS_DELTA_SYM = 0x7000001d
08c3a6
+    DT_MIPS_DELTA_SYM_NO = 0x7000001e
08c3a6
+    DT_MIPS_DELTA_CLASSSYM = 0x70000020
08c3a6
+    DT_MIPS_DELTA_CLASSSYM_NO = 0x70000021
08c3a6
+    DT_MIPS_CXX_FLAGS = 0x70000022
08c3a6
+    DT_MIPS_PIXIE_INIT = 0x70000023
08c3a6
+    DT_MIPS_SYMBOL_LIB = 0x70000024
08c3a6
+    DT_MIPS_LOCALPAGE_GOTIDX = 0x70000025
08c3a6
+    DT_MIPS_LOCAL_GOTIDX = 0x70000026
08c3a6
+    DT_MIPS_HIDDEN_GOTIDX = 0x70000027
08c3a6
+    DT_MIPS_PROTECTED_GOTIDX = 0x70000028
08c3a6
+    DT_MIPS_OPTIONS = 0x70000029
08c3a6
+    DT_MIPS_INTERFACE = 0x7000002a
08c3a6
+    DT_MIPS_DYNSTR_ALIGN = 0x7000002b
08c3a6
+    DT_MIPS_INTERFACE_SIZE = 0x7000002c
08c3a6
+    DT_MIPS_RLD_TEXT_RESOLVE_ADDR = 0x7000002d
08c3a6
+    DT_MIPS_PERF_SUFFIX = 0x7000002e
08c3a6
+    DT_MIPS_COMPACT_SIZE = 0x7000002f
08c3a6
+    DT_MIPS_GP_VALUE = 0x70000030
08c3a6
+    DT_MIPS_AUX_DYNAMIC = 0x70000031
08c3a6
+    DT_MIPS_PLTGOT = 0x70000032
08c3a6
+    DT_MIPS_RWPLT = 0x70000034
08c3a6
+    DT_MIPS_RLD_MAP_REL = 0x70000035
08c3a6
+    DT_MIPS_XHASH = 0x70000036
08c3a6
+
08c3a6
+class DtPPC(enum.Enum):
08c3a6
+    """Supplemental DT_* constants for EM_PPC."""
08c3a6
+    DT_PPC_GOT = 0x70000000
08c3a6
+    DT_PPC_OPT = 0x70000001
08c3a6
+
08c3a6
+class DtPPC64(enum.Enum):
08c3a6
+    """Supplemental DT_* constants for EM_PPC64."""
08c3a6
+    DT_PPC64_GLINK = 0x70000000
08c3a6
+    DT_PPC64_OPD = 0x70000001
08c3a6
+    DT_PPC64_OPDSZ = 0x70000002
08c3a6
+    DT_PPC64_OPT = 0x70000003
08c3a6
+
08c3a6
+class DtSPARC(enum.Enum):
08c3a6
+    """Supplemental DT_* constants for EM_SPARC."""
08c3a6
+    DT_SPARC_REGISTER = 0x70000001
08c3a6
+
08c3a6
+class StInfo:
08c3a6
+    """ELF symbol binding and type.  Type of the Sym.st_info field."""
08c3a6
+    def __init__(self, arg0, arg1=None):
08c3a6
+        if isinstance(arg0, int) and arg1 is None:
08c3a6
+            self.bind = Stb(arg0 >> 4)
08c3a6
+            self.type = Stt(arg0 & 15)
08c3a6
+        else:
08c3a6
+            self.bind = Stb(arg0)
08c3a6
+            self.type = Stt(arg1)
08c3a6
+
08c3a6
+    def value(self):
08c3a6
+        """Returns the raw value for the bind/type combination."""
08c3a6
+        return (self.bind.value() << 4) | (self.type.value())
08c3a6
+
08c3a6
+# Type in an ELF file.  Used for deserialization.
08c3a6
+_Layout = collections.namedtuple('_Layout', 'unpack size')
08c3a6
+
08c3a6
+def _define_layouts(baseclass: type, layout32: str, layout64: str,
08c3a6
+                    types=None, fields32=None):
08c3a6
+    """Assign variants dict to baseclass.
08c3a6
+
08c3a6
+    The variants dict is indexed by (ElfClass, ElfData) pairs, and its
08c3a6
+    values are _Layout instances.
08c3a6
+
08c3a6
+    """
08c3a6
+    struct32 = struct.Struct(layout32)
08c3a6
+    struct64 = struct.Struct(layout64)
08c3a6
+
08c3a6
+    # Check that the struct formats yield the right number of components.
08c3a6
+    for s in (struct32, struct64):
08c3a6
+        example = s.unpack(b' ' * s.size)
08c3a6
+        if len(example) != len(baseclass._fields):
08c3a6
+            raise ValueError('{!r} yields wrong field count: {} != {}'.format(
08c3a6
+                s.format, len(example),  len(baseclass._fields)))
08c3a6
+
08c3a6
+    # Check that field names in types are correct.
08c3a6
+    if types is None:
08c3a6
+        types = ()
08c3a6
+    for n in types:
08c3a6
+        if n not in baseclass._fields:
08c3a6
+            raise ValueError('{} does not have field {!r}'.format(
08c3a6
+                baseclass.__name__, n))
08c3a6
+
08c3a6
+    if fields32 is not None \
08c3a6
+       and set(fields32) != set(baseclass._fields):
08c3a6
+        raise ValueError('{!r} is not a permutation of the fields {!r}'.format(
08c3a6
+            fields32, baseclass._fields))
08c3a6
+
08c3a6
+    def unique_name(name, used_names = (set((baseclass.__name__,))
08c3a6
+                                        | set(baseclass._fields)
08c3a6
+                                        | {n.__name__
08c3a6
+                                           for n in (types or {}).values()})):
08c3a6
+        """Find a name that is not used for a class or field name."""
08c3a6
+        candidate = name
08c3a6
+        n = 0
08c3a6
+        while candidate in used_names:
08c3a6
+            n += 1
08c3a6
+            candidate = '{}{}'.format(name, n)
08c3a6
+        used_names.add(candidate)
08c3a6
+        return candidate
08c3a6
+
08c3a6
+    blob_name = unique_name('blob')
08c3a6
+    struct_unpack_name = unique_name('struct_unpack')
08c3a6
+    comps_name = unique_name('comps')
08c3a6
+
08c3a6
+    layouts = {}
08c3a6
+    for (bits, elfclass, layout, fields) in (
08c3a6
+            (32, ElfClass.ELFCLASS32, layout32, fields32),
08c3a6
+            (64, ElfClass.ELFCLASS64, layout64, None),
08c3a6
+    ):
08c3a6
+        for (elfdata, structprefix, funcsuffix) in (
08c3a6
+                (ElfData.ELFDATA2LSB, '<', 'LE'),
08c3a6
+                (ElfData.ELFDATA2MSB, '>', 'BE'),
08c3a6
+        ):
08c3a6
+            env = {
08c3a6
+                baseclass.__name__: baseclass,
08c3a6
+                struct_unpack_name: struct.unpack,
08c3a6
+            }
08c3a6
+
08c3a6
+            # Add the type converters.
08c3a6
+            if types:
08c3a6
+                for cls in types.values():
08c3a6
+                    env[cls.__name__] = cls
08c3a6
+
08c3a6
+            funcname = ''.join(
08c3a6
+                ('unpack_', baseclass.__name__, str(bits), funcsuffix))
08c3a6
+
08c3a6
+            code = '''
08c3a6
+def {funcname}({blob_name}):
08c3a6
+'''.format(funcname=funcname, blob_name=blob_name)
08c3a6
+
08c3a6
+            indent = ' ' * 4
08c3a6
+            unpack_call = '{}({!r}, {})'.format(
08c3a6
+                struct_unpack_name, structprefix + layout, blob_name)
08c3a6
+            field_names = ', '.join(baseclass._fields)
08c3a6
+            if types is None and fields is None:
08c3a6
+                code += '{}return {}({})\n'.format(
08c3a6
+                    indent, baseclass.__name__, unpack_call)
08c3a6
+            else:
08c3a6
+                # Destructuring tuple assignment.
08c3a6
+                if fields is None:
08c3a6
+                    code += '{}{} = {}\n'.format(
08c3a6
+                        indent, field_names, unpack_call)
08c3a6
+                else:
08c3a6
+                    # Use custom field order.
08c3a6
+                    code += '{}{} = {}\n'.format(
08c3a6
+                        indent, ', '.join(fields), unpack_call)
08c3a6
+
08c3a6
+                # Perform the type conversions.
08c3a6
+                for n in baseclass._fields:
08c3a6
+                    if n in types:
08c3a6
+                        code += '{}{} = {}({})\n'.format(
08c3a6
+                            indent, n, types[n].__name__, n)
08c3a6
+                # Create the named tuple.
08c3a6
+                code += '{}return {}({})\n'.format(
08c3a6
+                    indent, baseclass.__name__, field_names)
08c3a6
+
08c3a6
+            exec(code, env)
08c3a6
+            layouts[(elfclass, elfdata)] = _Layout(
08c3a6
+                env[funcname], struct.calcsize(layout))
08c3a6
+    baseclass.layouts = layouts
08c3a6
+
08c3a6
+
08c3a6
+# Corresponds to EI_* indices into Elf*_Ehdr.e_indent.
08c3a6
+class Ident(collections.namedtuple('Ident',
08c3a6
+    'ei_mag ei_class ei_data ei_version ei_osabi ei_abiversion ei_pad')):
08c3a6
+
08c3a6
+    def __new__(cls, *args):
08c3a6
+        """Construct an object from a blob or its constituent fields."""
08c3a6
+        if len(args) == 1:
08c3a6
+            return cls.unpack(args[0])
08c3a6
+        return cls.__base__.__new__(cls, *args)
08c3a6
+
08c3a6
+    @staticmethod
08c3a6
+    def unpack(blob: memoryview) -> 'Ident':
08c3a6
+        """Parse raws data into a tuple."""
08c3a6
+        ei_mag, ei_class, ei_data, ei_version, ei_osabi, ei_abiversion, \
08c3a6
+            ei_pad = struct.unpack('4s5B7s', blob)
08c3a6
+        return Ident(ei_mag, ElfClass(ei_class), ElfData(ei_data),
08c3a6
+                     ei_version, ei_osabi, ei_abiversion, ei_pad)
08c3a6
+    size = 16
08c3a6
+
08c3a6
+# Corresponds to Elf32_Ehdr and Elf64_Ehdr.
08c3a6
+Ehdr = collections.namedtuple('Ehdr',
08c3a6
+   'e_ident e_type e_machine e_version e_entry e_phoff e_shoff e_flags'
08c3a6
+    + ' e_ehsize e_phentsize e_phnum e_shentsize e_shnum e_shstrndx')
08c3a6
+_define_layouts(Ehdr,
08c3a6
+                layout32='16s2H5I6H',
08c3a6
+                layout64='16s2HI3QI6H',
08c3a6
+                types=dict(e_ident=Ident,
08c3a6
+                           e_machine=Machine,
08c3a6
+                           e_type=Et,
08c3a6
+                           e_shstrndx=Shn))
08c3a6
+
08c3a6
+# Corresponds to Elf32_Phdr and Elf64_Pdhr.  Order follows the latter.
08c3a6
+Phdr = collections.namedtuple('Phdr',
08c3a6
+    'p_type p_flags p_offset p_vaddr p_paddr p_filesz p_memsz p_align')
08c3a6
+_define_layouts(Phdr,
08c3a6
+                layout32='8I',
08c3a6
+                fields32=('p_type', 'p_offset', 'p_vaddr', 'p_paddr',
08c3a6
+                          'p_filesz', 'p_memsz', 'p_flags', 'p_align'),
08c3a6
+                layout64='2I6Q',
08c3a6
+            types=dict(p_type=Pt, p_flags=Pf))
08c3a6
+
08c3a6
+
08c3a6
+# Corresponds to Elf32_Shdr and Elf64_Shdr.
08c3a6
+class Shdr(collections.namedtuple('Shdr',
08c3a6
+    'sh_name sh_type sh_flags sh_addr sh_offset sh_size sh_link sh_info'
08c3a6
+    + ' sh_addralign sh_entsize')):
08c3a6
+    def resolve(self, strtab: 'StringTable') -> 'Shdr':
08c3a6
+        """Resolve sh_name using a string table."""
08c3a6
+        return self.__class__(strtab.get(self[0]), *self[1:])
08c3a6
+_define_layouts(Shdr,
08c3a6
+                layout32='10I',
08c3a6
+                layout64='2I4Q2I2Q',
08c3a6
+                types=dict(sh_type=Sht,
08c3a6
+                           sh_flags=Shf,
08c3a6
+                           sh_link=Shn))
08c3a6
+
08c3a6
+# Corresponds to Elf32_Dyn and Elf64_Dyn.  The nesting through the
08c3a6
+# d_un union is skipped, and d_ptr is missing (its representation in
08c3a6
+# Python would be identical to d_val).
08c3a6
+Dyn = collections.namedtuple('Dyn', 'd_tag d_val')
08c3a6
+_define_layouts(Dyn,
08c3a6
+                layout32='2i',
08c3a6
+                layout64='2q',
08c3a6
+                types=dict(d_tag=Dt))
08c3a6
+
08c3a6
+# Corresponds to Elf32_Sym and Elf64_Sym.
08c3a6
+class Sym(collections.namedtuple('Sym',
08c3a6
+    'st_name st_info st_other st_shndx st_value st_size')):
08c3a6
+    def resolve(self, strtab: 'StringTable') -> 'Sym':
08c3a6
+        """Resolve st_name using a string table."""
08c3a6
+        return self.__class__(strtab.get(self[0]), *self[1:])
08c3a6
+_define_layouts(Sym,
08c3a6
+                layout32='3I2BH',
08c3a6
+                layout64='I2BH2Q',
08c3a6
+                fields32=('st_name', 'st_value', 'st_size', 'st_info',
08c3a6
+                          'st_other', 'st_shndx'),
08c3a6
+                types=dict(st_shndx=Shn,
08c3a6
+                           st_info=StInfo))
08c3a6
+
08c3a6
+# Corresponds to Elf32_Rel and Elf64_Rel.
08c3a6
+Rel = collections.namedtuple('Rel', 'r_offset r_info')
08c3a6
+_define_layouts(Rel,
08c3a6
+                layout32='2I',
08c3a6
+                layout64='2Q')
08c3a6
+
08c3a6
+# Corresponds to Elf32_Rel and Elf64_Rel.
08c3a6
+Rela = collections.namedtuple('Rela', 'r_offset r_info r_addend')
08c3a6
+_define_layouts(Rela,
08c3a6
+                layout32='3I',
08c3a6
+                layout64='3Q')
08c3a6
+
08c3a6
+class StringTable:
08c3a6
+    """ELF string table."""
08c3a6
+    def __init__(self, blob):
08c3a6
+        """Create a new string table backed by the data in the blob.
08c3a6
+
08c3a6
+        blob: a memoryview-like object
08c3a6
+
08c3a6
+        """
08c3a6
+        self.blob = blob
08c3a6
+
08c3a6
+    def get(self, index) -> bytes:
08c3a6
+        """Returns the null-terminated byte string at the index."""
08c3a6
+        blob = self.blob
08c3a6
+        endindex = index
08c3a6
+        while True:
08c3a6
+            if blob[endindex] == 0:
08c3a6
+                return bytes(blob[index:endindex])
08c3a6
+            endindex += 1
08c3a6
+
08c3a6
+class Image:
08c3a6
+    """ELF image parser."""
08c3a6
+    def __init__(self, image):
08c3a6
+        """Create an ELF image from binary image data.
08c3a6
+
08c3a6
+        image: a memoryview-like object that supports efficient range
08c3a6
+        subscripting.
08c3a6
+
08c3a6
+        """
08c3a6
+        self.image = image
08c3a6
+        ident = self.read(Ident, 0)
08c3a6
+        classdata = (ident.ei_class, ident.ei_data)
08c3a6
+        # Set self.Ehdr etc. to the subtypes with the right parsers.
08c3a6
+        for typ in (Ehdr, Phdr, Shdr, Dyn, Sym, Rel, Rela):
08c3a6
+            setattr(self, typ.__name__, typ.layouts.get(classdata, None))
08c3a6
+
08c3a6
+        if self.Ehdr is not None:
08c3a6
+            self.ehdr = self.read(self.Ehdr, 0)
08c3a6
+            self._shdr_num = self._compute_shdr_num()
08c3a6
+        else:
08c3a6
+            self.ehdr = None
08c3a6
+            self._shdr_num = 0
08c3a6
+
08c3a6
+        self._section = {}
08c3a6
+        self._stringtab = {}
08c3a6
+
08c3a6
+        if self._shdr_num > 0:
08c3a6
+            self._shdr_strtab = self._find_shdr_strtab()
08c3a6
+        else:
08c3a6
+            self._shdr_strtab = None
08c3a6
+
08c3a6
+    @staticmethod
08c3a6
+    def readfile(path: str) -> 'Image':
08c3a6
+        """Reads the ELF file at the specified path."""
08c3a6
+        with open(path, 'rb') as inp:
08c3a6
+            return Image(memoryview(inp.read()))
08c3a6
+
08c3a6
+    def _compute_shdr_num(self) -> int:
08c3a6
+        """Computes the actual number of section headers."""
08c3a6
+        shnum = self.ehdr.e_shnum
08c3a6
+        if shnum == 0:
08c3a6
+            if self.ehdr.e_shoff == 0 or self.ehdr.e_shentsize == 0:
08c3a6
+                # No section headers.
08c3a6
+                return 0
08c3a6
+            # Otherwise the extension mechanism is used (which may be
08c3a6
+            # needed because e_shnum is just 16 bits).
08c3a6
+            return self.read(self.Shdr, self.ehdr.e_shoff).sh_size
08c3a6
+        return shnum
08c3a6
+
08c3a6
+    def _find_shdr_strtab(self) -> StringTable:
08c3a6
+        """Finds the section header string table (maybe via extensions)."""
08c3a6
+        shstrndx = self.ehdr.e_shstrndx
08c3a6
+        if shstrndx == Shn.SHN_XINDEX:
08c3a6
+            shstrndx = self.read(self.Shdr, self.ehdr.e_shoff).sh_link
08c3a6
+        return self._find_stringtab(shstrndx)
08c3a6
+
08c3a6
+    def read(self, typ: type, offset:int ):
08c3a6
+        """Reads an object at a specific offset.
08c3a6
+
08c3a6
+        The type must have been enhanced using _define_variants.
08c3a6
+
08c3a6
+        """
08c3a6
+        return typ.unpack(self.image[offset: offset + typ.size])
08c3a6
+
08c3a6
+    def phdrs(self) -> Phdr:
08c3a6
+        """Generator iterating over the program headers."""
08c3a6
+        if self.ehdr is None:
08c3a6
+            return
08c3a6
+        size = self.ehdr.e_phentsize
08c3a6
+        if size != self.Phdr.size:
08c3a6
+            raise ValueError('Unexpected Phdr size in ELF header: {} != {}'
08c3a6
+                             .format(size, self.Phdr.size))
08c3a6
+
08c3a6
+        offset = self.ehdr.e_phoff
08c3a6
+        for _ in range(self.ehdr.e_phnum):
08c3a6
+            yield self.read(self.Phdr, offset)
08c3a6
+            offset += size
08c3a6
+
08c3a6
+    def shdrs(self, resolve: bool=True) -> Shdr:
08c3a6
+        """Generator iterating over the section headers.
08c3a6
+
08c3a6
+        If resolve, section names are automatically translated
08c3a6
+        using the section header string table.
08c3a6
+
08c3a6
+        """
08c3a6
+        if self._shdr_num == 0:
08c3a6
+            return
08c3a6
+
08c3a6
+        size = self.ehdr.e_shentsize
08c3a6
+        if size != self.Shdr.size:
08c3a6
+            raise ValueError('Unexpected Shdr size in ELF header: {} != {}'
08c3a6
+                             .format(size, self.Shdr.size))
08c3a6
+
08c3a6
+        offset = self.ehdr.e_shoff
08c3a6
+        for _ in range(self._shdr_num):
08c3a6
+            shdr = self.read(self.Shdr, offset)
08c3a6
+            if resolve:
08c3a6
+                shdr = shdr.resolve(self._shdr_strtab)
08c3a6
+            yield shdr
08c3a6
+            offset += size
08c3a6
+
08c3a6
+    def dynamic(self) -> Dyn:
08c3a6
+        """Generator iterating over the dynamic segment."""
08c3a6
+        for phdr in self.phdrs():
08c3a6
+            if phdr.p_type == Pt.PT_DYNAMIC:
08c3a6
+                # Pick the first dynamic segment, like the loader.
08c3a6
+                if phdr.p_filesz == 0:
08c3a6
+                    # Probably separated debuginfo.
08c3a6
+                    return
08c3a6
+                offset = phdr.p_offset
08c3a6
+                end = offset + phdr.p_memsz
08c3a6
+                size = self.Dyn.size
08c3a6
+                while True:
08c3a6
+                    next_offset = offset + size
08c3a6
+                    if next_offset > end:
08c3a6
+                        raise ValueError(
08c3a6
+                            'Dynamic segment size {} is not a multiple of Dyn size {}'.format(
08c3a6
+                                phdr.p_memsz, size))
08c3a6
+                    yield self.read(self.Dyn, offset)
08c3a6
+                    if next_offset == end:
08c3a6
+                        return
08c3a6
+                    offset = next_offset
08c3a6
+
08c3a6
+    def syms(self, shdr: Shdr, resolve: bool=True) -> Sym:
08c3a6
+        """A generator iterating over a symbol table.
08c3a6
+
08c3a6
+        If resolve, symbol names are automatically translated using
08c3a6
+        the string table for the symbol table.
08c3a6
+
08c3a6
+        """
08c3a6
+        assert shdr.sh_type == Sht.SHT_SYMTAB
08c3a6
+        size = shdr.sh_entsize
08c3a6
+        if size != self.Sym.size:
08c3a6
+            raise ValueError('Invalid symbol table entry size {}'.format(size))
08c3a6
+        offset = shdr.sh_offset
08c3a6
+        end = shdr.sh_offset + shdr.sh_size
08c3a6
+        if resolve:
08c3a6
+            strtab = self._find_stringtab(shdr.sh_link)
08c3a6
+        while offset < end:
08c3a6
+            sym = self.read(self.Sym, offset)
08c3a6
+            if resolve:
08c3a6
+                sym = sym.resolve(strtab)
08c3a6
+            yield sym
08c3a6
+            offset += size
08c3a6
+        if offset != end:
08c3a6
+            raise ValueError('Symbol table is not a multiple of entry size')
08c3a6
+
08c3a6
+    def lookup_string(self, strtab_index: int, strtab_offset: int) -> bytes:
08c3a6
+        """Looks up a string in a string table identified by its link index."""
08c3a6
+        try:
08c3a6
+            strtab = self._stringtab[strtab_index]
08c3a6
+        except KeyError:
08c3a6
+            strtab = self._find_stringtab(strtab_index)
08c3a6
+        return strtab.get(strtab_offset)
08c3a6
+
08c3a6
+    def find_section(self, shndx: Shn) -> Shdr:
08c3a6
+        """Returns the section header for the indexed section.
08c3a6
+
08c3a6
+        The section name is not resolved.
08c3a6
+        """
08c3a6
+        try:
08c3a6
+            return self._section[shndx]
08c3a6
+        except KeyError:
08c3a6
+            pass
08c3a6
+        if shndx in Shn:
08c3a6
+            raise ValueError('Reserved section index {}'.format(shndx))
08c3a6
+        idx = shndx.value
08c3a6
+        if idx < 0 or idx > self._shdr_num:
08c3a6
+            raise ValueError('Section index {} out of range [0, {})'.format(
08c3a6
+                idx, self._shdr_num))
08c3a6
+        shdr = self.read(
08c3a6
+            self.Shdr, self.ehdr.e_shoff + idx * self.Shdr.size)
08c3a6
+        self._section[shndx] = shdr
08c3a6
+        return shdr
08c3a6
+
08c3a6
+    def _find_stringtab(self, sh_link: int) -> StringTable:
08c3a6
+        if sh_link in self._stringtab:
08c3a6
+            return self._stringtab
08c3a6
+        if sh_link < 0 or sh_link >= self._shdr_num:
08c3a6
+            raise ValueError('Section index {} out of range [0, {})'.format(
08c3a6
+                sh_link, self._shdr_num))
08c3a6
+        shdr = self.read(
08c3a6
+            self.Shdr, self.ehdr.e_shoff + sh_link * self.Shdr.size)
08c3a6
+        if shdr.sh_type != Sht.SHT_STRTAB:
08c3a6
+            raise ValueError(
08c3a6
+                'Section {} is not a string table: {}'.format(
08c3a6
+                    sh_link, shdr.sh_type))
08c3a6
+        strtab = StringTable(
08c3a6
+            self.image[shdr.sh_offset:shdr.sh_offset + shdr.sh_size])
08c3a6
+        # This could retrain essentially arbitrary amounts of data,
08c3a6
+        # but caching string tables seems important for performance.
08c3a6
+        self._stringtab[sh_link] = strtab
08c3a6
+        return strtab
08c3a6
+
08c3a6
+
08c3a6
+__all__ = [name for name in dir() if name[0].isupper()]