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