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