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