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