diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..fd984f8 --- /dev/null +++ b/.clang-format @@ -0,0 +1,54 @@ +# Generated from CLion C/C++ Code Style settings +--- +Language: Cpp +BasedOnStyle: LLVM +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignOperands: false +AlignTrailingComments: false +AlwaysBreakTemplateDeclarations: Yes +BraceWrapping: + AfterCaseLabel: true + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: false + BeforeCatch: true + BeforeElse: true + BeforeLambdaBody: true + BeforeWhile: true + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBraces: Custom +BreakConstructorInitializers: AfterColon +BreakConstructorInitializersBeforeComma: false +ColumnLimit: 120 +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ContinuationIndentWidth: 2 +IncludeCategories: + - Regex: '^<.*' + Priority: 1 + - Regex: '^".*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '([-_](test|unittest))?$' +IndentCaseBlocks: true +InsertNewlineAtEOF: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: All +PointerAlignment: Left +SpaceInEmptyParentheses: false +SpacesInAngles: false +SpacesInConditionalStatement: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +TabWidth: 4 +... diff --git a/.gitignore b/.gitignore index fa33649..317a2a6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .cache/ +.idea/ build/ emulator/customasm/*.bin diff --git a/DOCS.txt b/DOCS.txt index 7773b8c..23e546c 100644 --- a/DOCS.txt +++ b/DOCS.txt @@ -25,7 +25,7 @@ ╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣ ║ BXOR ║ Bitwise exclusive or ║ D = A ^ B ║ CCCR ║ 0100 ║ 0DDd ║ dddd ║ 0BBb ║ bbbb ║ 0AAa ║ aaaa ║ ║ 101 ║ A > B ║ ╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣ -║ RESERVED ║ ║ ║ ║ 0101 ║ ║ ║ ║ ║ ║ ║ ║ 110 ║ A != B ║ +║ ZRSH ║ Pad zero right shift ║ D = A >> B ║ CCCR ║ 0101 ║ 0DDd ║ dddd ║ 0BBb ║ bbbb ║ 0AAa ║ aaaa ║ ║ 110 ║ A != B ║ ╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣ ║ SRSH ║ Signed right shift ║ D = A >> B ║ CCCR ║ 0110 ║ xDDd ║ dddd ║ 0BBb ║ bbbb ║ xAAa ║ aaaa ║ ║ 111 ║ Reserved ║ ╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╩═════════════════════════╣ diff --git a/emulator/include/elfio/LICENSE.txt b/emulator/include/elfio/LICENSE.txt new file mode 100644 index 0000000..c6badc6 --- /dev/null +++ b/emulator/include/elfio/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/emulator/include/elfio/elf_types.hpp b/emulator/include/elfio/elf_types.hpp new file mode 100644 index 0000000..ff6743f --- /dev/null +++ b/emulator/include/elfio/elf_types.hpp @@ -0,0 +1,1564 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFTYPES_H +#define ELFTYPES_H + +#include + +#ifdef __cplusplus +namespace ELFIO { +#endif + +using Elf_Half = std::uint16_t; +using Elf_Word = std::uint32_t; +using Elf_Sword = std::int32_t; +using Elf_Xword = std::uint64_t; +using Elf_Sxword = std::int64_t; + +using Elf32_Addr = std::uint32_t; +using Elf32_Off = std::uint32_t; +using Elf64_Addr = std::uint64_t; +using Elf64_Off = std::uint64_t; + +using Elf32_Half = Elf_Half; +using Elf64_Half = Elf_Half; +using Elf32_Word = Elf_Word; +using Elf64_Word = Elf_Word; +using Elf32_Sword = Elf_Sword; +using Elf64_Sword = Elf_Sword; + +/////////////////////// +// ELF Header Constants + +// File type +constexpr Elf_Half ET_NONE = 0; +constexpr Elf_Half ET_REL = 1; +constexpr Elf_Half ET_EXEC = 2; +constexpr Elf_Half ET_DYN = 3; +constexpr Elf_Half ET_CORE = 4; +constexpr Elf_Half ET_LOOS = 0xFE00; +constexpr Elf_Half ET_HIOS = 0xFEFF; +constexpr Elf_Half ET_LOPROC = 0xFF00; +constexpr Elf_Half ET_HIPROC = 0xFFFF; + +// clang-format off +// Machine number +constexpr Elf_Half EM_NONE = 0 ; // No machine +constexpr Elf_Half EM_M32 = 1 ; // AT&T WE 32100 +constexpr Elf_Half EM_SPARC = 2 ; // SUN SPARC +constexpr Elf_Half EM_386 = 3 ; // Intel 80386 +constexpr Elf_Half EM_68K = 4 ; // Motorola m68k family +constexpr Elf_Half EM_88K = 5 ; // Motorola m88k family +constexpr Elf_Half EM_486 = 6 ; // Intel 80486// Reserved for future use +constexpr Elf_Half EM_860 = 7 ; // Intel 80860 +constexpr Elf_Half EM_MIPS = 8 ; // MIPS R3000 (officially, big-endian only) +constexpr Elf_Half EM_S370 = 9 ; // IBM System/370 +constexpr Elf_Half EM_MIPS_RS3_LE = 10; // MIPS R3000 little-endian (Deprecated) +constexpr Elf_Half EM_res011 = 11; // Reserved +constexpr Elf_Half EM_res012 = 12; // Reserved +constexpr Elf_Half EM_res013 = 13; // Reserved +constexpr Elf_Half EM_res014 = 14; // Reserved +constexpr Elf_Half EM_PARISC = 15; // HPPA +constexpr Elf_Half EM_res016 = 16; // Reserved +constexpr Elf_Half EM_VPP550 = 17; // Fujitsu VPP500 +constexpr Elf_Half EM_SPARC32PLUS = 18; // Sun's "v8plus" +constexpr Elf_Half EM_960 = 19; // Intel 80960 +constexpr Elf_Half EM_PPC = 20; // PowerPC +constexpr Elf_Half EM_PPC64 = 21; // 64-bit PowerPC +constexpr Elf_Half EM_S390 = 22; // IBM S/390 +constexpr Elf_Half EM_SPU = 23; // Sony/Toshiba/IBM SPU +constexpr Elf_Half EM_res024 = 24; // Reserved +constexpr Elf_Half EM_res025 = 25; // Reserved +constexpr Elf_Half EM_res026 = 26; // Reserved +constexpr Elf_Half EM_res027 = 27; // Reserved +constexpr Elf_Half EM_res028 = 28; // Reserved +constexpr Elf_Half EM_res029 = 29; // Reserved +constexpr Elf_Half EM_res030 = 30; // Reserved +constexpr Elf_Half EM_res031 = 31; // Reserved +constexpr Elf_Half EM_res032 = 32; // Reserved +constexpr Elf_Half EM_res033 = 33; // Reserved +constexpr Elf_Half EM_res034 = 34; // Reserved +constexpr Elf_Half EM_res035 = 35; // Reserved +constexpr Elf_Half EM_V800 = 36; // NEC V800 series +constexpr Elf_Half EM_FR20 = 37; // Fujitsu FR20 +constexpr Elf_Half EM_RH32 = 38; // TRW RH32 +constexpr Elf_Half EM_MCORE = 39; // Motorola M*Core // May also be taken by Fujitsu MMA +constexpr Elf_Half EM_RCE = 39; // Old name for MCore +constexpr Elf_Half EM_ARM = 40; // ARM +constexpr Elf_Half EM_OLD_ALPHA = 41; // Digital Alpha +constexpr Elf_Half EM_SH = 42; // Renesas (formerly Hitachi) / SuperH SH +constexpr Elf_Half EM_SPARCV9 = 43; // SPARC v9 64-bit +constexpr Elf_Half EM_TRICORE = 44; // Siemens Tricore embedded processor +constexpr Elf_Half EM_ARC = 45; // ARC Cores +constexpr Elf_Half EM_H8_300 = 46; // Renesas (formerly Hitachi) H8/300 +constexpr Elf_Half EM_H8_300H = 47; // Renesas (formerly Hitachi) H8/300H +constexpr Elf_Half EM_H8S = 48; // Renesas (formerly Hitachi) H8S +constexpr Elf_Half EM_H8_500 = 49; // Renesas (formerly Hitachi) H8/500 +constexpr Elf_Half EM_IA_64 = 50; // Intel IA-64 Processor +constexpr Elf_Half EM_MIPS_X = 51; // Stanford MIPS-X +constexpr Elf_Half EM_COLDFIRE = 52; // Motorola Coldfire +constexpr Elf_Half EM_68HC12 = 53; // Motorola M68HC12 +constexpr Elf_Half EM_MMA = 54; // Fujitsu Multimedia Accelerator +constexpr Elf_Half EM_PCP = 55; // Siemens PCP +constexpr Elf_Half EM_NCPU = 56; // Sony nCPU embedded RISC processor +constexpr Elf_Half EM_NDR1 = 57; // Denso NDR1 microprocesspr +constexpr Elf_Half EM_STARCORE = 58; // Motorola Star*Core processor +constexpr Elf_Half EM_ME16 = 59; // Toyota ME16 processor +constexpr Elf_Half EM_ST100 = 60; // STMicroelectronics ST100 processor +constexpr Elf_Half EM_TINYJ = 61; // Advanced Logic Corp. TinyJ embedded processor +constexpr Elf_Half EM_X86_64 = 62; // Advanced Micro Devices X86-64 processor +constexpr Elf_Half EM_PDSP = 63; // Sony DSP Processor +constexpr Elf_Half EM_PDP10 = 64; // Digital Equipment Corp. PDP-10 +constexpr Elf_Half EM_PDP11 = 65; // Digital Equipment Corp. PDP-11 +constexpr Elf_Half EM_FX66 = 66; // Siemens FX66 microcontroller +constexpr Elf_Half EM_ST9PLUS = 67; // STMicroelectronics ST9+ 8/16 bit microcontroller +constexpr Elf_Half EM_ST7 = 68 ; // STMicroelectronics ST7 8-bit microcontroller +constexpr Elf_Half EM_68HC16 = 69 ; // Motorola MC68HC16 Microcontroller +constexpr Elf_Half EM_68HC11 = 70 ; // Motorola MC68HC11 Microcontroller +constexpr Elf_Half EM_68HC08 = 71 ; // Motorola MC68HC08 Microcontroller +constexpr Elf_Half EM_68HC05 = 72 ; // Motorola MC68HC05 Microcontroller +constexpr Elf_Half EM_SVX = 73 ; // Silicon Graphics SVx +constexpr Elf_Half EM_ST19 = 74 ; // STMicroelectronics ST19 8-bit cpu +constexpr Elf_Half EM_VAX = 75 ; // Digital VAX +constexpr Elf_Half EM_CRIS = 76 ; // Axis Communications 32-bit embedded processor +constexpr Elf_Half EM_JAVELIN = 77 ; // Infineon Technologies 32-bit embedded cpu +constexpr Elf_Half EM_FIREPATH = 78 ; // Element 14 64-bit DSP processor +constexpr Elf_Half EM_ZSP = 79 ; // LSI Logic's 16-bit DSP processor +constexpr Elf_Half EM_MMIX = 80 ; // Donald Knuth's educational 64-bit processor +constexpr Elf_Half EM_HUANY = 81 ; // Harvard's machine-independent format +constexpr Elf_Half EM_PRISM = 82 ; // SiTera Prism +constexpr Elf_Half EM_AVR = 83 ; // Atmel AVR 8-bit microcontroller +constexpr Elf_Half EM_FR30 = 84 ; // Fujitsu FR30 +constexpr Elf_Half EM_D10V = 85 ; // Mitsubishi D10V +constexpr Elf_Half EM_D30V = 86 ; // Mitsubishi D30V +constexpr Elf_Half EM_V850 = 87 ; // NEC v850 +constexpr Elf_Half EM_M32R = 88 ; // Renesas M32R (formerly Mitsubishi M32R) +constexpr Elf_Half EM_MN10300 = 89 ; // Matsushita MN10300 +constexpr Elf_Half EM_MN10200 = 90 ; // Matsushita MN10200 +constexpr Elf_Half EM_PJ = 91 ; // picoJava +constexpr Elf_Half EM_OPENRISC = 92 ; // OpenRISC 32-bit embedded processor +constexpr Elf_Half EM_ARC_A5 = 93 ; // ARC Cores Tangent-A5 +constexpr Elf_Half EM_XTENSA = 94 ; // Tensilica Xtensa Architecture +constexpr Elf_Half EM_VIDEOCORE = 95 ; // Alphamosaic VideoCore processor +constexpr Elf_Half EM_TMM_GPP = 96 ; // Thompson Multimedia General Purpose Processor +constexpr Elf_Half EM_NS32K = 97 ; // National Semiconductor 32000 series +constexpr Elf_Half EM_TPC = 98 ; // Tenor Network TPC processor +constexpr Elf_Half EM_SNP1K = 99 ; // Trebia SNP 1000 processor +constexpr Elf_Half EM_ST200 = 100; // STMicroelectronics ST200 microcontroller +constexpr Elf_Half EM_IP2K = 101; // Ubicom IP2022 micro controller +constexpr Elf_Half EM_MAX = 102; // MAX Processor +constexpr Elf_Half EM_CR = 103; // National Semiconductor CompactRISC +constexpr Elf_Half EM_F2MC16 = 104; // Fujitsu F2MC16 +constexpr Elf_Half EM_MSP430 = 105; // TI msp430 micro controller +constexpr Elf_Half EM_BLACKFIN = 106; // ADI Blackfin +constexpr Elf_Half EM_SE_C33 = 107; // S1C33 Family of Seiko Epson processors +constexpr Elf_Half EM_SEP = 108; // Sharp embedded microprocessor +constexpr Elf_Half EM_ARCA = 109; // Arca RISC Microprocessor +constexpr Elf_Half EM_UNICORE = 110; // Microprocessor series from PKU-Unity Ltd. +constexpr Elf_Half EM_EXCESS = 111; // eXcess: 16/32/64-bit configurable embedded CPU +constexpr Elf_Half EM_DXP = 112; // Icera Semiconductor Inc. Deep Execution Processor +constexpr Elf_Half EM_ALTERA_NIOS2 = 113; // Altera Nios II soft-core processor +constexpr Elf_Half EM_CRX = 114; // National Semiconductor CRX +constexpr Elf_Half EM_XGATE = 115; // Motorola XGATE embedded processor +constexpr Elf_Half EM_C166 = 116; // Infineon C16x/XC16x processor +constexpr Elf_Half EM_M16C = 117; // Renesas M16C series microprocessors +constexpr Elf_Half EM_DSPIC30F = 118; // Microchip Technology dsPIC30F DSignal Controller +constexpr Elf_Half EM_CE = 119; // Freescale Communication Engine RISC core +constexpr Elf_Half EM_M32C = 120; // Renesas M32C series microprocessors +constexpr Elf_Half EM_res121 = 121; // Reserved +constexpr Elf_Half EM_res122 = 122; // Reserved +constexpr Elf_Half EM_res123 = 123; // Reserved +constexpr Elf_Half EM_res124 = 124; // Reserved +constexpr Elf_Half EM_res125 = 125; // Reserved +constexpr Elf_Half EM_res126 = 126; // Reserved +constexpr Elf_Half EM_res127 = 127; // Reserved +constexpr Elf_Half EM_res128 = 128; // Reserved +constexpr Elf_Half EM_res129 = 129; // Reserved +constexpr Elf_Half EM_res130 = 130; // Reserved +constexpr Elf_Half EM_TSK3000 = 131; // Altium TSK3000 core +constexpr Elf_Half EM_RS08 = 132; // Freescale RS08 embedded processor +constexpr Elf_Half EM_res133 = 133; // Reserved +constexpr Elf_Half EM_ECOG2 = 134; // Cyan Technology eCOG2 microprocessor +constexpr Elf_Half EM_SCORE = 135; // Sunplus Score +constexpr Elf_Half EM_SCORE7 = 135; // Sunplus S+core7 RISC processor +constexpr Elf_Half EM_DSP24 = 136; // New Japan Radio (NJR) 24-bit DSP Processor +constexpr Elf_Half EM_VIDEOCORE3 = 137; // Broadcom VideoCore III processor +constexpr Elf_Half EM_LATTICEMICO32 = 138; // RISC processor for Lattice FPGA architecture +constexpr Elf_Half EM_SE_C17 = 139; // Seiko Epson C17 family +constexpr Elf_Half EM_TI_C6000 = 140; // Texas Instruments TMS320C6000 DSP family +constexpr Elf_Half EM_TI_C2000 = 141; // Texas Instruments TMS320C2000 DSP family +constexpr Elf_Half EM_TI_C5500 = 142; // Texas Instruments TMS320C55x DSP family +constexpr Elf_Half EM_res143 = 143; // Reserved +constexpr Elf_Half EM_res144 = 144; // Reserved +constexpr Elf_Half EM_res145 = 145; // Reserved +constexpr Elf_Half EM_res146 = 146; // Reserved +constexpr Elf_Half EM_res147 = 147; // Reserved +constexpr Elf_Half EM_res148 = 148; // Reserved +constexpr Elf_Half EM_res149 = 149; // Reserved +constexpr Elf_Half EM_res150 = 150; // Reserved +constexpr Elf_Half EM_res151 = 151; // Reserved +constexpr Elf_Half EM_res152 = 152; // Reserved +constexpr Elf_Half EM_res153 = 153; // Reserved +constexpr Elf_Half EM_res154 = 154; // Reserved +constexpr Elf_Half EM_res155 = 155; // Reserved +constexpr Elf_Half EM_res156 = 156; // Reserved +constexpr Elf_Half EM_res157 = 157; // Reserved +constexpr Elf_Half EM_res158 = 158; // Reserved +constexpr Elf_Half EM_res159 = 159; // Reserved +constexpr Elf_Half EM_MMDSP_PLUS = 160; // STMicroelectronics 64bit VLIW Data Signal Processor +constexpr Elf_Half EM_CYPRESS_M8C = 161; // Cypress M8C microprocessor +constexpr Elf_Half EM_R32C = 162; // Renesas R32C series microprocessors +constexpr Elf_Half EM_TRIMEDIA = 163; // NXP Semiconductors TriMedia architecture family +constexpr Elf_Half EM_QDSP6 = 164; // QUALCOMM DSP6 Processor +constexpr Elf_Half EM_8051 = 165; // Intel 8051 and variants +constexpr Elf_Half EM_STXP7X = 166; // STMicroelectronics STxP7x family +constexpr Elf_Half EM_NDS32 = 167; // Andes Technology embedded RISC processor family +constexpr Elf_Half EM_ECOG1 = 168; // Cyan Technology eCOG1X family +constexpr Elf_Half EM_ECOG1X = 168; // Cyan Technology eCOG1X family +constexpr Elf_Half EM_MAXQ30 = 169; // Dallas Semiconductor MAXQ30 Core Micro-controllers +constexpr Elf_Half EM_XIMO16 = 170; // New Japan Radio (NJR) 16-bit DSP Processor +constexpr Elf_Half EM_MANIK = 171; // M2000 Reconfigurable RISC Microprocessor +constexpr Elf_Half EM_CRAYNV2 = 172; // Cray Inc. NV2 vector architecture +constexpr Elf_Half EM_RX = 173; // Renesas RX family +constexpr Elf_Half EM_METAG = 174; // Imagination Technologies META processor architecture +constexpr Elf_Half EM_MCST_ELBRUS = 175; // MCST Elbrus general purpose hardware architecture +constexpr Elf_Half EM_ECOG16 = 176; // Cyan Technology eCOG16 family +constexpr Elf_Half EM_CR16 = 177; // National Semiconductor CompactRISC 16-bit processor +constexpr Elf_Half EM_ETPU = 178; // Freescale Extended Time Processing Unit +constexpr Elf_Half EM_SLE9X = 179; // Infineon Technologies SLE9X core +constexpr Elf_Half EM_L1OM = 180; // Intel L1OM +constexpr Elf_Half EM_INTEL181 = 181; // Reserved by Intel +constexpr Elf_Half EM_INTEL182 = 182; // Reserved by Intel +constexpr Elf_Half EM_AARCH64 = 183; // ARM AArch64 +constexpr Elf_Half EM_res184 = 184; // Reserved by ARM +constexpr Elf_Half EM_AVR32 = 185; // Atmel Corporation 32-bit microprocessor family +constexpr Elf_Half EM_STM8 = 186; // STMicroeletronics STM8 8-bit microcontroller +constexpr Elf_Half EM_TILE64 = 187; // Tilera TILE64 multicore architecture family +constexpr Elf_Half EM_TILEPRO = 188; // Tilera TILEPro multicore architecture family +constexpr Elf_Half EM_MICROBLAZE = 189; // Xilinx MicroBlaze 32-bit RISC soft processor core +constexpr Elf_Half EM_CUDA = 190; // NVIDIA CUDA architecture +constexpr Elf_Half EM_TILEGX = 191; // Tilera TILE-Gx multicore architecture family +constexpr Elf_Half EM_CLOUDSHIELD = 192; // CloudShield architecture family +constexpr Elf_Half EM_COREA_1ST = 193; // KIPO-KAIST Core-A 1st generation processor family +constexpr Elf_Half EM_COREA_2ND = 194; // KIPO-KAIST Core-A 2nd generation processor family +constexpr Elf_Half EM_ARC_COMPACT2 = 195; // Synopsys ARCompact V2 +constexpr Elf_Half EM_OPEN8 = 196; // Open8 8-bit RISC soft processor core +constexpr Elf_Half EM_RL78 = 197; // Renesas RL78 family +constexpr Elf_Half EM_VIDEOCORE5 = 198; // Broadcom VideoCore V processor +constexpr Elf_Half EM_78KOR = 199; // Renesas 78KOR family +constexpr Elf_Half EM_56800EX = 200; // Freescale 56800EX Digital Signal Controller (DSC) +constexpr Elf_Half EM_BA1 = 201; // Beyond BA1 CPU architecture +constexpr Elf_Half EM_BA2 = 202; // Beyond BA2 CPU architecture +constexpr Elf_Half EM_XCORE = 203; // XMOS xCORE processor family +constexpr Elf_Half EM_MCHP_PIC = 204; // Microchip 8-bit PIC(r) family +constexpr Elf_Half EM_INTEL205 = 205; // Reserved by Intel +constexpr Elf_Half EM_INTEL206 = 206; // Reserved by Intel +constexpr Elf_Half EM_INTEL207 = 207; // Reserved by Intel +constexpr Elf_Half EM_INTEL208 = 208; // Reserved by Intel +constexpr Elf_Half EM_INTEL209 = 209; // Reserved by Intel +constexpr Elf_Half EM_KM32 = 210; // KM211 KM32 32-bit processor +constexpr Elf_Half EM_KMX32 = 211; // KM211 KMX32 32-bit processor +constexpr Elf_Half EM_KMX16 = 212; // KM211 KMX16 16-bit processor +constexpr Elf_Half EM_KMX8 = 213; // KM211 KMX8 8-bit processor +constexpr Elf_Half EM_KVARC = 214; // KM211 KVARC processor +constexpr Elf_Half EM_CDP = 215; // Paneve CDP architecture family +constexpr Elf_Half EM_COGE = 216; // Cognitive Smart Memory Processor +constexpr Elf_Half EM_COOL = 217; // iCelero CoolEngine +constexpr Elf_Half EM_NORC = 218; // Nanoradio Optimized RISC +constexpr Elf_Half EM_CSR_KALIMBA = 219; // CSR Kalimba architecture family +constexpr Elf_Half EM_Z80 = 220; // Zilog Z80 +constexpr Elf_Half EM_VISIUM = 221; // Controls and Data Services VISIUMcore processor +constexpr Elf_Half EM_FT32 = 222; // FTDI Chip FT32 high performance 32-bit RISC architecture +constexpr Elf_Half EM_MOXIE = 223; // Moxie processor family +constexpr Elf_Half EM_AMDGPU = 224; // AMD GPU architecture +constexpr Elf_Half EM_RISCV = 243; // RISC-V +constexpr Elf_Half EM_LANAI = 244; // Lanai processor +constexpr Elf_Half EM_CEVA = 245; // CEVA Processor Architecture Family +constexpr Elf_Half EM_CEVA_X2 = 246; // CEVA X2 Processor Family +constexpr Elf_Half EM_BPF = 247; // Linux BPF - in-kernel virtual machine +constexpr Elf_Half EM_GRAPHCORE_IPU = 248; // Graphcore Intelligent Processing Unit +constexpr Elf_Half EM_IMG1 = 249; // Imagination Technologies +constexpr Elf_Half EM_NFP = 250; // Netronome Flow Processor (P) +constexpr Elf_Half EM_CSKY = 252; // C-SKY processor family +constexpr Elf_Half EM_ARC_COMPACT3_64 = 253; // Synopsys ARCv2.3 64-bit +constexpr Elf_Half EM_MCS6502 = 254; // MOS Technology MCS 6502 processor +constexpr Elf_Half EM_ARC_COMPACT3 = 255; // Synopsys ARCv2.3 32-bit +constexpr Elf_Half EM_KVX = 256; // Kalray VLIW core of the MPPA processor family +constexpr Elf_Half EM_65816 = 257; // WDC 65816/65C816 +constexpr Elf_Half EM_LOONGARCH = 258; // Loongson Loongarch +constexpr Elf_Half EM_KF32 = 259; // ChipON KungFu32 + +constexpr Elf_Half EM_MT = 0x2530; // Morpho Techologies MT processor +constexpr Elf_Half EM_ALPHA = 0x9026; // Alpha +constexpr Elf_Half EM_WEBASSEMBLY = 0x4157; // Web Assembly +constexpr Elf_Half EM_DLX = 0x5aa5; // OpenDLX +constexpr Elf_Half EM_XSTORMY16 = 0xad45; // Sanyo XStormy16 CPU core +constexpr Elf_Half EM_IQ2000 = 0xFEBA; // Vitesse IQ2000 +constexpr Elf_Half EM_M32C_OLD = 0xFEB; +constexpr Elf_Half EM_NIOS32 = 0xFEBB; // Altera Nios +constexpr Elf_Half EM_CYGNUS_MEP = 0xF00D; // Toshiba MeP Media Engine +constexpr Elf_Half EM_ADAPTEVA_EPIPHANY = 0x1223; // Adapteva EPIPHANY +constexpr Elf_Half EM_CYGNUS_FRV = 0x5441; // Fujitsu FR-V +constexpr Elf_Half EM_S12Z = 0x4DEF; // Freescale S12Z +// clang-format on + +// File version +constexpr unsigned char EV_NONE = 0; +constexpr unsigned char EV_CURRENT = 1; + +// Identification index +constexpr unsigned char EI_MAG0 = 0; +constexpr unsigned char EI_MAG1 = 1; +constexpr unsigned char EI_MAG2 = 2; +constexpr unsigned char EI_MAG3 = 3; +constexpr unsigned char EI_CLASS = 4; +constexpr unsigned char EI_DATA = 5; +constexpr unsigned char EI_VERSION = 6; +constexpr unsigned char EI_OSABI = 7; +constexpr unsigned char EI_ABIVERSION = 8; +constexpr unsigned char EI_PAD = 9; +constexpr unsigned char EI_NIDENT = 16; + +// Magic number +constexpr unsigned char ELFMAG0 = 0x7F; +constexpr unsigned char ELFMAG1 = 'E'; +constexpr unsigned char ELFMAG2 = 'L'; +constexpr unsigned char ELFMAG3 = 'F'; + +// File class +constexpr unsigned char ELFCLASSNONE = 0; +constexpr unsigned char ELFCLASS32 = 1; +constexpr unsigned char ELFCLASS64 = 2; + +// Encoding +constexpr unsigned char ELFDATANONE = 0; +constexpr unsigned char ELFDATA2LSB = 1; +constexpr unsigned char ELFDATA2MSB = 2; + +// clang-format off +// OS extensions +constexpr unsigned char ELFOSABI_NONE = 0; // No extensions or unspecified +constexpr unsigned char ELFOSABI_HPUX = 1; // Hewlett-Packard HP-UX +constexpr unsigned char ELFOSABI_NETBSD = 2; // NetBSD +constexpr unsigned char ELFOSABI_LINUX = 3; // Linux +constexpr unsigned char ELFOSABI_HURD = 4; // GNU Hurd +constexpr unsigned char ELFOSABI_SOLARIS = 6; // Sun Solaris +constexpr unsigned char ELFOSABI_AIX = 7; // AIX +constexpr unsigned char ELFOSABI_IRIX = 8; // IRIX +constexpr unsigned char ELFOSABI_FREEBSD = 9; // FreeBSD +constexpr unsigned char ELFOSABI_TRU64 = 10; // Compaq TRU64 UNIX +constexpr unsigned char ELFOSABI_MODESTO = 11; // Novell Modesto +constexpr unsigned char ELFOSABI_OPENBSD = 12; // Open BSD +constexpr unsigned char ELFOSABI_OPENVMS = 13; // Open VMS +constexpr unsigned char ELFOSABI_NSK = 14; // Hewlett-Packard Non-Stop Kernel +constexpr unsigned char ELFOSABI_AROS = 15; // Amiga Research OS +constexpr unsigned char ELFOSABI_FENIXOS = 16; // The FenixOS highly scalable multi-core OS +constexpr unsigned char ELFOSABI_NUXI = 17; // Nuxi CloudABI +constexpr unsigned char ELFOSABI_OPENVOS = 18; // Stratus Technologies OpenVOS +constexpr unsigned char ELFOSABI_ARM = 97; // ARM +constexpr unsigned char ELFOSABI_STANDALONE = 255; // Standalone (embedded) application + +// 64-255 Architecture-specific value range +// AMDGPU OS for HSA compatible compute kernels +constexpr unsigned char ELFOSABI_AMDGPU_HSA = 64; +// AMDGPU OS for AMD PAL compatible graphics +// shaders and compute kernels +constexpr unsigned char ELFOSABI_AMDGPU_PAL = 65; +// AMDGPU OS for Mesa3D compatible graphics +// shaders and compute kernels +constexpr unsigned char ELFOSABI_AMDGPU_MESA3D = 66; +// clang-format on + +constexpr unsigned char ELFABIVERSION_AMDGPU_HSA_V2 = 0; +constexpr unsigned char ELFABIVERSION_AMDGPU_HSA_V3 = 1; +constexpr unsigned char ELFABIVERSION_AMDGPU_HSA_V4 = 2; + +// AMDGPU specific e_flags +constexpr Elf_Word EF_AMDGPU_MACH = 0x0ff; // AMDGPU processor selection mask. +// Indicates if the XNACK target feature is +// enabled for all code contained in the ELF. +constexpr Elf_Word EF_AMDGPU_XNACK = 0x100; + +constexpr Elf_Word EF_AMDGPU_FEATURE_XNACK_V2 = 0x01; +constexpr Elf_Word EF_AMDGPU_FEATURE_TRAP_HANDLER_V2 = 0x02; +constexpr Elf_Word EF_AMDGPU_FEATURE_XNACK_V3 = 0x100; +constexpr Elf_Word EF_AMDGPU_FEATURE_SRAMECC_V3 = 0x200; +constexpr Elf_Word EF_AMDGPU_FEATURE_XNACK_V4 = 0x300; +constexpr Elf_Word EF_AMDGPU_FEATURE_XNACK_UNSUPPORTED_V4 = 0x000; +constexpr Elf_Word EF_AMDGPU_FEATURE_XNACK_ANY_V4 = 0x100; +constexpr Elf_Word EF_AMDGPU_FEATURE_XNACK_OFF_V4 = 0x200; +constexpr Elf_Word EF_AMDGPU_FEATURE_XNACK_ON_V4 = 0x300; +constexpr Elf_Word EF_AMDGPU_FEATURE_SRAMECC_V4 = 0xc00; +constexpr Elf_Word EF_AMDGPU_FEATURE_SRAMECC_UNSUPPORTED_V4 = 0x000; +constexpr Elf_Word EF_AMDGPU_FEATURE_SRAMECC_ANY_V4 = 0x400; +constexpr Elf_Word EF_AMDGPU_FEATURE_SRAMECC_OFF_V4 = 0x800; +constexpr Elf_Word EF_AMDGPU_FEATURE_SRAMECC_ON_V4 = 0xc00; + +// AMDGPU processors +constexpr Elf_Word EF_AMDGPU_MACH_NONE = 0x000; // Unspecified processor. +constexpr Elf_Word EF_AMDGPU_MACH_R600_R600 = 0x001; +constexpr Elf_Word EF_AMDGPU_MACH_R600_R630 = 0x002; +constexpr Elf_Word EF_AMDGPU_MACH_R600_RS880 = 0x003; +constexpr Elf_Word EF_AMDGPU_MACH_R600_RV670 = 0x004; +constexpr Elf_Word EF_AMDGPU_MACH_R600_RV710 = 0x005; +constexpr Elf_Word EF_AMDGPU_MACH_R600_RV730 = 0x006; +constexpr Elf_Word EF_AMDGPU_MACH_R600_RV770 = 0x007; +constexpr Elf_Word EF_AMDGPU_MACH_R600_CEDAR = 0x008; +constexpr Elf_Word EF_AMDGPU_MACH_R600_CYPRESS = 0x009; +constexpr Elf_Word EF_AMDGPU_MACH_R600_JUNIPER = 0x00a; +constexpr Elf_Word EF_AMDGPU_MACH_R600_REDWOOD = 0x00b; +constexpr Elf_Word EF_AMDGPU_MACH_R600_SUMO = 0x00c; +constexpr Elf_Word EF_AMDGPU_MACH_R600_BARTS = 0x00d; +constexpr Elf_Word EF_AMDGPU_MACH_R600_CAICOS = 0x00e; +constexpr Elf_Word EF_AMDGPU_MACH_R600_CAYMAN = 0x00f; +constexpr Elf_Word EF_AMDGPU_MACH_R600_TURKS = 0x010; +constexpr Elf_Word EF_AMDGPU_MACH_R600_RESERVED_FIRST = 0x011; +constexpr Elf_Word EF_AMDGPU_MACH_R600_RESERVED_LAST = 0x01f; +constexpr Elf_Word EF_AMDGPU_MACH_R600_FIRST = EF_AMDGPU_MACH_R600_R600; +constexpr Elf_Word EF_AMDGPU_MACH_R600_LAST = EF_AMDGPU_MACH_R600_TURKS; + +// AMDGCN-based processors. +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX600 = 0x020; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX601 = 0x021; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX700 = 0x022; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX701 = 0x023; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX702 = 0x024; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX703 = 0x025; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX704 = 0x026; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_RESERVED_0X27 = 0x027; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX801 = 0x028; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX802 = 0x029; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX803 = 0x02a; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX810 = 0x02b; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX900 = 0x02c; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX902 = 0x02d; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX904 = 0x02e; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX906 = 0x02f; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX908 = 0x030; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX909 = 0x031; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX90C = 0x032; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1010 = 0x033; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1011 = 0x034; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1012 = 0x035; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1030 = 0x036; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1031 = 0x037; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1032 = 0x038; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1033 = 0x039; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX602 = 0x03a; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX705 = 0x03b; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX805 = 0x03c; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_RESERVED_0X3D = 0x03d; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1034 = 0x03e; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX90A = 0x03f; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_RESERVED_0X40 = 0x040; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_RESERVED_0X41 = 0x041; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1013 = 0x042; +// First/last AMDGCN-based processors. +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_FIRST = EF_AMDGPU_MACH_AMDGCN_GFX600; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_LAST = EF_AMDGPU_MACH_AMDGCN_GFX1013; + +///////////////////// +// Sections constants + +// Section indexes +constexpr Elf_Word SHN_UNDEF = 0; +constexpr Elf_Word SHN_LORESERVE = 0xFF00; +constexpr Elf_Word SHN_LOPROC = 0xFF00; +constexpr Elf_Word SHN_HIPROC = 0xFF1F; +constexpr Elf_Word SHN_LOOS = 0xFF20; +constexpr Elf_Word SHN_HIOS = 0xFF3F; +constexpr Elf_Word SHN_ABS = 0xFFF1; +constexpr Elf_Word SHN_COMMON = 0xFFF2; +constexpr Elf_Word SHN_XINDEX = 0xFFFF; +constexpr Elf_Word SHN_HIRESERVE = 0xFFFF; + +// Section types +constexpr Elf_Word SHT_NULL = 0; +constexpr Elf_Word SHT_PROGBITS = 1; +constexpr Elf_Word SHT_SYMTAB = 2; +constexpr Elf_Word SHT_STRTAB = 3; +constexpr Elf_Word SHT_RELA = 4; +constexpr Elf_Word SHT_HASH = 5; +constexpr Elf_Word SHT_DYNAMIC = 6; +constexpr Elf_Word SHT_NOTE = 7; +constexpr Elf_Word SHT_NOBITS = 8; +constexpr Elf_Word SHT_REL = 9; +constexpr Elf_Word SHT_SHLIB = 10; +constexpr Elf_Word SHT_DYNSYM = 11; +constexpr Elf_Word SHT_INIT_ARRAY = 14; +constexpr Elf_Word SHT_FINI_ARRAY = 15; +constexpr Elf_Word SHT_PREINIT_ARRAY = 16; +constexpr Elf_Word SHT_GROUP = 17; +constexpr Elf_Word SHT_SYMTAB_SHNDX = 18; +constexpr Elf_Word SHT_GNU_ATTRIBUTES = 0x6ffffff5; +constexpr Elf_Word SHT_GNU_HASH = 0x6ffffff6; +constexpr Elf_Word SHT_GNU_LIBLIST = 0x6ffffff7; +constexpr Elf_Word SHT_CHECKSUM = 0x6ffffff8; +constexpr Elf_Word SHT_LOSUNW = 0x6ffffffa; +constexpr Elf_Word SHT_SUNW_move = 0x6ffffffa; +constexpr Elf_Word SHT_SUNW_COMDAT = 0x6ffffffb; +constexpr Elf_Word SHT_SUNW_syminfo = 0x6ffffffc; +constexpr Elf_Word SHT_GNU_verdef = 0x6ffffffd; +constexpr Elf_Word SHT_GNU_verneed = 0x6ffffffe; +constexpr Elf_Word SHT_GNU_versym = 0x6fffffff; +constexpr Elf_Word SHT_LOOS = 0x60000000; +constexpr Elf_Word SHT_HIOS = 0x6fffffff; +constexpr Elf_Word SHT_LOPROC = 0x70000000; +constexpr Elf_Word SHT_ARM_EXIDX = 0x70000001; +constexpr Elf_Word SHT_ARM_PREEMPTMAP = 0x70000002; +constexpr Elf_Word SHT_ARM_ATTRIBUTES = 0x70000003; +constexpr Elf_Word SHT_ARM_DEBUGOVERLAY = 0x70000004; +constexpr Elf_Word SHT_ARM_OVERLAYSECTION = 0x70000005; +constexpr Elf_Word SHT_HIPROC = 0x7FFFFFFF; +constexpr Elf_Word SHT_LOUSER = 0x80000000; +// Used by Nintendo Wii U +constexpr Elf_Word SHT_RPL_EXPORTS = 0x80000001; +constexpr Elf_Word SHT_RPL_IMPORTS = 0x80000002; +constexpr Elf_Word SHT_RPL_CRCS = 0x80000003; +constexpr Elf_Word SHT_RPL_FILEINFO = 0x80000004; +constexpr Elf_Word SHT_HIUSER = 0xFFFFFFFF; + +// Section attribute flags +constexpr Elf_Xword SHF_WRITE = 0x1; +constexpr Elf_Xword SHF_ALLOC = 0x2; +constexpr Elf_Xword SHF_EXECINSTR = 0x4; +constexpr Elf_Xword SHF_MERGE = 0x10; +constexpr Elf_Xword SHF_STRINGS = 0x20; +constexpr Elf_Xword SHF_INFO_LINK = 0x40; +constexpr Elf_Xword SHF_LINK_ORDER = 0x80; +constexpr Elf_Xword SHF_OS_NONCONFORMING = 0x100; +constexpr Elf_Xword SHF_GROUP = 0x200; +constexpr Elf_Xword SHF_TLS = 0x400; +constexpr Elf_Xword SHF_COMPRESSED = 0x800; +constexpr Elf_Xword SHF_GNU_RETAIN = 0x200000; +constexpr Elf_Xword SHF_GNU_MBIND = 0x01000000; +// flag used in Nintendo RPX/RPL to indicate section data is compressed +constexpr Elf_Xword SHF_RPX_DEFLATE = 0x08000000; +constexpr Elf_Xword SHF_MASKOS = 0x0FF00000; +constexpr Elf_Xword SHF_MIPS_GPREL = 0x10000000; +constexpr Elf_Xword SHF_ORDERED = 0x40000000; +constexpr Elf_Xword SHF_EXCLUDE = 0x80000000; +constexpr Elf_Xword SHF_MASKPROC = 0xF0000000; + +// Section group flags +constexpr Elf_Word GRP_COMDAT = 0x1; +constexpr Elf_Word GRP_MASKOS = 0x0ff00000; +constexpr Elf_Word GRP_MASKPROC = 0xf0000000; + +// Symbol binding +constexpr unsigned char STB_LOCAL = 0; +constexpr unsigned char STB_GLOBAL = 1; +constexpr unsigned char STB_WEAK = 2; +constexpr unsigned char STB_LOOS = 10; +constexpr unsigned char STB_HIOS = 12; +constexpr unsigned char STB_MULTIDEF = 13; +constexpr unsigned char STB_LOPROC = 13; +constexpr unsigned char STB_HIPROC = 15; + +// Values of note segment descriptor types for core files +constexpr Elf_Word NT_PRSTATUS = 1; // Contains copy of prstatus struct +constexpr Elf_Word NT_FPREGSET = 2; // Contains copy of fpregset struct +constexpr Elf_Word NT_PRPSINFO = 3; // Contains copy of prpsinfo struct +constexpr Elf_Word NT_TASKSTRUCT = 4; // Contains copy of task struct +constexpr Elf_Word NT_AUXV = 6; // Contains copy of Elfxx_auxv_t +constexpr Elf_Word NT_SIGINFO = 0x53494749; // Fields of siginfo_t. +constexpr Elf_Word NT_FILE = 0x46494c45; // Description of mapped files. + +// Note segments for core files on dir-style procfs systems. +constexpr Elf_Word NT_PSTATUS = 10; // Has a struct pstatus +constexpr Elf_Word NT_FPREGS = 12; // Has a struct fpregset +constexpr Elf_Word NT_PSINFO = 13; // Has a struct psinfo +constexpr Elf_Word NT_LWPSTATUS = 16; // Has a struct lwpstatus_t +constexpr Elf_Word NT_LWPSINFO = 17; // Has a struct lwpsinfo_t +constexpr Elf_Word NT_WIN32PSTATUS = 18; // Has a struct win32_pstatus + +// clang-format off + +// Note name must be "LINUX" +constexpr Elf_Word NT_PRXFPREG = 0x46e62b7f; // Contains a user_xfpregs_struct +constexpr Elf_Word NT_PPC_VMX = 0x100; // PowerPC Altivec/VMX registers +constexpr Elf_Word NT_PPC_VSX = 0x102; // PowerPC VSX registers +constexpr Elf_Word NT_PPC_TAR = 0x103; // PowerPC Target Address Register +constexpr Elf_Word NT_PPC_PPR = 0x104; // PowerPC Program Priority Register +constexpr Elf_Word NT_PPC_DSCR = 0x105; // PowerPC Data Stream Control Register +constexpr Elf_Word NT_PPC_EBB = 0x106; // PowerPC Event Based Branch Registers +constexpr Elf_Word NT_PPC_PMU = 0x107; // PowerPC Performance Monitor Registers +constexpr Elf_Word NT_PPC_TM_CGPR = 0x108; // PowerPC TM checkpointed GPR Registers +constexpr Elf_Word NT_PPC_TM_CFPR = 0x109; // PowerPC TM checkpointed FPR Registers +constexpr Elf_Word NT_PPC_TM_CVMX = 0x10a; // PowerPC TM checkpointed VMX Registers +constexpr Elf_Word NT_PPC_TM_CVSX = 0x10b; // PowerPC TM checkpointed VSX Registers +constexpr Elf_Word NT_PPC_TM_SPR = 0x10c; // PowerPC TM Special Purpose Registers +constexpr Elf_Word NT_PPC_TM_CTAR = 0x10d; // PowerPC TM checkpointed TAR +constexpr Elf_Word NT_PPC_TM_CPPR = 0x10e; // PowerPC TM checkpointed PPR +constexpr Elf_Word NT_PPC_TM_CDSCR = 0x10f; // PowerPC TM checkpointed Data SCR +constexpr Elf_Word NT_386_TLS = 0x200; // x86 TLS information +constexpr Elf_Word NT_386_IOPERM = 0x201; // x86 io permissions +constexpr Elf_Word NT_X86_XSTATE = 0x202; // x86 XSAVE extended state +constexpr Elf_Word NT_X86_CET = 0x203; // x86 CET state. +constexpr Elf_Word NT_S390_HIGH_GPRS = 0x300; // S/390 upper halves of GPRs +constexpr Elf_Word NT_S390_TIMER = 0x301; // S390 timer +constexpr Elf_Word NT_S390_TODCMP = 0x302; // S390 TOD clock comparator +constexpr Elf_Word NT_S390_TODPREG = 0x303; // S390 TOD programmable register +constexpr Elf_Word NT_S390_CTRS = 0x304; // S390 control registers +constexpr Elf_Word NT_S390_PREFIX = 0x305; // S390 prefix register +constexpr Elf_Word NT_S390_LAST_BREAK = 0x306; // S390 breaking event address +constexpr Elf_Word NT_S390_SYSTEM_CALL = 0x307; // S390 system call restart data +constexpr Elf_Word NT_S390_TDB = 0x308; // S390 transaction diagnostic block +constexpr Elf_Word NT_S390_VXRS_LOW = 0x309; // S390 vector registers 0-15 upper half +constexpr Elf_Word NT_S390_VXRS_HIGH = 0x30a; // S390 vector registers 16-31 +constexpr Elf_Word NT_S390_GS_CB = 0x30b; // s390 guarded storage registers +constexpr Elf_Word NT_S390_GS_BC = 0x30c; // s390 guarded storage broadcast control block +constexpr Elf_Word NT_ARM_VFP = 0x400; // ARM VFP registers +constexpr Elf_Word NT_ARM_TLS = 0x401; // AArch TLS registers +constexpr Elf_Word NT_ARM_HW_BREAK = 0x402; // AArch hardware breakpoint registers +constexpr Elf_Word NT_ARM_HW_WATCH = 0x403; // AArch hardware watchpoint registers +constexpr Elf_Word NT_ARM_SVE = 0x405; // AArch SVE registers. +constexpr Elf_Word NT_ARM_PAC_MASK = 0x406; // AArch pointer authentication code masks +constexpr Elf_Word NT_ARM_PACA_KEYS = 0x407; // ARM pointer authentication address keys +constexpr Elf_Word NT_ARM_PACG_KEYS = 0x408; // ARM pointer authentication generic keys +constexpr Elf_Word NT_ARM_TAGGED_ADDR_CTRL = 0x409; // AArch64 tagged address control (prctl()) +constexpr Elf_Word NT_ARM_PAC_ENABLED_KEYS = 0x40a; // AArch64 pointer authentication enabled keys (prctl()) +constexpr Elf_Word NT_ARC_V2 = 0x600; // ARC HS accumulator/extra registers. +constexpr Elf_Word NT_LARCH_CPUCFG = 0xa00; // LoongArch CPU config registers +constexpr Elf_Word NT_LARCH_CSR = 0xa01; // LoongArch Control State Registers +constexpr Elf_Word NT_LARCH_LSX = 0xa02; // LoongArch SIMD eXtension registers +constexpr Elf_Word NT_LARCH_LASX = 0xa03; // LoongArch Advanced SIMD eXtension registers +constexpr Elf_Word NT_RISCV_CSR = 0x900; // RISC-V Control and Status Registers + +// Note name must be "CORE" +constexpr Elf_Word NT_LARCH_LBT = 0xa04; // LoongArch Binary Translation registers + +/* The range 0xff000000 to 0xffffffff is set aside for notes that don't + originate from any particular operating system. */ +constexpr Elf_Word NT_GDB_TDESC = 0xff000000; // Contains copy of GDB's target description XML. +constexpr Elf_Word NT_MEMTAG = 0xff000001; // Contains a copy of the memory tags. +/* ARM-specific NT_MEMTAG types. */ +constexpr Elf_Word NT_MEMTAG_TYPE_AARCH_MTE = 0x400; // MTE memory tags for AArch64. + +constexpr Elf_Word NT_STAPSDT = 3; // Note segment for SystemTap probes. + +// Note name is "FreeBSD" +constexpr Elf_Word NT_FREEBSD_THRMISC = 7; // Thread miscellaneous info. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_PROC = 8; // Procstat proc data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_FILES = 9; // Procstat files data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_VMMAP = 10; // Procstat vmmap data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_GROUPS = 11; // Procstat groups data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_UMASK = 12; // Procstat umask data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_RLIMIT = 13; // Procstat rlimit data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_OSREL = 14; // Procstat osreldate data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_PSSTRINGS = 15; // Procstat ps_strings data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_AUXV = 16; // Procstat auxv data. +constexpr Elf_Word NT_FREEBSD_PTLWPINFO = 17; // Thread ptrace miscellaneous info. + +// Note name must start with "NetBSD-CORE" +constexpr Elf_Word NT_NETBSDCORE_PROCINFO = 1; // Has a struct procinfo +constexpr Elf_Word NT_NETBSDCORE_AUXV = 2; // Has auxv data +constexpr Elf_Word NT_NETBSDCORE_LWPSTATUS = 24; // Has LWPSTATUS data +constexpr Elf_Word NT_NETBSDCORE_FIRSTMACH = 32; // start of machdep note types + +// Note name is "OpenBSD" +constexpr Elf_Word NT_OPENBSD_PROCINFO = 10; +constexpr Elf_Word NT_OPENBSD_AUXV = 11; +constexpr Elf_Word NT_OPENBSD_REGS = 20; +constexpr Elf_Word NT_OPENBSD_FPREGS = 21; +constexpr Elf_Word NT_OPENBSD_XFPREGS = 22; +constexpr Elf_Word NT_OPENBSD_WCOOKIE = 23; + +// Note name must start with "SPU" +constexpr Elf_Word NT_SPU = 1; + +// Values of note segment descriptor types for object files +constexpr Elf_Word NT_VERSION = 1; // Contains a version string. +constexpr Elf_Word NT_ARCH = 2; // Contains an architecture string. +constexpr Elf_Word NT_GO_BUILDID = 4; // Contains GO buildid data. + +// Values for notes in non-core files using name "GNU" +constexpr Elf_Word NT_GNU_ABI_TAG = 1; +constexpr Elf_Word NT_GNU_HWCAP = 2; // Used by ld.so and kernel vDSO. +constexpr Elf_Word NT_GNU_BUILD_ID = 3; // Generated by ld --build-id. +constexpr Elf_Word NT_GNU_GOLD_VERSION = 4; // Generated by gold. +constexpr Elf_Word NT_GNU_PROPERTY_TYPE_0 = 5; // Generated by gcc. +// clang-format on + +constexpr Elf_Word NT_GNU_BUILD_ATTRIBUTE_OPEN = 0x100; +constexpr Elf_Word NT_GNU_BUILD_ATTRIBUTE_FUNC = 0x101; + +// Symbol types +constexpr Elf_Word STT_NOTYPE = 0; +constexpr Elf_Word STT_OBJECT = 1; +constexpr Elf_Word STT_FUNC = 2; +constexpr Elf_Word STT_SECTION = 3; +constexpr Elf_Word STT_FILE = 4; +constexpr Elf_Word STT_COMMON = 5; +constexpr Elf_Word STT_TLS = 6; +constexpr Elf_Word STT_LOOS = 10; +constexpr Elf_Word STT_AMDGPU_HSA_KERNEL = 10; +constexpr Elf_Word STT_HIOS = 12; +constexpr Elf_Word STT_LOPROC = 13; +constexpr Elf_Word STT_HIPROC = 15; + +// Symbol visibility +constexpr unsigned char STV_DEFAULT = 0; +constexpr unsigned char STV_INTERNAL = 1; +constexpr unsigned char STV_HIDDEN = 2; +constexpr unsigned char STV_PROTECTED = 3; + +// Undefined name +constexpr Elf_Word STN_UNDEF = 0; + +// Relocation types +// X86 +constexpr unsigned R_386_NONE = 0; +constexpr unsigned R_X86_64_NONE = 0; +constexpr unsigned R_AMDGPU_NONE = 0; +constexpr unsigned R_386_32 = 1; +constexpr unsigned R_X86_64_64 = 1; +constexpr unsigned R_AMDGPU_ABS32_LO = 1; +constexpr unsigned R_386_PC32 = 2; +constexpr unsigned R_X86_64_PC32 = 2; +constexpr unsigned R_AMDGPU_ABS32_HI = 2; +constexpr unsigned R_386_GOT32 = 3; +constexpr unsigned R_X86_64_GOT32 = 3; +constexpr unsigned R_AMDGPU_ABS64 = 3; +constexpr unsigned R_386_PLT32 = 4; +constexpr unsigned R_X86_64_PLT32 = 4; +constexpr unsigned R_AMDGPU_REL32 = 4; +constexpr unsigned R_386_COPY = 5; +constexpr unsigned R_X86_64_COPY = 5; +constexpr unsigned R_AMDGPU_REL64 = 5; +constexpr unsigned R_386_GLOB_DAT = 6; +constexpr unsigned R_X86_64_GLOB_DAT = 6; +constexpr unsigned R_AMDGPU_ABS32 = 6; +constexpr unsigned R_386_JMP_SLOT = 7; +constexpr unsigned R_X86_64_JUMP_SLOT = 7; +constexpr unsigned R_AMDGPU_GOTPCREL = 7; +constexpr unsigned R_386_RELATIVE = 8; +constexpr unsigned R_X86_64_RELATIVE = 8; +constexpr unsigned R_AMDGPU_GOTPCREL32_LO = 8; +constexpr unsigned R_386_GOTOFF = 9; +constexpr unsigned R_X86_64_GOTPCREL = 9; +constexpr unsigned R_AMDGPU_GOTPCREL32_HI = 9; +constexpr unsigned R_386_GOTPC = 10; +constexpr unsigned R_X86_64_32 = 10; +constexpr unsigned R_AMDGPU_REL32_LO = 10; +constexpr unsigned R_386_32PLT = 11; +constexpr unsigned R_X86_64_32S = 11; +constexpr unsigned R_AMDGPU_REL32_HI = 11; +constexpr unsigned R_X86_64_16 = 12; +constexpr unsigned R_X86_64_PC16 = 13; +constexpr unsigned R_AMDGPU_RELATIVE64 = 13; +constexpr unsigned R_386_TLS_TPOFF = 14; +constexpr unsigned R_X86_64_8 = 14; +constexpr unsigned R_386_TLS_IE = 15; +constexpr unsigned R_X86_64_PC8 = 15; +constexpr unsigned R_386_TLS_GOTIE = 16; +constexpr unsigned R_X86_64_DTPMOD64 = 16; +constexpr unsigned R_386_TLS_LE = 17; +constexpr unsigned R_X86_64_DTPOFF64 = 17; +constexpr unsigned R_386_TLS_GD = 18; +constexpr unsigned R_X86_64_TPOFF64 = 18; +constexpr unsigned R_386_TLS_LDM = 19; +constexpr unsigned R_X86_64_TLSGD = 19; +constexpr unsigned R_386_16 = 20; +constexpr unsigned R_X86_64_TLSLD = 20; +constexpr unsigned R_386_PC16 = 21; +constexpr unsigned R_X86_64_DTPOFF32 = 21; +constexpr unsigned R_386_8 = 22; +constexpr unsigned R_X86_64_GOTTPOFF = 22; +constexpr unsigned R_386_PC8 = 23; +constexpr unsigned R_X86_64_TPOFF32 = 23; +constexpr unsigned R_386_TLS_GD_32 = 24; +constexpr unsigned R_X86_64_PC64 = 24; +constexpr unsigned R_386_TLS_GD_PUSH = 25; +constexpr unsigned R_X86_64_GOTOFF64 = 25; +constexpr unsigned R_386_TLS_GD_CALL = 26; +constexpr unsigned R_X86_64_GOTPC32 = 26; +constexpr unsigned R_386_TLS_GD_POP = 27; +constexpr unsigned R_X86_64_GOT64 = 27; +constexpr unsigned R_386_TLS_LDM_32 = 28; +constexpr unsigned R_X86_64_GOTPCREL64 = 28; +constexpr unsigned R_386_TLS_LDM_PUSH = 29; +constexpr unsigned R_X86_64_GOTPC64 = 29; +constexpr unsigned R_386_TLS_LDM_CALL = 30; +constexpr unsigned R_X86_64_GOTPLT64 = 30; +constexpr unsigned R_386_TLS_LDM_POP = 31; +constexpr unsigned R_X86_64_PLTOFF64 = 31; +constexpr unsigned R_386_TLS_LDO_32 = 32; +constexpr unsigned R_386_TLS_IE_32 = 33; +constexpr unsigned R_386_TLS_LE_32 = 34; +constexpr unsigned R_X86_64_GOTPC32_TLSDESC = 34; +constexpr unsigned R_386_TLS_DTPMOD32 = 35; +constexpr unsigned R_X86_64_TLSDESC_CALL = 35; +constexpr unsigned R_386_TLS_DTPOFF32 = 36; +constexpr unsigned R_X86_64_TLSDESC = 36; +constexpr unsigned R_386_TLS_TPOFF32 = 37; +constexpr unsigned R_X86_64_IRELATIVE = 37; +constexpr unsigned R_386_SIZE32 = 38; +constexpr unsigned R_386_TLS_GOTDESC = 39; +constexpr unsigned R_386_TLS_DESC_CALL = 40; +constexpr unsigned R_386_TLS_DESC = 41; +constexpr unsigned R_386_IRELATIVE = 42; +constexpr unsigned R_386_GOT32X = 43; +constexpr unsigned R_X86_64_GNU_VTINHERIT = 250; +constexpr unsigned R_X86_64_GNU_VTENTRY = 251; +// Arm +constexpr unsigned R_ARM_NONE = 0; +constexpr unsigned R_ARM_PC24 = 1; +constexpr unsigned R_ARM_ABS32 = 2; +constexpr unsigned R_ARM_REL32 = 3; +constexpr unsigned R_ARM_CALL = 28; +constexpr unsigned R_ARM_JUMP24 = 29; +constexpr unsigned R_ARM_TARGET1 = 38; +constexpr unsigned R_ARM_V4BX = 40; +constexpr unsigned R_ARM_PREL31 = 42; +constexpr unsigned R_ARM_MOVW_ABS_NC = 43; +constexpr unsigned R_ARM_MOVT_ABS = 44; +constexpr unsigned R_ARM_MOVW_PREL_NC = 45; +constexpr unsigned R_ARM_MOVT_PREL = 46; +constexpr unsigned R_ARM_ALU_PC_G0_NC = 57; +constexpr unsigned R_ARM_ALU_PC_G1_NC = 59; +constexpr unsigned R_ARM_LDR_PC_G2 = 63; +// Arm thumb +constexpr unsigned R_ARM_THM_CALL = 10; +constexpr unsigned R_ARM_THM_JUMP24 = 30; +constexpr unsigned R_ARM_THM_MOVW_ABS_NC = 47; +constexpr unsigned R_ARM_THM_MOVT_ABS = 48; +constexpr unsigned R_ARM_THM_MOVW_PREL_NC = 49; +constexpr unsigned R_ARM_THM_MOVT_PREL = 50; +// AArch64 +constexpr unsigned R_AARCH64_NONE = 0; +constexpr unsigned R_AARCH64_P32_ABS32 = 1; +constexpr unsigned R_AARCH64_P32_COPY = 180; +constexpr unsigned R_AARCH64_P32_GLOB_DAT = 181; +constexpr unsigned R_AARCH64_P32_JUMP_SLOT = 182; +constexpr unsigned R_AARCH64_P32_RELATIVE = 183; +constexpr unsigned R_AARCH64_P32_TLS_DTPMOD = 184; +constexpr unsigned R_AARCH64_P32_TLS_DTPREL = 185; +constexpr unsigned R_AARCH64_P32_TLS_TPREL = 186; +constexpr unsigned R_AARCH64_P32_TLSDESC = 187; +constexpr unsigned R_AARCH64_P32_IRELATIVE = 188; +constexpr unsigned R_AARCH64_ABS64 = 257; +constexpr unsigned R_AARCH64_ABS32 = 258; +constexpr unsigned R_AARCH64_ABS16 = 259; +constexpr unsigned R_AARCH64_PREL64 = 260; +constexpr unsigned R_AARCH64_PREL32 = 261; +constexpr unsigned R_AARCH64_PREL16 = 262; +constexpr unsigned R_AARCH64_MOVW_UABS_G0 = 263; +constexpr unsigned R_AARCH64_MOVW_UABS_G0_NC = 264; +constexpr unsigned R_AARCH64_MOVW_UABS_G1 = 265; +constexpr unsigned R_AARCH64_MOVW_UABS_G1_NC = 266; +constexpr unsigned R_AARCH64_MOVW_UABS_G2 = 267; +constexpr unsigned R_AARCH64_MOVW_UABS_G2_NC = 268; +constexpr unsigned R_AARCH64_MOVW_UABS_G3 = 269; +constexpr unsigned R_AARCH64_MOVW_SABS_G0 = 270; +constexpr unsigned R_AARCH64_MOVW_SABS_G1 = 271; +constexpr unsigned R_AARCH64_MOVW_SABS_G2 = 272; +constexpr unsigned R_AARCH64_LD_PREL_LO19 = 273; +constexpr unsigned R_AARCH64_ADR_PREL_LO21 = 274; +constexpr unsigned R_AARCH64_ADR_PREL_PG_HI21 = 275; +constexpr unsigned R_AARCH64_ADR_PREL_PG_HI21_NC = 276; +constexpr unsigned R_AARCH64_ADD_ABS_LO12_NC = 277; +constexpr unsigned R_AARCH64_LDST8_ABS_LO12_NC = 278; +constexpr unsigned R_AARCH64_TSTBR14 = 279; +constexpr unsigned R_AARCH64_CONDBR19 = 280; +constexpr unsigned R_AARCH64_JUMP26 = 282; +constexpr unsigned R_AARCH64_CALL26 = 283; +constexpr unsigned R_AARCH64_LDST16_ABS_LO12_NC = 284; +constexpr unsigned R_AARCH64_LDST32_ABS_LO12_NC = 285; +constexpr unsigned R_AARCH64_LDST64_ABS_LO12_NC = 286; +constexpr unsigned R_AARCH64_MOVW_PREL_G0 = 287; +constexpr unsigned R_AARCH64_MOVW_PREL_G0_NC = 288; +constexpr unsigned R_AARCH64_MOVW_PREL_G1 = 289; +constexpr unsigned R_AARCH64_MOVW_PREL_G1_NC = 290; +constexpr unsigned R_AARCH64_MOVW_PREL_G2 = 291; +constexpr unsigned R_AARCH64_MOVW_PREL_G2_NC = 292; +constexpr unsigned R_AARCH64_MOVW_PREL_G3 = 293; +constexpr unsigned R_AARCH64_LDST128_ABS_LO12_NC = 299; +constexpr unsigned R_AARCH64_MOVW_GOTOFF_G0 = 300; +constexpr unsigned R_AARCH64_MOVW_GOTOFF_G0_NC = 301; +constexpr unsigned R_AARCH64_MOVW_GOTOFF_G1 = 302; +constexpr unsigned R_AARCH64_MOVW_GOTOFF_G1_NC = 303; +constexpr unsigned R_AARCH64_MOVW_GOTOFF_G2 = 304; +constexpr unsigned R_AARCH64_MOVW_GOTOFF_G2_NC = 305; +constexpr unsigned R_AARCH64_MOVW_GOTOFF_G3 = 306; +constexpr unsigned R_AARCH64_GOTREL64 = 307; +constexpr unsigned R_AARCH64_GOTREL32 = 308; +constexpr unsigned R_AARCH64_GOT_LD_PREL19 = 309; +constexpr unsigned R_AARCH64_LD64_GOTOFF_LO15 = 310; +constexpr unsigned R_AARCH64_ADR_GOT_PAGE = 311; +constexpr unsigned R_AARCH64_LD64_GOT_LO12_NC = 312; +constexpr unsigned R_AARCH64_LD64_GOTPAGE_LO15 = 313; +constexpr unsigned R_AARCH64_TLSGD_ADR_PREL21 = 512; +constexpr unsigned R_AARCH64_TLSGD_ADR_PAGE21 = 513; +constexpr unsigned R_AARCH64_TLSGD_ADD_LO12_NC = 514; +constexpr unsigned R_AARCH64_TLSGD_MOVW_G1 = 515; +constexpr unsigned R_AARCH64_TLSGD_MOVW_G0_NC = 516; +constexpr unsigned R_AARCH64_TLSLD_ADR_PREL21 = 517; +constexpr unsigned R_AARCH64_TLSLD_ADR_PAGE21 = 518; +constexpr unsigned R_AARCH64_TLSLD_ADD_LO12_NC = 519; +constexpr unsigned R_AARCH64_TLSLD_MOVW_G1 = 520; +constexpr unsigned R_AARCH64_TLSLD_MOVW_G0_NC = 521; +constexpr unsigned R_AARCH64_TLSLD_LD_PREL19 = 522; +constexpr unsigned R_AARCH64_TLSLD_MOVW_DTPREL_G2 = 523; +constexpr unsigned R_AARCH64_TLSLD_MOVW_DTPREL_G1 = 524; +constexpr unsigned R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC = 525; +constexpr unsigned R_AARCH64_TLSLD_MOVW_DTPREL_G0 = 526; +constexpr unsigned R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC = 527; +constexpr unsigned R_AARCH64_TLSLD_ADD_DTPREL_HI12 = 528; +constexpr unsigned R_AARCH64_TLSLD_ADD_DTPREL_LO12 = 529; +constexpr unsigned R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC = 530; +constexpr unsigned R_AARCH64_TLSLD_LDST8_DTPREL_LO12 = 531; +constexpr unsigned R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC = 532; +constexpr unsigned R_AARCH64_TLSLD_LDST16_DTPREL_LO12 = 533; +constexpr unsigned R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC = 534; +constexpr unsigned R_AARCH64_TLSLD_LDST32_DTPREL_LO12 = 535; +constexpr unsigned R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC = 536; +constexpr unsigned R_AARCH64_TLSLD_LDST64_DTPREL_LO12 = 537; +constexpr unsigned R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC = 538; +constexpr unsigned R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 = 539; +constexpr unsigned R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC = 540; +constexpr unsigned R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 = 541; +constexpr unsigned R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC = 542; +constexpr unsigned R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 = 543; +constexpr unsigned R_AARCH64_TLSLE_MOVW_TPREL_G2 = 544; +constexpr unsigned R_AARCH64_TLSLE_MOVW_TPREL_G1 = 545; +constexpr unsigned R_AARCH64_TLSLE_MOVW_TPREL_G1_NC = 546; +constexpr unsigned R_AARCH64_TLSLE_MOVW_TPREL_G0 = 547; +constexpr unsigned R_AARCH64_TLSLE_MOVW_TPREL_G0_NC = 548; +constexpr unsigned R_AARCH64_TLSLE_ADD_TPREL_HI12 = 549; +constexpr unsigned R_AARCH64_TLSLE_ADD_TPREL_LO12 = 550; +constexpr unsigned R_AARCH64_TLSLE_ADD_TPREL_LO12_NC = 551; +constexpr unsigned R_AARCH64_TLSLE_LDST8_TPREL_LO12 = 552; +constexpr unsigned R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC = 553; +constexpr unsigned R_AARCH64_TLSLE_LDST16_TPREL_LO12 = 554; +constexpr unsigned R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC = 555; +constexpr unsigned R_AARCH64_TLSLE_LDST32_TPREL_LO12 = 556; +constexpr unsigned R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC = 557; +constexpr unsigned R_AARCH64_TLSLE_LDST64_TPREL_LO12 = 558; +constexpr unsigned R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC = 559; +constexpr unsigned R_AARCH64_TLSDESC_LD_PREL19 = 560; +constexpr unsigned R_AARCH64_TLSDESC_ADR_PREL21 = 561; +constexpr unsigned R_AARCH64_TLSDESC_ADR_PAGE21 = 562; +constexpr unsigned R_AARCH64_TLSDESC_LD64_LO12 = 563; +constexpr unsigned R_AARCH64_TLSDESC_ADD_LO12 = 564; +constexpr unsigned R_AARCH64_TLSDESC_OFF_G1 = 565; +constexpr unsigned R_AARCH64_TLSDESC_OFF_G0_NC = 566; +constexpr unsigned R_AARCH64_TLSDESC_LDR = 567; +constexpr unsigned R_AARCH64_TLSDESC_ADD = 568; +constexpr unsigned R_AARCH64_TLSDESC_CALL = 569; +constexpr unsigned R_AARCH64_TLSLE_LDST128_TPREL_LO12 = 570; +constexpr unsigned R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC = 571; +constexpr unsigned R_AARCH64_TLSLD_LDST128_DTPREL_LO12 = 572; +constexpr unsigned R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC = 573; +constexpr unsigned R_AARCH64_COPY = 1024; +constexpr unsigned R_AARCH64_GLOB_DAT = 1025; +constexpr unsigned R_AARCH64_JUMP_SLOT = 1026; +constexpr unsigned R_AARCH64_RELATIVE = 1027; +constexpr unsigned R_AARCH64_TLS_DTPMOD = 1028; +constexpr unsigned R_AARCH64_TLS_DTPMOD64 = 1028; +constexpr unsigned R_AARCH64_TLS_DTPREL = 1029; +constexpr unsigned R_AARCH64_TLS_DTPREL64 = 1029; +constexpr unsigned R_AARCH64_TLS_TPREL = 1030; +constexpr unsigned R_AARCH64_TLS_TPREL64 = 1030; +constexpr unsigned R_AARCH64_TLSDESC = 1031; +// RISC-V +constexpr unsigned R_RISCV_NONE = 0; +constexpr unsigned R_RISCV_32 = 1; +constexpr unsigned R_RISCV_64 = 2; +constexpr unsigned R_RISCV_RELATIVE = 3; +constexpr unsigned R_RISCV_COPY = 4; +constexpr unsigned R_RISCV_JUMP_SLOT = 5; +constexpr unsigned R_RISCV_TLS_DTPMOD32 = 6; +constexpr unsigned R_RISCV_TLS_DTPMOD64 = 7; +constexpr unsigned R_RISCV_TLS_DTPREL32 = 8; +constexpr unsigned R_RISCV_TLS_DTPREL64 = 9; +constexpr unsigned R_RISCV_TLS_TPREL32 = 10; +constexpr unsigned R_RISCV_TLS_TPREL64 = 11; +constexpr unsigned R_RISCV_BRANCH = 16; +constexpr unsigned R_RISCV_JAL = 17; +constexpr unsigned R_RISCV_CALL = 18; +constexpr unsigned R_RISCV_CALL_PLT = 19; +constexpr unsigned R_RISCV_GOT_HI20 = 20; +constexpr unsigned R_RISCV_TLS_GOT_HI20 = 21; +constexpr unsigned R_RISCV_TLS_GD_HI20 = 22; +constexpr unsigned R_RISCV_PCREL_HI20 = 23; +constexpr unsigned R_RISCV_PCREL_LO12_I = 24; +constexpr unsigned R_RISCV_PCREL_LO12_S = 25; +constexpr unsigned R_RISCV_HI20 = 26; +constexpr unsigned R_RISCV_LO12_I = 27; +constexpr unsigned R_RISCV_LO12_S = 28; +constexpr unsigned R_RISCV_TPREL_HI20 = 29; +constexpr unsigned R_RISCV_TPREL_LO12_I = 30; +constexpr unsigned R_RISCV_TPREL_LO12_S = 31; +constexpr unsigned R_RISCV_TPREL_ADD = 32; +constexpr unsigned R_RISCV_ADD8 = 33; +constexpr unsigned R_RISCV_ADD16 = 34; +constexpr unsigned R_RISCV_ADD32 = 35; +constexpr unsigned R_RISCV_ADD64 = 36; +constexpr unsigned R_RISCV_SUB8 = 37; +constexpr unsigned R_RISCV_SUB16 = 38; +constexpr unsigned R_RISCV_SUB32 = 39; +constexpr unsigned R_RISCV_SUB64 = 40; +constexpr unsigned R_RISCV_GNU_VTINHERIT = 41; +constexpr unsigned R_RISCV_GNU_VTENTRY = 42; +constexpr unsigned R_RISCV_ALIGN = 43; +constexpr unsigned R_RISCV_RVC_BRANCH = 44; +constexpr unsigned R_RISCV_RVC_JUMP = 45; +constexpr unsigned R_RISCV_RVC_LUI = 46; +constexpr unsigned R_RISCV_RELAX = 51; +constexpr unsigned R_RISCV_SUB6 = 52; +constexpr unsigned R_RISCV_SET6 = 53; +constexpr unsigned R_RISCV_SET8 = 54; +constexpr unsigned R_RISCV_SET16 = 55; +constexpr unsigned R_RISCV_SET32 = 56; +constexpr unsigned R_RISCV_32_PCREL = 57; +constexpr unsigned R_RISCV_IRELATIVE = 58; + +// Segment types +constexpr Elf_Word PT_NULL = 0; +constexpr Elf_Word PT_LOAD = 1; +constexpr Elf_Word PT_DYNAMIC = 2; +constexpr Elf_Word PT_INTERP = 3; +constexpr Elf_Word PT_NOTE = 4; +constexpr Elf_Word PT_SHLIB = 5; +constexpr Elf_Word PT_PHDR = 6; +constexpr Elf_Word PT_TLS = 7; +constexpr Elf_Word PT_LOOS = 0X60000000; +constexpr Elf_Word PT_GNU_EH_FRAME = 0X6474E550; // Frame unwind information +constexpr Elf_Word PT_GNU_STACK = 0X6474E551; // Stack flags +constexpr Elf_Word PT_GNU_RELRO = 0X6474E552; // Read only after relocs +constexpr Elf_Word PT_GNU_PROPERTY = 0X6474E553; // GNU property +constexpr Elf_Word PT_GNU_MBIND_LO = 0X6474E555; // Mbind segments start +constexpr Elf_Word PT_GNU_MBIND_HI = 0X6474F554; // Mbind segments finish +constexpr Elf_Word PT_PAX_FLAGS = 0X65041580; +constexpr Elf_Word PT_OPENBSD_RANDOMIZE = 0X65A3DBE6; +constexpr Elf_Word PT_OPENBSD_WXNEEDED = 0X65A3DBE7; +constexpr Elf_Word PT_OPENBSD_BOOTDATA = 0X65A41BE6; +constexpr Elf_Word PT_SUNWBSS = 0X6FFFFFFA; +constexpr Elf_Word PT_SUNWSTACK = 0X6FFFFFFB; +constexpr Elf_Word PT_HIOS = 0X6FFFFFFF; +constexpr Elf_Word PT_LOPROC = 0X70000000; +constexpr Elf_Word PT_HIPROC = 0X7FFFFFFF; + +// Segment flags +constexpr Elf_Word PF_X = 1; // Execute +constexpr Elf_Word PF_W = 2; // Write +constexpr Elf_Word PF_R = 4; // Read +constexpr Elf_Word PF_MASKOS = 0x0ff00000; // Unspecified +constexpr Elf_Word PF_MASKPROC = 0xf0000000; // Unspecified + +// Dynamic Array Tags +constexpr Elf_Word DT_NULL = 0; +constexpr Elf_Word DT_NEEDED = 1; +constexpr Elf_Word DT_PLTRELSZ = 2; +constexpr Elf_Word DT_PLTGOT = 3; +constexpr Elf_Word DT_HASH = 4; +constexpr Elf_Word DT_STRTAB = 5; +constexpr Elf_Word DT_SYMTAB = 6; +constexpr Elf_Word DT_RELA = 7; +constexpr Elf_Word DT_RELASZ = 8; +constexpr Elf_Word DT_RELAENT = 9; +constexpr Elf_Word DT_STRSZ = 10; +constexpr Elf_Word DT_SYMENT = 11; +constexpr Elf_Word DT_INIT = 12; +constexpr Elf_Word DT_FINI = 13; +constexpr Elf_Word DT_SONAME = 14; +constexpr Elf_Word DT_RPATH = 15; +constexpr Elf_Word DT_SYMBOLIC = 16; +constexpr Elf_Word DT_REL = 17; +constexpr Elf_Word DT_RELSZ = 18; +constexpr Elf_Word DT_RELENT = 19; +constexpr Elf_Word DT_PLTREL = 20; +constexpr Elf_Word DT_DEBUG = 21; +constexpr Elf_Word DT_TEXTREL = 22; +constexpr Elf_Word DT_JMPREL = 23; +constexpr Elf_Word DT_BIND_NOW = 24; +constexpr Elf_Word DT_INIT_ARRAY = 25; +constexpr Elf_Word DT_FINI_ARRAY = 26; +constexpr Elf_Word DT_INIT_ARRAYSZ = 27; +constexpr Elf_Word DT_FINI_ARRAYSZ = 28; +constexpr Elf_Word DT_RUNPATH = 29; +constexpr Elf_Word DT_FLAGS = 30; +constexpr Elf_Word DT_ENCODING = 32; +constexpr Elf_Word DT_PREINIT_ARRAY = 32; +constexpr Elf_Word DT_PREINIT_ARRAYSZ = 33; +constexpr Elf_Word DT_MAXPOSTAGS = 34; +constexpr Elf_Word DT_LOOS = 0x6000000D; +constexpr Elf_Word DT_HIOS = 0x6ffff000; +constexpr Elf_Word DT_GNU_HASH = 0x6ffffef5; +constexpr Elf_Word DT_TLSDESC_PLT = 0x6ffffef6; +constexpr Elf_Word DT_TLSDESC_GOT = 0x6ffffef7; +constexpr Elf_Word DT_GNU_CONFLICT = 0x6ffffef8; +constexpr Elf_Word DT_GNU_LIBLIST = 0x6ffffef9; +constexpr Elf_Word DT_CONFIG = 0x6ffffefa; +constexpr Elf_Word DT_DEPAUDIT = 0x6ffffefb; +constexpr Elf_Word DT_AUDIT = 0x6ffffefc; +constexpr Elf_Word DT_PLTPAD = 0x6ffffefd; +constexpr Elf_Word DT_MOVETAB = 0x6ffffefe; +constexpr Elf_Word DT_SYMINFO = 0x6ffffeff; +constexpr Elf_Word DT_ADDRRNGHI = 0x6ffffeff; +constexpr Elf_Word DT_VERSYM = 0x6ffffff0; +constexpr Elf_Word DT_RELACOUNT = 0x6ffffff9; +constexpr Elf_Word DT_RELCOUNT = 0x6ffffffa; +constexpr Elf_Word DT_FLAGS_1 = 0x6ffffffb; +constexpr Elf_Word DT_VERDEF = 0x6ffffffc; +constexpr Elf_Word DT_VERDEFNUM = 0x6ffffffd; +constexpr Elf_Word DT_VERNEED = 0x6ffffffe; +constexpr Elf_Word DT_VERNEEDNUM = 0x6fffffff; +constexpr Elf_Word DT_LOPROC = 0x70000000; +constexpr Elf_Word DT_HIPROC = 0x7FFFFFFF; + +// DT_FLAGS values +constexpr Elf_Word DF_ORIGIN = 0x1; +constexpr Elf_Word DF_SYMBOLIC = 0x2; +constexpr Elf_Word DF_TEXTREL = 0x4; +constexpr Elf_Word DF_BIND_NOW = 0x8; +constexpr Elf_Word DF_STATIC_TLS = 0x10; + +// Legal values for d_tag (dynamic entry type). +constexpr Elf_Word AT_NULL = 0; // End of vector +constexpr Elf_Word AT_IGNORE = 1; // Entry should be ignored +constexpr Elf_Word AT_EXECFD = 2; // File descriptor of program +constexpr Elf_Word AT_PHDR = 3; // Program headers for program +constexpr Elf_Word AT_PHENT = 4; // Size of program header entry +constexpr Elf_Word AT_PHNUM = 5; // Number of program headers +constexpr Elf_Word AT_PAGESZ = 6; // System page size +constexpr Elf_Word AT_BASE = 7; // Base address of interpreter +constexpr Elf_Word AT_FLAGS = 8; // Flags +constexpr Elf_Word AT_ENTRY = 9; // Entry point of program +constexpr Elf_Word AT_NOTELF = 10; // Program is not ELF +constexpr Elf_Word AT_UID = 11; // Real uid +constexpr Elf_Word AT_EUID = 12; // Effective uid +constexpr Elf_Word AT_GID = 13; // Real gid +constexpr Elf_Word AT_EGID = 14; // Effective gid +constexpr Elf_Word AT_CLKTCK = 17; // Frequency of times() +constexpr Elf_Word AT_PLATFORM = 15; // String identifying platform. +constexpr Elf_Word AT_HWCAP = 16; // Hints about processor capabilities. +constexpr Elf_Word AT_FPUCW = 18; // Used FPU control word. +constexpr Elf_Word AT_DCACHEBSIZE = 19; // Data cache block size. +constexpr Elf_Word AT_ICACHEBSIZE = 20; // Instruction cache block size. +constexpr Elf_Word AT_UCACHEBSIZE = 21; // Unified cache block size. +constexpr Elf_Word AT_IGNOREPPC = 22; // Entry should be ignored. +constexpr Elf_Word AT_SECURE = 23; // Boolean, was exec setuid-like? +constexpr Elf_Word AT_BASE_PLATFORM = 24; // String identifying real platforms. +constexpr Elf_Word AT_RANDOM = 25; // Address of 16 random bytes. +constexpr Elf_Word AT_HWCAP2 = 26; // More hints about processor capabilities. +constexpr Elf_Word AT_EXECFN = 31; // Filename of executable. +constexpr Elf_Word AT_SYSINFO = 32; // EP to the system call in the vDSO. +constexpr Elf_Word AT_SYSINFO_EHDR = 33; // Start of the ELF header of the vDSO. +constexpr Elf_Word AT_L1I_CACHESHAPE = 34; +constexpr Elf_Word AT_L1D_CACHESHAPE = 35; +constexpr Elf_Word AT_L2_CACHESHAPE = 36; +constexpr Elf_Word AT_L3_CACHESHAPE = 37; +constexpr Elf_Word AT_L1I_CACHESIZE = 40; +constexpr Elf_Word AT_L1I_CACHEGEOMETRY = 41; +constexpr Elf_Word AT_L1D_CACHESIZE = 42; +constexpr Elf_Word AT_L1D_CACHEGEOMETRY = 43; +constexpr Elf_Word AT_L2_CACHESIZE = 44; +constexpr Elf_Word AT_L2_CACHEGEOMETRY = 45; +constexpr Elf_Word AT_L3_CACHESIZE = 46; + +// ELF file header +struct Elf32_Ehdr +{ + // Identification bytes + unsigned char e_ident[EI_NIDENT]; + // Object file type + Elf_Half e_type; + // Architecture + Elf_Half e_machine; + // Object file version + Elf_Word e_version; + // Entry point virtual address + Elf32_Addr e_entry; + // Program header table file offset + Elf32_Off e_phoff; + // Section header table file offset + Elf32_Off e_shoff; + // Processor-specific flags + Elf_Word e_flags; + // ELF header size in bytes + Elf_Half e_ehsize; + // Program header table entry size + Elf_Half e_phentsize; + // Program header table entry count + Elf_Half e_phnum; + // Section header table entry size + Elf_Half e_shentsize; + // Section header table entry count + Elf_Half e_shnum; + // Section header string table index + Elf_Half e_shstrndx; +}; + +struct Elf64_Ehdr +{ + // Identification bytes + unsigned char e_ident[EI_NIDENT]; + // Object file type + Elf_Half e_type; + // Architecture + Elf_Half e_machine; + // Object file version + Elf_Word e_version; + // Entry point virtual address + Elf64_Addr e_entry; + // Program header table file offset + Elf64_Off e_phoff; + // Section header table file offset + Elf64_Off e_shoff; + // Processor-specific flags + Elf_Word e_flags; + // ELF header size in bytes + Elf_Half e_ehsize; + // Program header table entry size + Elf_Half e_phentsize; + // Program header table entry count + Elf_Half e_phnum; + // Section header table entry size + Elf_Half e_shentsize; + // Section header table entry count + Elf_Half e_shnum; + // Section header string table index + Elf_Half e_shstrndx; +}; + +// Section header +struct Elf32_Shdr +{ + // Section name (string table index) + Elf_Word sh_name; + // Section type + Elf_Word sh_type; + // Section flags + Elf_Word sh_flags; + // Section virtual address at execution + Elf32_Addr sh_addr; + // Section file offset + Elf32_Off sh_offset; + // Section size in bytes + Elf_Word sh_size; + // Link to another section + Elf_Word sh_link; + // Additional section information + Elf_Word sh_info; + // Section alignment + Elf_Word sh_addralign; + // Entry size if section holds table + Elf_Word sh_entsize; +}; + +struct Elf64_Shdr +{ + // Section name (string table index) + Elf_Word sh_name; + // Section type + Elf_Word sh_type; + // Section flags + Elf_Xword sh_flags; + // Section virtual address at execution + Elf64_Addr sh_addr; + // Section file offset + Elf64_Off sh_offset; + // Section size in bytes + Elf_Xword sh_size; + // Link to another section + Elf_Word sh_link; + // Additional section information + Elf_Word sh_info; + // Section alignment + Elf_Xword sh_addralign; + // Entry size if section holds table + Elf_Xword sh_entsize; +}; + +// Segment header +struct Elf32_Phdr +{ + // Segment type + Elf_Word p_type; + // Segment file offset + Elf32_Off p_offset; + // Segment virtual address at execution + Elf32_Addr p_vaddr; + // Segment physical address + Elf32_Addr p_paddr; + // Segment size in file + Elf_Word p_filesz; + // Segment size in memory + Elf_Word p_memsz; + // Segment flags + Elf_Word p_flags; + // Segment alignment + Elf_Word p_align; +}; + +struct Elf64_Phdr +{ + // Segment type + Elf_Word p_type; + // Segment flags + Elf_Word p_flags; + // Segment file offset + Elf64_Off p_offset; + // Segment virtual address at execution + Elf64_Addr p_vaddr; + // Segment physical address + Elf64_Addr p_paddr; + // Segment size in file + Elf_Xword p_filesz; + // Segment size in memory + Elf_Xword p_memsz; + // Segment alignment + Elf_Xword p_align; +}; + +// Symbol table entry +struct Elf32_Sym +{ + // Symbol name (string table index) + Elf_Word st_name; + // Symbol value + Elf32_Addr st_value; + // Symbol size + Elf_Word st_size; + // Symbol type and binding attributes + unsigned char st_info; + // Symbol visibility + unsigned char st_other; + // Section index + Elf_Half st_shndx; +}; + +struct Elf64_Sym +{ + // Symbol name (string table index) + Elf_Word st_name; + // Symbol type and binding attributes + unsigned char st_info; + // Symbol visibility + unsigned char st_other; + // Section index + Elf_Half st_shndx; + // Symbol value + Elf64_Addr st_value; + // Symbol size + Elf_Xword st_size; +}; + +#define ELF_ST_BIND( i ) ( ( i ) >> 4 ) +#define ELF_ST_TYPE( i ) ( ( i ) & 0xf ) +#define ELF_ST_INFO( b, t ) ( ( ( b ) << 4 ) + ( ( t ) & 0xf ) ) + +#define ELF_ST_VISIBILITY( o ) ( ( o ) & 0x3 ) + +// Relocation entries +struct Elf32_Rel +{ + // Location to apply the relocation action + Elf32_Addr r_offset; + // Relocation type and symbol index + Elf_Word r_info; +}; + +struct Elf32_Rela +{ + // Location to apply the relocation action + Elf32_Addr r_offset; + // Relocation type and symbol index + Elf_Word r_info; + // Constant addend used to compute the value + Elf_Sword r_addend; +}; + +struct Elf64_Rel +{ + // Location to apply the relocation action + Elf64_Addr r_offset; + // Relocation type and symbol index + Elf_Xword r_info; +}; + +struct Elf64_Rela +{ + // Location to apply the relocation action + Elf64_Addr r_offset; + // Relocation type and symbol index + Elf_Xword r_info; + // Constant addend used to compute the value + Elf_Sxword r_addend; +}; + +#define ELF32_R_SYM( i ) ( ( i ) >> 8 ) +#define ELF32_R_TYPE( i ) ( (unsigned char)( i ) ) +#define ELF32_R_INFO( s, t ) ( ( ( s ) << 8 ) + (unsigned char)( t ) ) + +#define ELF64_R_SYM( i ) ( ( i ) >> 32 ) +#define ELF64_R_TYPE( i ) ( ( i ) & 0xffffffffL ) +#define ELF64_R_INFO( s, t ) \ + ( ( ( ( std::int64_t )( s ) ) << 32 ) + ( ( t ) & 0xffffffffL ) ) + +// Dynamic structure +struct Elf32_Dyn +{ + // Dynamic entry type + Elf_Sword d_tag; + union { + // Integer value + Elf_Word d_val; + // Address value + Elf32_Addr d_ptr; + } d_un; +}; + +struct Elf64_Dyn +{ + // Dynamic entry type + Elf_Sxword d_tag; + union { + // Integer value + Elf_Xword d_val; + // Address value + Elf64_Addr d_ptr; + } d_un; +}; + +struct Elfxx_Verdef +{ + // Version revision + Elf_Half vd_version; + // Version information flags + Elf_Half vd_flags; + // Version index + Elf_Half vd_ndx; + // Number of associated aux entries + Elf_Half vd_cnt; + // Version name hash value + Elf_Word vd_hash; + // Offset to verdaux array + Elf_Word vd_aux; + // Offset to next verdef entry + Elf_Word vd_next; +}; + +struct Elfxx_Verdaux +{ + // Version or dependency name + Elf_Word vda_name; + // Offset to next verdaux entry + Elf_Word vda_next; +}; + +struct Elfxx_Verneed +{ + // Version of structure + Elf_Half vn_version; + // Number of associated aux entries + Elf_Half vn_cnt; + // Offset to file name string + Elf_Word vn_file; + // Offset to vernaux array + Elf_Word vn_aux; + // Offset to next verneed entry + Elf_Word vn_next; +}; + +struct Elfxx_Vernaux +{ + // Hash value of dependency name + Elf_Word vna_hash; + // Dependency information flags + Elf_Half vna_flags; + // Dependency index + Elf_Half vna_other; + // Dependency name string offset + Elf_Word vna_name; + // Offset to next vernaux entry + Elf_Word vna_next; +}; + +// ELF auxiliary vectors, they are usually run-time information +// being passed to program when the kernel is loading it. +// This is now required, +// because in order to initialize the stack cookie +// to protect against buffer overflows, +// most of libc ask us to have a valid pointer for the AT_RANDOM entry. +// glibc for example crashes if you don't. +// https://sourceware.org/git/?p=glibc.git;a=blob;f=csu/libc-start.c;h=543560f36c33b07a1fbe1b7e4578374fe8007b1f;hb=HEAD#l308 +// This is also useful to be able to reconstruct at run-time +// the ELF headers, if ELF headers were erased after loading. +// Although this library is targeted to be parsing files only, +// I assume auxiliary vectors could be also used to get +// more information about the ELF binary at run-time in future. +// The main purpose is also for ELF injectors. +struct Elf32_auxv +{ + // Entry type + std::uint32_t a_type; // Entry type + + union { + // Integer value, usually a pointer + std::uint32_t a_val; // Integer value, usually a pointer + } a_un; +}; + +struct Elf64_auxv +{ + // Entry type + std::uint64_t a_type; // Entry type + + union { + // Integer value, usually a pointer + std::uint64_t a_val; // Integer value, usually a pointer + } a_un; +}; + +struct Elf32_Chdr +{ + // The compression algorithm used + Elf32_Word ch_type; // The compression algorithm used + // The size, in bytes, of the uncompressed section data + Elf32_Word ch_size; //The size, in bytes, of the uncompressed section data + // The address alignment of the uncompressed section data + Elf32_Word + ch_addralign; // The address alignment of the uncompressed section data +}; + +struct Elf64_Chdr +{ + //The compression algorithm used + Elf64_Word ch_type; //The compression algorithm used + // Reserved + Elf64_Word ch_reserved; // Reserved + //The size, in bytes, of the uncompressed section data + Elf_Xword ch_size; //The size, in bytes, of the uncompressed section data + //The address alignment of the uncompressed section data + Elf_Xword + ch_addralign; //The address alignment of the uncompressed section data +}; + +#ifdef __cplusplus +} // namespace ELFIO +#endif + +#endif // ELFTYPES_H diff --git a/emulator/include/elfio/elfio.hpp b/emulator/include/elfio/elfio.hpp new file mode 100644 index 0000000..e228776 --- /dev/null +++ b/emulator/include/elfio/elfio.hpp @@ -0,0 +1,1260 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_HPP +#define ELFIO_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define ELFIO_HEADER_ACCESS_GET( TYPE, FNAME ) \ + TYPE get_##FNAME() const { return header ? ( header->get_##FNAME() ) : 0; } + +#define ELFIO_HEADER_ACCESS_GET_SET( TYPE, FNAME ) \ + TYPE get_##FNAME() const \ + { \ + return header ? ( header->get_##FNAME() ) : 0; \ + } \ + void set_##FNAME( TYPE val ) \ + { \ + if ( header ) { \ + header->set_##FNAME( val ); \ + } \ + } + +namespace ELFIO { + +//------------------------------------------------------------------------------ +//! \class elfio +//! \brief The elfio class represents an ELF file and provides methods to manipulate it. +class elfio +{ + public: + //------------------------------------------------------------------------------ + //! \brief Default constructor + elfio() noexcept : sections( this ), segments( this ) + { + convertor = std::make_shared(); + addr_translator = std::make_shared(); + create( ELFCLASS32, ELFDATA2LSB ); + } + + //------------------------------------------------------------------------------ + //! \brief Constructor with compression interface + //! \param compression Pointer to the compression interface + explicit elfio( compression_interface* compression_ptr ) noexcept : elfio() + { + this->compression = + std::shared_ptr( compression_ptr ); + } + + //------------------------------------------------------------------------------ + //! \brief Move constructor + //! \param other The other elfio object to move from + elfio( elfio&& other ) noexcept + : sections( this ), segments( this ), + current_file_pos( other.current_file_pos ) + { + header = std::move( other.header ); + sections_ = std::move( other.sections_ ); + segments_ = std::move( other.segments_ ); + convertor = std::move( other.convertor ); + addr_translator = std::move( other.addr_translator ); + compression = std::move( other.compression ); + + other.header = nullptr; + other.sections_.clear(); + other.segments_.clear(); + other.compression = nullptr; + } + + //------------------------------------------------------------------------------ + //! \brief Move assignment operator + //! \param other The other elfio object to move from + //! \return Reference to this object + elfio& operator=( elfio&& other ) noexcept + { + if ( this != &other ) { + header = std::move( other.header ); + sections_ = std::move( other.sections_ ); + segments_ = std::move( other.segments_ ); + convertor = std::move( other.convertor ); + addr_translator = std::move( other.addr_translator ); + current_file_pos = other.current_file_pos; + compression = std::move( other.compression ); + + other.current_file_pos = 0; + other.header = nullptr; + other.compression = nullptr; + other.sections_.clear(); + other.segments_.clear(); + } + return *this; + } + + //------------------------------------------------------------------------------ + //! \brief Delete copy constructor and copy assignment operator + elfio( const elfio& ) = delete; + elfio& operator=( const elfio& ) = delete; + ~elfio() = default; + + //------------------------------------------------------------------------------ + //! \brief Create a new ELF file with the specified class and encoding + //! \param file_class The class of the ELF file (ELFCLASS32 or ELFCLASS64) + //! \param encoding The encoding of the ELF file (ELFDATA2LSB or ELFDATA2MSB) + void create( unsigned char file_class, unsigned char encoding ) + { + sections_.clear(); + segments_.clear(); + ( *convertor ).setup( encoding ); + header = create_header( file_class, encoding ); + create_mandatory_sections(); + } + + //------------------------------------------------------------------------------ + //! \brief Set address translation + //! \param addr_trans Vector of address translations + void set_address_translation( std::vector& addr_trans ) + { + ( *addr_translator ).set_address_translation( addr_trans ); + } + + //------------------------------------------------------------------------------ + //! \brief Load an ELF file from a file + //! \param file_name The name of the file to load + //! \param is_lazy Whether to load the file lazily + //! \return True if successful, false otherwise + bool load( const std::string& file_name, bool is_lazy = false ) + { + pstream = std::make_unique(); + if ( !pstream ) { + return false; + } + + pstream->open( file_name.c_str(), std::ios::in | std::ios::binary ); + if ( !*pstream ) { + return false; + } + + bool ret = load( *pstream, is_lazy ); + + if ( !is_lazy ) { + pstream.reset(); + } + + return ret; + } + + //------------------------------------------------------------------------------ + //! \brief Load an ELF file from a stream + //! \param stream The input stream to load from + //! \param is_lazy Whether to load the file lazily + //! \return True if successful, false otherwise + bool load( std::istream& stream, bool is_lazy = false ) + { + sections_.clear(); + segments_.clear(); + + std::array e_ident = { 0 }; + // Read ELF file signature + stream.seekg( ( *addr_translator )[0] ); + stream.read( e_ident.data(), sizeof( e_ident ) ); + + // Is it ELF file? + if ( stream.gcount() != sizeof( e_ident ) || + e_ident[EI_MAG0] != ELFMAG0 || e_ident[EI_MAG1] != ELFMAG1 || + e_ident[EI_MAG2] != ELFMAG2 || e_ident[EI_MAG3] != ELFMAG3 ) { + return false; + } + + if ( ( e_ident[EI_CLASS] != ELFCLASS64 ) && + ( e_ident[EI_CLASS] != ELFCLASS32 ) ) { + return false; + } + + if ( ( e_ident[EI_DATA] != ELFDATA2LSB ) && + ( e_ident[EI_DATA] != ELFDATA2MSB ) ) { + return false; + } + + ( *convertor ).setup( e_ident[EI_DATA] ); + header = create_header( e_ident[EI_CLASS], e_ident[EI_DATA] ); + if ( nullptr == header ) { + return false; + } + if ( !header->load( stream ) ) { + return false; + } + + load_sections( stream, is_lazy ); + bool is_still_good = load_segments( stream, is_lazy ); + return is_still_good; + } + + //------------------------------------------------------------------------------ + //! \brief Save the ELF file to a file + //! \param file_name The name of the file to save to + //! \return True if successful, false otherwise + bool save( const std::string& file_name ) + { + std::ofstream stream; + stream.open( file_name.c_str(), std::ios::out | std::ios::binary ); + if ( !stream ) { + return false; + } + + return save( stream ); + } + + //------------------------------------------------------------------------------ + //! \brief Save the ELF file to a stream + //! \param stream The output stream to save to + //! \return True if successful, false otherwise + bool save( std::ostream& stream ) + { + if ( !stream || header == nullptr ) { + return false; + } + + // Define layout specific header fields + // The position of the segment table is fixed after the header. + // The position of the section table is variable and needs to be fixed + // before saving. + header->set_segments_num( segments.size() ); + header->set_segments_offset( + segments.size() > 0 ? header->get_header_size() : 0 ); + header->set_sections_num( sections.size() ); + header->set_sections_offset( 0 ); + + // Layout the first section right after the segment table + current_file_pos = + header->get_header_size() + + header->get_segment_entry_size() * + static_cast( header->get_segments_num() ); + + calc_segment_alignment(); + + bool is_still_good = layout_segments_and_their_sections(); + is_still_good = is_still_good && layout_sections_without_segments(); + is_still_good = is_still_good && layout_section_table(); + + is_still_good = is_still_good && save_header( stream ); + is_still_good = is_still_good && save_sections( stream ); + is_still_good = is_still_good && save_segments( stream ); + + return is_still_good; + } + + //------------------------------------------------------------------------------ + // ELF header access functions + ELFIO_HEADER_ACCESS_GET( unsigned char, class ); + ELFIO_HEADER_ACCESS_GET( unsigned char, elf_version ); + ELFIO_HEADER_ACCESS_GET( unsigned char, encoding ); + ELFIO_HEADER_ACCESS_GET( Elf_Word, version ); + ELFIO_HEADER_ACCESS_GET( Elf_Half, header_size ); + ELFIO_HEADER_ACCESS_GET( Elf_Half, section_entry_size ); + ELFIO_HEADER_ACCESS_GET( Elf_Half, segment_entry_size ); + + ELFIO_HEADER_ACCESS_GET_SET( unsigned char, os_abi ); + ELFIO_HEADER_ACCESS_GET_SET( unsigned char, abi_version ); + ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, type ); + ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, machine ); + ELFIO_HEADER_ACCESS_GET_SET( Elf_Word, flags ); + ELFIO_HEADER_ACCESS_GET_SET( Elf64_Addr, entry ); + ELFIO_HEADER_ACCESS_GET_SET( Elf64_Off, sections_offset ); + ELFIO_HEADER_ACCESS_GET_SET( Elf64_Off, segments_offset ); + ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, section_name_str_index ); + + //------------------------------------------------------------------------------ + //! \brief Get the endianness convertor + //! \return Reference to the endianness convertor + const std::shared_ptr& get_convertor() const + { + return convertor; + } + + //------------------------------------------------------------------------------ + //! \brief Get the default entry size for a section type + //! \param section_type The type of the section + //! \return The default entry size for the section type + Elf_Xword get_default_entry_size( Elf_Word section_type ) const + { + switch ( section_type ) { + case SHT_RELA: + if ( header->get_class() == ELFCLASS64 ) { + return sizeof( Elf64_Rela ); + } + else { + return sizeof( Elf32_Rela ); + } + case SHT_REL: + if ( header->get_class() == ELFCLASS64 ) { + return sizeof( Elf64_Rel ); + } + else { + return sizeof( Elf32_Rel ); + } + case SHT_SYMTAB: + if ( header->get_class() == ELFCLASS64 ) { + return sizeof( Elf64_Sym ); + } + else { + return sizeof( Elf32_Sym ); + } + case SHT_DYNAMIC: + if ( header->get_class() == ELFCLASS64 ) { + return sizeof( Elf64_Dyn ); + } + else { + return sizeof( Elf32_Dyn ); + } + default: + return 0; + } + } + + //------------------------------------------------------------------------------ + //! \brief Validate the ELF file + //! \return An empty string if no problems are detected, or a string containing an error message if problems are found, with one error per line. + std::string validate() const + { + // clang-format off + + std::string errors; + // Check for overlapping sections in the file + // This is explicitly forbidden by ELF specification + for ( int i = 0; i < sections.size(); ++i) { + for ( int j = i+1; j < sections.size(); ++j ) { + const section* a = sections[i]; + const section* b = sections[j]; + if ( ( ( a->get_type() & SHT_NOBITS) == 0 ) + && ( ( b->get_type() & SHT_NOBITS) == 0 ) + && ( a->get_size() > 0 ) + && ( b->get_size() > 0 ) + && ( a->get_offset() > 0 ) + && ( b->get_offset() > 0 ) + && ( is_offset_in_section( a->get_offset(), b ) + || is_offset_in_section( a->get_offset()+a->get_size()-1, b ) + || is_offset_in_section( b->get_offset(), a ) + || is_offset_in_section( b->get_offset()+b->get_size()-1, a ) ) ) { + errors += "Sections " + a->get_name() + " and " + b->get_name() + " overlap in file\n"; + } + } + } + // clang-format on + + // Check for conflicting section / program header tables, where + // the same offset has different vaddresses in section table and + // program header table. + // This doesn't seem to be explicitly forbidden by ELF specification, + // but: + // - it doesn't make any sense + // - ELFIO relies on this being consistent when writing ELF files, + // since offsets are re-calculated from vaddress + for ( int h = 0; h < segments.size(); ++h ) { + const segment* seg = segments[h]; + const section* sec = + find_prog_section_for_offset( seg->get_offset() ); + if ( seg->get_type() == PT_LOAD && seg->get_file_size() > 0 && + sec != nullptr ) { + Elf64_Addr sec_addr = + get_virtual_addr( seg->get_offset(), sec ); + if ( sec_addr != seg->get_virtual_address() ) { + errors += "Virtual address of segment " + + std::to_string( h ) + " (" + + to_hex_string( seg->get_virtual_address() ) + + ")" + " conflicts with address of section " + + sec->get_name() + " (" + + to_hex_string( sec_addr ) + ")" + " at offset " + + to_hex_string( seg->get_offset() ) + "\n"; + } + } + } + + // more checks to be added here... + + return errors; + } + + private: + //------------------------------------------------------------------------------ + //! \brief Check if an offset is within a section + //! \param offset The offset to check + //! \param sec Pointer to the section + //! \return True if the offset is within the section, false otherwise + static bool is_offset_in_section( Elf64_Off offset, const section* sec ) + { + return ( offset >= sec->get_offset() ) && + ( offset < ( sec->get_offset() + sec->get_size() ) ); + } + + //------------------------------------------------------------------------------ + //! \brief Get the virtual address of an offset within a section + //! \param offset The offset within the section + //! \param sec Pointer to the section + //! \return The virtual address of the offset within the section + static Elf64_Addr get_virtual_addr( Elf64_Off offset, const section* sec ) + { + return sec->get_address() + offset - sec->get_offset(); + } + + //------------------------------------------------------------------------------ + //! \brief Find the section that contains a given offset + //! \param offset The offset to find + //! \return Pointer to the section that contains the offset, or nullptr if not found + const section* find_prog_section_for_offset( Elf64_Off offset ) const + { + for ( const auto& sec : sections ) { + if ( sec->get_type() == SHT_PROGBITS && + is_offset_in_section( offset, sec.get() ) ) { + return sec.get(); + } + } + return nullptr; + } + + //------------------------------------------------------------------------------ + //! \brief Create an ELF header + //! \param file_class The class of the ELF file (ELFCLASS32 or ELFCLASS64) + //! \param encoding The encoding of the ELF file (ELFDATA2LSB or ELFDATA2MSB) + //! \return Unique pointer to the created ELF header + std::unique_ptr create_header( unsigned char file_class, + unsigned char encoding ) + { + std::unique_ptr new_header; + + if ( file_class == ELFCLASS64 ) { + new_header = std::unique_ptr( + new ( std::nothrow ) elf_header_impl( + convertor, encoding, addr_translator ) ); + } + else if ( file_class == ELFCLASS32 ) { + new_header = std::unique_ptr( + new ( std::nothrow ) elf_header_impl( + convertor, encoding, addr_translator ) ); + } + else { + return nullptr; + } + + return new_header; + } + + //------------------------------------------------------------------------------ + //! \brief Create a new section + //! \return Pointer to the created section + section* create_section() + { + if ( auto file_class = get_class(); file_class == ELFCLASS64 ) { + sections_.emplace_back( + new ( std::nothrow ) section_impl( + convertor, addr_translator, compression ) ); + } + else if ( file_class == ELFCLASS32 ) { + sections_.emplace_back( + new ( std::nothrow ) section_impl( + convertor, addr_translator, compression ) ); + } + else { + sections_.pop_back(); + return nullptr; + } + + section* new_section = sections_.back().get(); + new_section->set_index( static_cast( sections_.size() - 1 ) ); + + return new_section; + } + + //------------------------------------------------------------------------------ + //! \brief Create a new segment + //! \return Pointer to the created segment + segment* create_segment() + { + if ( auto file_class = header->get_class(); file_class == ELFCLASS64 ) { + segments_.emplace_back( + new ( std::nothrow ) + segment_impl( convertor, addr_translator ) ); + } + else if ( file_class == ELFCLASS32 ) { + segments_.emplace_back( + new ( std::nothrow ) + segment_impl( convertor, addr_translator ) ); + } + else { + segments_.pop_back(); + return nullptr; + } + + segment* new_segment = segments_.back().get(); + new_segment->set_index( static_cast( segments_.size() - 1 ) ); + + return new_segment; + } + + //------------------------------------------------------------------------------ + //! \brief Create mandatory sections + void create_mandatory_sections() + { + // Create null section without calling to 'add_section' as no string + // section containing section names exists yet + section* sec0 = create_section(); + sec0->set_index( 0 ); + sec0->set_name( "" ); + sec0->set_name_string_offset( 0 ); + + set_section_name_str_index( 1 ); + section* shstrtab = sections.add( ".shstrtab" ); + shstrtab->set_type( SHT_STRTAB ); + shstrtab->set_addr_align( 1 ); + } + + //------------------------------------------------------------------------------ + //! \brief Load sections from a stream + //! \param stream The input stream to load from + //! \param is_lazy Whether to load the sections lazily + //! \return True if successful, false otherwise + bool load_sections( std::istream& stream, bool is_lazy ) + { + unsigned char file_class = header->get_class(); + Elf_Half entry_size = header->get_section_entry_size(); + Elf_Half num = header->get_sections_num(); + Elf64_Off offset = header->get_sections_offset(); + + if ( ( num != 0 && file_class == ELFCLASS64 && + entry_size < sizeof( Elf64_Shdr ) ) || + ( num != 0 && file_class == ELFCLASS32 && + entry_size < sizeof( Elf32_Shdr ) ) ) { + return false; + } + + for ( Elf_Half i = 0; i < num; ++i ) { + section* sec = create_section(); + + // Load return value is ignored here + // This allows retrieval of information from corrupted sections + sec->load( stream, + static_cast( offset ) + + static_cast( i ) * entry_size, + is_lazy ); + // To mark that the section is not permitted to reassign address + // during layout calculation + sec->set_address( sec->get_address() ); + } + + if ( Elf_Half shstrndx = get_section_name_str_index(); + SHN_UNDEF != shstrndx ) { + string_section_accessor str_reader( sections[shstrndx] ); + for ( Elf_Half i = 0; i < num; ++i ) { + Elf_Word section_offset = sections[i]->get_name_string_offset(); + const char* p = str_reader.get_string( section_offset ); + if ( p != nullptr ) { + sections[i]->set_name( p ); + } + } + } + + return true; + } + + //------------------------------------------------------------------------------ + //! \brief Checks whether the addresses of the section entirely fall within the given segment. + //! It doesn't matter if the addresses are memory addresses, or file offsets, + //! they just need to be in the same address space + //! \param sect_begin The beginning address of the section + //! \param sect_size The size of the section + //! \param seg_begin The beginning address of the segment + //! \param seg_end The end address of the segment + //! \return True if the section is within the segment, false otherwise + static bool is_sect_in_seg( Elf64_Off sect_begin, + Elf_Xword sect_size, + Elf64_Off seg_begin, + Elf64_Off seg_end ) + { + return ( seg_begin <= sect_begin ) && + ( sect_begin + sect_size <= seg_end ) && + ( sect_begin < + seg_end ); // this is important criteria when sect_size == 0 + // Example: seg_begin=10, seg_end=12 (-> covering the bytes 10 and 11) + // sect_begin=12, sect_size=0 -> shall return false! + } + + //------------------------------------------------------------------------------ + //! \brief Load segments from a stream + //! \param stream The input stream to load from + //! \param is_lazy Whether to load the segments lazily + //! \return True if successful, false otherwise + bool load_segments( std::istream& stream, bool is_lazy ) + { + unsigned char file_class = header->get_class(); + Elf_Half entry_size = header->get_segment_entry_size(); + Elf_Half num = header->get_segments_num(); + Elf64_Off offset = header->get_segments_offset(); + + if ( ( num != 0 && file_class == ELFCLASS64 && + entry_size < sizeof( Elf64_Phdr ) ) || + ( num != 0 && file_class == ELFCLASS32 && + entry_size < sizeof( Elf32_Phdr ) ) ) { + return false; + } + + for ( Elf_Half i = 0; i < num; ++i ) { + if ( file_class == ELFCLASS64 ) { + segments_.emplace_back( new ( std::nothrow ) + segment_impl( + convertor, addr_translator ) ); + } + else if ( file_class == ELFCLASS32 ) { + segments_.emplace_back( new ( std::nothrow ) + segment_impl( + convertor, addr_translator ) ); + } + else { + segments_.pop_back(); + return false; + } + + segment* seg = segments_.back().get(); + + if ( !seg->load( stream, + static_cast( offset ) + + static_cast( i ) * entry_size, + is_lazy ) || + stream.fail() ) { + segments_.pop_back(); + return false; + } + + seg->set_index( i ); + + // Add sections to the segments (similar to readelfs algorithm) + Elf64_Off segBaseOffset = seg->get_offset(); + Elf64_Off segEndOffset = segBaseOffset + seg->get_file_size(); + Elf64_Off segVBaseAddr = seg->get_virtual_address(); + Elf64_Off segVEndAddr = segVBaseAddr + seg->get_memory_size(); + for ( const auto& psec : sections ) { + // SHF_ALLOC sections are matched based on the virtual address + // otherwise the file offset is matched + if ( ( ( psec->get_flags() & SHF_ALLOC ) == SHF_ALLOC ) + ? is_sect_in_seg( psec->get_address(), + psec->get_size(), segVBaseAddr, + segVEndAddr ) + : is_sect_in_seg( psec->get_offset(), psec->get_size(), + segBaseOffset, segEndOffset ) ) { + + // If it is a TLS segment, add TLS sections only and vice versa + if ( ( ( seg->get_type() == PT_TLS ) && + ( ( psec->get_flags() & SHF_TLS ) != SHF_TLS ) ) || + ( ( ( psec->get_flags() & SHF_TLS ) == SHF_TLS ) && + ( seg->get_type() != PT_TLS ) ) ) + continue; + + // Alignment of segment shall not be updated, to preserve original value + // It will be re-calculated on saving. + seg->add_section_index( psec->get_index(), 0 ); + } + } + } + + return true; + } + + //------------------------------------------------------------------------------ + //! \brief Save the ELF header to a stream + //! \param stream The output stream to save to + //! \return True if successful, false otherwise + bool save_header( std::ostream& stream ) const + { + return header->save( stream ); + } + + //------------------------------------------------------------------------------ + //! \brief Save the sections to a stream + //! \param stream The output stream to save to + //! \return True if successful, false otherwise + bool save_sections( std::ostream& stream ) const + { + for ( const auto& sec : sections_ ) { + std::streampos headerPosition = + static_cast( header->get_sections_offset() ) + + static_cast( + header->get_section_entry_size() ) * + sec->get_index(); + + sec->save( stream, headerPosition, sec->get_offset() ); + } + return true; + } + + //------------------------------------------------------------------------------ + //! \brief Save the segments to a stream + //! \param stream The output stream to save to + //! \return True if successful, false otherwise + bool save_segments( std::ostream& stream ) const + { + for ( const auto& seg : segments_ ) { + std::streampos headerPosition = + static_cast( header->get_segments_offset() ) + + static_cast( + header->get_segment_entry_size() ) * + seg->get_index(); + + seg->save( stream, headerPosition, seg->get_offset() ); + } + return true; + } + + //------------------------------------------------------------------------------ + //! \brief Check if a section is without a segment + //! \param section_index The index of the section + //! \return True if the section is without a segment, false otherwise + bool is_section_without_segment( unsigned int section_index ) const + { + bool found = false; + + for ( unsigned int j = 0; !found && ( j < segments.size() ); ++j ) { + for ( Elf_Half k = 0; + !found && ( k < segments[j]->get_sections_num() ); ++k ) { + found = segments[j]->get_section_index_at( k ) == section_index; + } + } + + return !found; + } + + //------------------------------------------------------------------------------ + //! \brief Check if a segment is a subsequence of another segment + //! \param seg1 Pointer to the first segment + //! \param seg2 Pointer to the second segment + //! \return True if seg1 is a subsequence of seg2, false otherwise + static bool is_subsequence_of( const segment* seg1, const segment* seg2 ) + { + // Return 'true' if sections of seg1 are a subset of sections in seg2 + const std::vector& sections1 = seg1->get_sections(); + const std::vector& sections2 = seg2->get_sections(); + + bool found = false; + if ( sections1.size() < sections2.size() ) { + found = std::includes( sections2.begin(), sections2.end(), + sections1.begin(), sections1.end() ); + } + + return found; + } + + //------------------------------------------------------------------------------ + //! \brief Get ordered segments + //! \return Vector of ordered segments + std::vector get_ordered_segments() const + { + std::vector res; + std::deque worklist; + + res.reserve( segments.size() ); + for ( const auto& seg : segments ) { + worklist.emplace_back( seg.get() ); + } + + // Bring the segments which start at address 0 to the front + size_t nextSlot = 0; + for ( size_t i = 0; i < worklist.size(); ++i ) { + if ( i != nextSlot && worklist[i]->is_offset_initialized() && + worklist[i]->get_offset() == 0 ) { + if ( worklist[nextSlot]->get_offset() == 0 ) { + ++nextSlot; + } + std::swap( worklist[i], worklist[nextSlot] ); + ++nextSlot; + } + } + + while ( !worklist.empty() ) { + segment* seg = worklist.front(); + worklist.pop_front(); + + size_t i = 0; + for ( ; i < worklist.size(); ++i ) { + if ( is_subsequence_of( seg, worklist[i] ) ) { + break; + } + } + + if ( i < worklist.size() ) { + worklist.emplace_back( seg ); + } + else { + res.emplace_back( seg ); + } + } + + return res; + } + + //------------------------------------------------------------------------------ + //! \brief Layout sections without segments + //! \return True if successful, false otherwise + bool layout_sections_without_segments() + { + for ( unsigned int i = 0; i < sections_.size(); ++i ) { + if ( is_section_without_segment( i ) ) { + const auto& sec = sections_[i]; + + if ( Elf_Xword section_align = sec->get_addr_align(); + section_align > 1 && + current_file_pos % section_align != 0 ) { + current_file_pos += + section_align - current_file_pos % section_align; + } + + if ( 0 != sec->get_index() ) { + sec->set_offset( current_file_pos ); + } + + if ( SHT_NOBITS != sec->get_type() && + SHT_NULL != sec->get_type() ) { + current_file_pos += sec->get_size(); + } + } + } + + return true; + } + + //------------------------------------------------------------------------------ + //! \brief Calculate segment alignment + void calc_segment_alignment() const + { + for ( const auto& seg : segments_ ) { + for ( Elf_Half i = 0; i < seg->get_sections_num(); ++i ) { + const auto& sect = sections_[seg->get_section_index_at( i )]; + if ( sect->get_addr_align() > seg->get_align() ) { + seg->set_align( sect->get_addr_align() ); + } + } + } + } + + //------------------------------------------------------------------------------ + //! \brief Layout segments and their sections + //! \return True if successful, false otherwise + bool layout_segments_and_their_sections() + { + std::vector worklist; + std::vector section_generated( sections.size(), false ); + + // Get segments in a order in where segments which contain a + // sub sequence of other segments are located at the end + worklist = get_ordered_segments(); + + for ( auto* seg : worklist ) { + Elf_Xword segment_memory = 0; + Elf_Xword segment_filesize = 0; + Elf_Xword seg_start_pos = current_file_pos; + // Special case: PHDR segment + // This segment contains the program headers but no sections + if ( seg->get_type() == PT_PHDR && seg->get_sections_num() == 0 ) { + seg_start_pos = header->get_segments_offset(); + segment_memory = segment_filesize = + header->get_segment_entry_size() * + static_cast( header->get_segments_num() ); + } + // Special case: + else if ( seg->is_offset_initialized() && seg->get_offset() == 0 ) { + seg_start_pos = 0; + if ( seg->get_sections_num() > 0 ) { + segment_memory = segment_filesize = current_file_pos; + } + } + // New segments with not generated sections + // have to be aligned + else if ( seg->get_sections_num() > 0 && + !section_generated[seg->get_section_index_at( 0 )] ) { + Elf_Xword align = seg->get_align() > 0 ? seg->get_align() : 1; + Elf64_Off cur_page_alignment = current_file_pos % align; + Elf64_Off req_page_alignment = + seg->get_virtual_address() % align; + Elf64_Off adjustment = req_page_alignment - cur_page_alignment; + + current_file_pos += ( seg->get_align() + adjustment ) % align; + seg_start_pos = current_file_pos; + } + else if ( seg->get_sections_num() > 0 ) { + seg_start_pos = + sections[seg->get_section_index_at( 0 )]->get_offset(); + } + + // Write segment's data + if ( !write_segment_data( seg, section_generated, segment_memory, + segment_filesize, seg_start_pos ) ) { + return false; + } + + seg->set_file_size( segment_filesize ); + + // If we already have a memory size from loading an elf file (value > 0), + // it must not shrink! + // Memory size may be bigger than file size and it is the loader's job to do something + // with the surplus bytes in memory, like initializing them with a defined value. + if ( seg->get_memory_size() < segment_memory ) { + seg->set_memory_size( segment_memory ); + } + + seg->set_offset( seg_start_pos ); + } + + return true; + } + + //------------------------------------------------------------------------------ + //! \brief Layout the section table + //! \return True if successful, false otherwise + bool layout_section_table() + { + // Simply place the section table at the end for now + Elf64_Off alignmentError = current_file_pos % 16; + current_file_pos += 16 - alignmentError; + header->set_sections_offset( current_file_pos ); + return true; + } + + //------------------------------------------------------------------------------ + //! \brief Write segment data + //! \param seg Pointer to the segment + //! \param section_generated Vector of section generated flags + //! \param segment_memory Reference to the segment memory size + //! \param segment_filesize Reference to the segment file size + //! \param seg_start_pos The start position of the segment + //! \return True if successful, false otherwise + bool write_segment_data( const segment* seg, + std::vector& section_generated, + Elf_Xword& segment_memory, + Elf_Xword& segment_filesize, + const Elf_Xword& seg_start_pos ) + { + for ( Elf_Half j = 0; j < seg->get_sections_num(); ++j ) { + Elf_Half index = seg->get_section_index_at( j ); + + section* sec = sections[index]; + + // The NULL section is always generated + if ( SHT_NULL == sec->get_type() ) { + section_generated[index] = true; + continue; + } + + Elf_Xword section_align = 0; + // Fix up the alignment + if ( !section_generated[index] && sec->is_address_initialized() && + SHT_NOBITS != sec->get_type() && SHT_NULL != sec->get_type() && + 0 != sec->get_size() ) { + // Align the sections based on the virtual addresses + // when possible (this is what matters for execution) + Elf64_Off req_offset = + sec->get_address() - seg->get_virtual_address(); + Elf64_Off cur_offset = current_file_pos - seg_start_pos; + if ( req_offset < cur_offset ) { + // something has gone awfully wrong, abort! + // section_align would turn out negative, seeking backwards and overwriting previous data + return false; + } + section_align = req_offset - cur_offset; + } + else if ( !section_generated[index] && + !sec->is_address_initialized() ) { + // If no address has been specified then only the section + // alignment constraint has to be matched + Elf_Xword align = sec->get_addr_align(); + if ( align == 0 ) { + align = 1; + } + Elf64_Off error = current_file_pos % align; + section_align = ( align - error ) % align; + } + else if ( section_generated[index] ) { + // Alignment for already generated sections + section_align = + sec->get_offset() - seg_start_pos - segment_filesize; + } + + // Determine the segment file and memory sizes + // Special case .tbss section (NOBITS) in non TLS segment + if ( ( ( sec->get_flags() & SHF_ALLOC ) == SHF_ALLOC ) && + !( ( ( sec->get_flags() & SHF_TLS ) == SHF_TLS ) && + ( seg->get_type() != PT_TLS ) && + ( SHT_NOBITS == sec->get_type() ) ) ) { + segment_memory += sec->get_size() + section_align; + } + + if ( SHT_NOBITS != sec->get_type() ) { + segment_filesize += sec->get_size() + section_align; + } + + // Nothing to be done when generating nested segments + if ( section_generated[index] ) { + continue; + } + + current_file_pos += section_align; + + // Set the section addresses when missing + if ( !sec->is_address_initialized() ) { + sec->set_address( seg->get_virtual_address() + + current_file_pos - seg_start_pos ); + } + + if ( 0 != sec->get_index() ) { + sec->set_offset( current_file_pos ); + } + + if ( SHT_NOBITS != sec->get_type() ) { + current_file_pos += sec->get_size(); + } + + section_generated[index] = true; + } + + return true; + } + + //------------------------------------------------------------------------------ + public: + //! \class Sections + //! \brief The Sections class provides methods to manipulate sections in an ELF file. + friend class Sections; + class Sections + { + public: + //------------------------------------------------------------------------------ + //! \brief Constructor + //! \param parent Pointer to the parent elfio object + explicit Sections( elfio* parent ) : parent( parent ) {} + + //------------------------------------------------------------------------------ + //! \brief Get the number of sections + //! \return The number of sections + Elf_Half size() const + { + return static_cast( parent->sections_.size() ); + } + + //------------------------------------------------------------------------------ + //! \brief Get a section by index + //! \param index The index of the section + //! \return Pointer to the section, or nullptr if not found + section* operator[]( unsigned int index ) const + { + section* sec = nullptr; + + if ( index < parent->sections_.size() ) { + sec = parent->sections_[index].get(); + } + + return sec; + } + + //------------------------------------------------------------------------------ + //! \brief Get a section by name + //! \param name The name of the section + //! \return Pointer to the section, or nullptr if not found + section* operator[]( const std::string_view& name ) const + { + section* sec = nullptr; + + for ( const auto& it : parent->sections_ ) { + if ( it->get_name() == name ) { + sec = it.get(); + break; + } + } + + return sec; + } + + //------------------------------------------------------------------------------ + //! \brief Add a new section + //! \param name The name of the section + //! \return Pointer to the created section + section* add( const std::string& name ) const + { + section* new_section = parent->create_section(); + new_section->set_name( name ); + + Elf_Half str_index = parent->get_section_name_str_index(); + section* string_table( parent->sections_[str_index].get() ); + string_section_accessor str_writer( string_table ); + Elf_Word pos = str_writer.add_string( name ); + new_section->set_name_string_offset( pos ); + + return new_section; + } + + //------------------------------------------------------------------------------ + //! \brief Get an iterator to the beginning of the sections + //! \return Iterator to the beginning of the sections + std::vector>::iterator begin() + { + return parent->sections_.begin(); + } + + //------------------------------------------------------------------------------ + //! \brief Get an iterator to the end of the sections + //! \return Iterator to the end of the sections + std::vector>::iterator end() + { + return parent->sections_.end(); + } + + //------------------------------------------------------------------------------ + //! \brief Get a const iterator to the beginning of the sections + //! \return Const iterator to the beginning of the sections + std::vector>::const_iterator begin() const + { + return parent->sections_.cbegin(); + } + + //------------------------------------------------------------------------------ + //! \brief Get a const iterator to the end of the sections + //! \return Const iterator to the end of the sections + std::vector>::const_iterator end() const + { + return parent->sections_.cend(); + } + + //------------------------------------------------------------------------------ + private: + elfio* parent; //!< Pointer to the parent elfio object + }; + Sections sections; //!< Sections object + + //------------------------------------------------------------------------------ + //! \class Segments + //! \brief The Segments class provides methods to manipulate segments in an ELF file. + friend class Segments; + class Segments + { + public: + //------------------------------------------------------------------------------ + //! \brief Constructor + //! \param parent Pointer to the parent elfio object + explicit Segments( elfio* parent ) : parent( parent ) {} + + //------------------------------------------------------------------------------ + //! \brief Get the number of segments + //! \return The number of segments + Elf_Half size() const + { + return static_cast( parent->segments_.size() ); + } + + //------------------------------------------------------------------------------ + //! \brief Get a segment by index + //! \param index The index of the segment + //! \return Pointer to the segment, or nullptr if not found + segment* operator[]( unsigned int index ) const + { + return parent->segments_[index].get(); + } + + //------------------------------------------------------------------------------ + //! \brief Add a new segment + //! \return Pointer to the created segment + segment* add() { return parent->create_segment(); } + + //------------------------------------------------------------------------------ + //! \brief Get an iterator to the beginning of the segments + //! \return Iterator to the beginning of the segments + std::vector>::iterator begin() + { + return parent->segments_.begin(); + } + + //------------------------------------------------------------------------------ + //! \brief Get an iterator to the end of the segments + //! \return Iterator to the end of the segments + std::vector>::iterator end() + { + return parent->segments_.end(); + } + + //------------------------------------------------------------------------------ + //! \brief Get a const iterator to the beginning of the segments + //! \return Const iterator to the beginning of the segments + std::vector>::const_iterator begin() const + { + return parent->segments_.cbegin(); + } + + //------------------------------------------------------------------------------ + //! \brief Get a const iterator to the end of the segments + //! \return Const iterator to the end of the segments + std::vector>::const_iterator end() const + { + return parent->segments_.cend(); + } + + //------------------------------------------------------------------------------ + private: + elfio* parent; //!< Pointer to the parent elfio object + }; + Segments segments; //!< Segments object + + //------------------------------------------------------------------------------ + private: + std::unique_ptr pstream = + nullptr; //!< Pointer to the input stream + std::unique_ptr header = nullptr; //!< Pointer to the ELF header + std::vector> sections_; //!< Vector of sections + std::vector> segments_; //!< Vector of segments + std::shared_ptr convertor; //!< Endianness convertor + std::shared_ptr addr_translator; //!< Address translator + std::shared_ptr compression = + nullptr; //!< Pointer to the compression interface + + Elf_Xword current_file_pos = 0; //!< Current file position +}; + +} // namespace ELFIO + +#include +#include +#include +#include +#include +#include +#include + +#endif // ELFIO_HPP diff --git a/emulator/include/elfio/elfio_array.hpp b/emulator/include/elfio/elfio_array.hpp new file mode 100644 index 0000000..3e81adc --- /dev/null +++ b/emulator/include/elfio/elfio_array.hpp @@ -0,0 +1,119 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_ARRAY_HPP +#define ELFIO_ARRAY_HPP + +#include + +namespace ELFIO { + +//------------------------------------------------------------------------------ +// Template class for accessing array sections +template class array_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + // Constructor + explicit array_section_accessor_template( const elfio& elf_file, + S* section ); + + //------------------------------------------------------------------------------ + // Returns the number of entries in the array section + Elf_Xword get_entries_num() const; + + //------------------------------------------------------------------------------ + // Retrieves an entry from the array section + bool get_entry( Elf_Xword index, Elf64_Addr& address ) const; + + //------------------------------------------------------------------------------ + // Adds an entry to the array section + void add_entry( Elf64_Addr address ); + + private: + //------------------------------------------------------------------------------ + // Reference to the ELF file + const elfio& elf_file; + //------------------------------------------------------------------------------ + // Pointer to the array section + S* array_section; +}; + +//------------------------------------------------------------------------------ +// Constructor +template +array_section_accessor_template::array_section_accessor_template( + const elfio& elf_file, S* section ) + : elf_file( elf_file ), array_section( section ) +{ +} + +//------------------------------------------------------------------------------ +// Returns the number of entries in the array section +template +Elf_Xword array_section_accessor_template::get_entries_num() const +{ + Elf_Xword entry_size = sizeof( T ); + return array_section->get_size() / entry_size; +} + +//------------------------------------------------------------------------------ +// Retrieves an entry from the array section +template +bool array_section_accessor_template::get_entry( + Elf_Xword index, Elf64_Addr& address ) const +{ + if ( index >= get_entries_num() ) { // Is index valid + return false; + } + + const auto& convertor = elf_file.get_convertor(); + + const T temp = *reinterpret_cast( array_section->get_data() + + index * sizeof( T ) ); + address = ( *convertor )( temp ); + + return true; +} + +//------------------------------------------------------------------------------ +// Adds an entry to the array section +template +void array_section_accessor_template::add_entry( Elf64_Addr address ) +{ + const auto& convertor = elf_file.get_convertor(); + + T temp = ( *convertor )( (T)address ); + array_section->append_data( reinterpret_cast( &temp ), + sizeof( temp ) ); +} + +// Type aliases for array section accessors +template +using array_section_accessor = array_section_accessor_template; +template +using const_array_section_accessor = + array_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_ARRAY_HPP diff --git a/emulator/include/elfio/elfio_dump.hpp b/emulator/include/elfio/elfio_dump.hpp new file mode 100644 index 0000000..0eadda8 --- /dev/null +++ b/emulator/include/elfio/elfio_dump.hpp @@ -0,0 +1,1388 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_DUMP_HPP +#define ELFIO_DUMP_HPP + +#include +#include +#include +#include +#include +#include + +namespace ELFIO { + +static const struct class_table_t +{ + const char key; + const char* str; +} class_table[] = { + { ELFCLASS32, "ELF32" }, + { ELFCLASS64, "ELF64" }, +}; + +static const struct endian_table_t +{ + const char key; + const char* str; +} endian_table[] = { + { ELFDATANONE, "None" }, + { ELFDATA2LSB, "Little endian" }, + { ELFDATA2MSB, "Big endian" }, +}; + +static const struct os_abi_table_t +{ + const unsigned char key; + const char* str; +} os_abi_table[] = { + { ELFOSABI_NONE, "UNIX System V" }, + { ELFOSABI_HPUX, "Hewlett-Packard HP-UX" }, + { ELFOSABI_NETBSD, "NetBSD" }, + { ELFOSABI_LINUX, "Linux" }, + { ELFOSABI_HURD, "GNU Hurd" }, + { ELFOSABI_SOLARIS, "Sun Solaris" }, + { ELFOSABI_AIX, "AIX" }, + { ELFOSABI_IRIX, "IRIX" }, + { ELFOSABI_FREEBSD, "FreeBSD" }, + { ELFOSABI_TRU64, "Compaq TRU64 UNIX" }, + { ELFOSABI_MODESTO, "Novell Modesto" }, + { ELFOSABI_OPENBSD, "Open BSD" }, + { ELFOSABI_OPENVMS, "Open VMS" }, + { ELFOSABI_NSK, "Hewlett-Packard Non-Stop Kernel" }, + { ELFOSABI_AROS, "Amiga Research OS" }, + { ELFOSABI_FENIXOS, "FenixOS" }, + { ELFOSABI_NUXI, "Nuxi CloudABI" }, + { ELFOSABI_OPENVOS, "OpenVOS" }, + { ELFOSABI_ARM, "ARM" }, + { ELFOSABI_STANDALONE, "Standalone (embedded)" }, +}; + +static const struct version_table_t +{ + const Elf64_Word key; + const char* str; +} version_table[] = { + { EV_NONE, "None" }, + { EV_CURRENT, "Current" }, +}; + +static const struct type_table_t +{ + const Elf32_Half key; + const char* str; +} type_table[] = { + { ET_NONE, "No file type" }, { ET_REL, "Relocatable file" }, + { ET_EXEC, "Executable file" }, { ET_DYN, "Shared object file" }, + { ET_CORE, "Core file" }, +}; + +static const struct machine_table_t +{ + const Elf64_Half key; + const char* str; +} machine_table[] = { + { EM_NONE, "No machine" }, + { EM_M32, "AT&T WE 32100" }, + { EM_SPARC, "SUN SPARC" }, + { EM_386, "Intel 80386" }, + { EM_68K, "Motorola m68k family" }, + { EM_88K, "Motorola m88k family" }, + { EM_486, "Intel 80486// Reserved for future use" }, + { EM_860, "Intel 80860" }, + { EM_MIPS, "MIPS R3000 (officially, big-endian only)" }, + { EM_S370, "IBM System/370" }, + { EM_MIPS_RS3_LE, + "MIPS R3000 little-endian (Oct 4 1999 Draft) Deprecated" }, + { EM_res011, "Reserved" }, + { EM_res012, "Reserved" }, + { EM_res013, "Reserved" }, + { EM_res014, "Reserved" }, + { EM_PARISC, "HPPA" }, + { EM_res016, "Reserved" }, + { EM_VPP550, "Fujitsu VPP500" }, + { EM_SPARC32PLUS, "Sun's v8plus" }, + { EM_960, "Intel 80960" }, + { EM_PPC, "PowerPC" }, + { EM_PPC64, "64-bit PowerPC" }, + { EM_S390, "IBM S/390" }, + { EM_SPU, "Sony/Toshiba/IBM SPU" }, + { EM_res024, "Reserved" }, + { EM_res025, "Reserved" }, + { EM_res026, "Reserved" }, + { EM_res027, "Reserved" }, + { EM_res028, "Reserved" }, + { EM_res029, "Reserved" }, + { EM_res030, "Reserved" }, + { EM_res031, "Reserved" }, + { EM_res032, "Reserved" }, + { EM_res033, "Reserved" }, + { EM_res034, "Reserved" }, + { EM_res035, "Reserved" }, + { EM_V800, "NEC V800 series" }, + { EM_FR20, "Fujitsu FR20" }, + { EM_RH32, "TRW RH32" }, + { EM_MCORE, "Motorola M*Core // May also be taken by Fujitsu MMA" }, + { EM_RCE, "Old name for MCore" }, + { EM_ARM, "ARM" }, + { EM_OLD_ALPHA, "Digital Alpha" }, + { EM_SH, "Renesas (formerly Hitachi) / SuperH SH" }, + { EM_SPARCV9, "SPARC v9 64-bit" }, + { EM_TRICORE, "Siemens Tricore embedded processor" }, + { EM_ARC, "ARC Cores" }, + { EM_H8_300, "Renesas (formerly Hitachi) H8/300" }, + { EM_H8_300H, "Renesas (formerly Hitachi) H8/300H" }, + { EM_H8S, "Renesas (formerly Hitachi) H8S" }, + { EM_H8_500, "Renesas (formerly Hitachi) H8/500" }, + { EM_IA_64, "Intel IA-64 Processor" }, + { EM_MIPS_X, "Stanford MIPS-X" }, + { EM_COLDFIRE, "Motorola Coldfire" }, + { EM_68HC12, "Motorola M68HC12" }, + { EM_MMA, "Fujitsu Multimedia Accelerator" }, + { EM_PCP, "Siemens PCP" }, + { EM_NCPU, "Sony nCPU embedded RISC processor" }, + { EM_NDR1, "Denso NDR1 microprocesspr" }, + { EM_STARCORE, "Motorola Star*Core processor" }, + { EM_ME16, "Toyota ME16 processor" }, + { EM_ST100, "STMicroelectronics ST100 processor" }, + { EM_TINYJ, "Advanced Logic Corp. TinyJ embedded processor" }, + { EM_X86_64, "Advanced Micro Devices X86-64 processor" }, + { EM_PDSP, "Sony DSP Processor" }, + { EM_PDP10, "Digital Equipment Corp. PDP-10" }, + { EM_PDP11, "Digital Equipment Corp. PDP-11" }, + { EM_FX66, "Siemens FX66 microcontroller" }, + { EM_ST9PLUS, "STMicroelectronics ST9+ 8/16 bit microcontroller" }, + { EM_ST7, "STMicroelectronics ST7 8-bit microcontroller" }, + { EM_68HC16, "Motorola MC68HC16 Microcontroller" }, + { EM_68HC11, "Motorola MC68HC11 Microcontroller" }, + { EM_68HC08, "Motorola MC68HC08 Microcontroller" }, + { EM_68HC05, "Motorola MC68HC05 Microcontroller" }, + { EM_SVX, "Silicon Graphics SVx" }, + { EM_ST19, "STMicroelectronics ST19 8-bit cpu" }, + { EM_VAX, "Digital VAX" }, + { EM_CRIS, "Axis Communications 32-bit embedded processor" }, + { EM_JAVELIN, "Infineon Technologies 32-bit embedded cpu" }, + { EM_FIREPATH, "Element 14 64-bit DSP processor" }, + { EM_ZSP, "LSI Logic's 16-bit DSP processor" }, + { EM_MMIX, "Donald Knuth's educational 64-bit processor" }, + { EM_HUANY, "Harvard's machine-independent format" }, + { EM_PRISM, "SiTera Prism" }, + { EM_AVR, "Atmel AVR 8-bit microcontroller" }, + { EM_FR30, "Fujitsu FR30" }, + { EM_D10V, "Mitsubishi D10V" }, + { EM_D30V, "Mitsubishi D30V" }, + { EM_V850, "NEC v850" }, + { EM_M32R, "Renesas M32R (formerly Mitsubishi M32R)" }, + { EM_MN10300, "Matsushita MN10300" }, + { EM_MN10200, "Matsushita MN10200" }, + { EM_PJ, "picoJava" }, + { EM_OPENRISC, "OpenRISC 32-bit embedded processor" }, + { EM_ARC_A5, "ARC Cores Tangent-A5" }, + { EM_XTENSA, "Tensilica Xtensa Architecture" }, + { EM_VIDEOCORE, "Alphamosaic VideoCore processor" }, + { EM_TMM_GPP, "Thompson Multimedia General Purpose Processor" }, + { EM_NS32K, "National Semiconductor 32000 series" }, + { EM_TPC, "Tenor Network TPC processor" }, + { EM_SNP1K, "Trebia SNP 1000 processor" }, + { EM_ST200, "STMicroelectronics ST200 microcontroller" }, + { EM_IP2K, "Ubicom IP2022 micro controller" }, + { EM_MAX, "MAX Processor" }, + { EM_CR, "National Semiconductor CompactRISC" }, + { EM_F2MC16, "Fujitsu F2MC16" }, + { EM_MSP430, "TI msp430 micro controller" }, + { EM_BLACKFIN, "ADI Blackfin" }, + { EM_SE_C33, "S1C33 Family of Seiko Epson processors" }, + { EM_SEP, "Sharp embedded microprocessor" }, + { EM_ARCA, "Arca RISC Microprocessor" }, + { EM_UNICORE, "Microprocessor series from PKU-Unity Ltd. and MPRC of " + "Peking University" }, + { EM_EXCESS, "eXcess: 16/32/64-bit configurable embedded CPU" }, + { EM_DXP, "Icera Semiconductor Inc. Deep Execution Processor" }, + { EM_ALTERA_NIOS2, "Altera Nios II soft-core processor" }, + { EM_CRX, "National Semiconductor CRX" }, + { EM_XGATE, "Motorola XGATE embedded processor" }, + { EM_C166, "Infineon C16x/XC16x processor" }, + { EM_M16C, "Renesas M16C series microprocessors" }, + { EM_DSPIC30F, "Microchip Technology dsPIC30F Digital Signal Controller" }, + { EM_CE, "Freescale Communication Engine RISC core" }, + { EM_M32C, "Renesas M32C series microprocessors" }, + { EM_res121, "Reserved" }, + { EM_res122, "Reserved" }, + { EM_res123, "Reserved" }, + { EM_res124, "Reserved" }, + { EM_res125, "Reserved" }, + { EM_res126, "Reserved" }, + { EM_res127, "Reserved" }, + { EM_res128, "Reserved" }, + { EM_res129, "Reserved" }, + { EM_res130, "Reserved" }, + { EM_TSK3000, "Altium TSK3000 core" }, + { EM_RS08, "Freescale RS08 embedded processor" }, + { EM_res133, "Reserved" }, + { EM_ECOG2, "Cyan Technology eCOG2 microprocessor" }, + { EM_SCORE, "Sunplus Score" }, + { EM_SCORE7, "Sunplus S+core7 RISC processor" }, + { EM_DSP24, "New Japan Radio (NJR) 24-bit DSP Processor" }, + { EM_VIDEOCORE3, "Broadcom VideoCore III processor" }, + { EM_LATTICEMICO32, "RISC processor for Lattice FPGA architecture" }, + { EM_SE_C17, "Seiko Epson C17 family" }, + { EM_TI_C6000, "Texas Instruments TMS320C6000 DSP family" }, + { EM_TI_C2000, "Texas Instruments TMS320C2000 DSP family" }, + { EM_TI_C5500, "Texas Instruments TMS320C55x DSP family" }, + { EM_res143, "Reserved" }, + { EM_res144, "Reserved" }, + { EM_res145, "Reserved" }, + { EM_res146, "Reserved" }, + { EM_res147, "Reserved" }, + { EM_res148, "Reserved" }, + { EM_res149, "Reserved" }, + { EM_res150, "Reserved" }, + { EM_res151, "Reserved" }, + { EM_res152, "Reserved" }, + { EM_res153, "Reserved" }, + { EM_res154, "Reserved" }, + { EM_res155, "Reserved" }, + { EM_res156, "Reserved" }, + { EM_res157, "Reserved" }, + { EM_res158, "Reserved" }, + { EM_res159, "Reserved" }, + { EM_MMDSP_PLUS, "STMicroelectronics 64bit VLIW Data Signal Processor" }, + { EM_CYPRESS_M8C, "Cypress M8C microprocessor" }, + { EM_R32C, "Renesas R32C series microprocessors" }, + { EM_TRIMEDIA, "NXP Semiconductors TriMedia architecture family" }, + { EM_QDSP6, "QUALCOMM DSP6 Processor" }, + { EM_8051, "Intel 8051 and variants" }, + { EM_STXP7X, "STMicroelectronics STxP7x family" }, + { EM_NDS32, + "Andes Technology compact code size embedded RISC processor family" }, + { EM_ECOG1, "Cyan Technology eCOG1X family" }, + { EM_ECOG1X, "Cyan Technology eCOG1X family" }, + { EM_MAXQ30, "Dallas Semiconductor MAXQ30 Core Micro-controllers" }, + { EM_XIMO16, "New Japan Radio (NJR) 16-bit DSP Processor" }, + { EM_MANIK, "M2000 Reconfigurable RISC Microprocessor" }, + { EM_CRAYNV2, "Cray Inc. NV2 vector architecture" }, + { EM_RX, "Renesas RX family" }, + { EM_METAG, "Imagination Technologies META processor architecture" }, + { EM_MCST_ELBRUS, "MCST Elbrus general purpose hardware architecture" }, + { EM_ECOG16, "Cyan Technology eCOG16 family" }, + { EM_CR16, "National Semiconductor CompactRISC 16-bit processor" }, + { EM_ETPU, "Freescale Extended Time Processing Unit" }, + { EM_SLE9X, "Infineon Technologies SLE9X core" }, + { EM_L1OM, "Intel L1OM" }, + { EM_INTEL181, "Reserved by Intel" }, + { EM_INTEL182, "Reserved by Intel" }, + { EM_AARCH64, "ARM AArch64" }, + { EM_res184, "Reserved by ARM" }, + { EM_AVR32, "Atmel Corporation 32-bit microprocessor family" }, + { EM_STM8, "STMicroeletronics STM8 8-bit microcontroller" }, + { EM_TILE64, "Tilera TILE64 multicore architecture family" }, + { EM_TILEPRO, "Tilera TILEPro multicore architecture family" }, + { EM_MICROBLAZE, "Xilinx MicroBlaze 32-bit RISC soft processor core" }, + { EM_CUDA, "NVIDIA CUDA architecture " }, + { EM_TILEGX, "Tilera TILE-Gx multicore architecture family" }, + { EM_CLOUDSHIELD, "CloudShield architecture family" }, + { EM_COREA_1ST, "KIPO-KAIST Core-A 1st generation processor family" }, + { EM_COREA_2ND, "KIPO-KAIST Core-A 2nd generation processor family" }, + { EM_ARC_COMPACT2, "Synopsys ARCompact V2" }, + { EM_OPEN8, "Open8 8-bit RISC soft processor core" }, + { EM_RL78, "Renesas RL78 family" }, + { EM_VIDEOCORE5, "Broadcom VideoCore V processor" }, + { EM_78KOR, "Renesas 78KOR family" }, + { EM_56800EX, "Freescale 56800EX Digital Signal Controller (DSC)" }, + { EM_BA1, "Beyond BA1 CPU architecture" }, + { EM_BA2, "Beyond BA2 CPU architecture" }, + { EM_XCORE, "XMOS xCORE processor family" }, + { EM_MCHP_PIC, "Microchip 8-bit PIC(r) family" }, + { EM_INTEL205, "Reserved by Intel" }, + { EM_INTEL206, "Reserved by Intel" }, + { EM_INTEL207, "Reserved by Intel" }, + { EM_INTEL208, "Reserved by Intel" }, + { EM_INTEL209, "Reserved by Intel" }, + { EM_KM32, "KM211 KM32 32-bit processor" }, + { EM_KMX32, "KM211 KMX32 32-bit processor" }, + { EM_KMX16, "KM211 KMX16 16-bit processor" }, + { EM_KMX8, "KM211 KMX8 8-bit processor" }, + { EM_KVARC, "KM211 KVARC processor" }, + { EM_CDP, "Paneve CDP architecture family" }, + { EM_COGE, "Cognitive Smart Memory Processor" }, + { EM_COOL, "iCelero CoolEngine" }, + { EM_NORC, "Nanoradio Optimized RISC" }, + { EM_CSR_KALIMBA, "CSR Kalimba architecture family" }, + { EM_Z80, "Zilog Z80" }, + { EM_VISIUM, "Controls and Data Services VISIUMcore processor" }, + { EM_FT32, "FTDI Chip FT32 high performance 32-bit RISC architecture" }, + { EM_MOXIE, "Moxie processor family" }, + { EM_AMDGPU, "AMD GPU architecture" }, + { EM_RISCV, "RISC-V" }, + { EM_LANAI, "Lanai processor" }, + { EM_CEVA, "CEVA Processor Architecture Family" }, + { EM_CEVA_X2, "CEVA X2 Processor Family" }, + { EM_BPF, "Linux BPF – in-kernel virtual machine" }, + { EM_GRAPHCORE_IPU, "Graphcore Intelligent Processing Unit" }, + { EM_IMG1, "Imagination Technologies" }, + { EM_NFP, "Netronome Flow Processor (P)" }, + { EM_CSKY, "C-SKY processor family" }, + { EM_ARC_COMPACT3_64, "Synopsys ARCv2.3 64-bit" }, + { EM_MCS6502, "MOS Technology MCS 6502 processor" }, + { EM_ARC_COMPACT3, "Synopsys ARCv2.3 32-bit" }, + { EM_KVX, "Kalray VLIW core of the MPPA processor family" }, + { EM_65816, "WDC 65816/65C816" }, + { EM_LOONGARCH, "Loongson Loongarch" }, + { EM_KF32, "ChipON KungFu32" }, + { EM_MT, "Morpho Techologies MT processor" }, + { EM_ALPHA, "Alpha" }, + { EM_WEBASSEMBLY, "Web Assembly" }, + { EM_DLX, "OpenDLX" }, + { EM_XSTORMY16, "Sanyo XStormy16 CPU core" }, + { EM_IQ2000, "Vitesse IQ2000" }, + { EM_M32C_OLD, "M32C_OLD" }, + { EM_NIOS32, "Altera Nios" }, + { EM_CYGNUS_MEP, "Toshiba MeP Media Engine" }, + { EM_ADAPTEVA_EPIPHANY, "Adapteva EPIPHANY" }, + { EM_CYGNUS_FRV, "Fujitsu FR-V" }, + { EM_S12Z, "Freescale S12Z" }, +}; + +static const struct section_type_table_t +{ + const Elf64_Word key; + const char* str; +} section_type_table[] = { + { SHT_NULL, "NULL" }, + { SHT_PROGBITS, "PROGBITS" }, + { SHT_SYMTAB, "SYMTAB" }, + { SHT_STRTAB, "STRTAB" }, + { SHT_RELA, "RELA" }, + { SHT_HASH, "HASH" }, + { SHT_DYNAMIC, "DYNAMIC" }, + { SHT_NOTE, "NOTE" }, + { SHT_NOBITS, "NOBITS" }, + { SHT_REL, "REL" }, + { SHT_SHLIB, "SHLIB" }, + { SHT_DYNSYM, "DYNSYM" }, + { SHT_INIT_ARRAY, "INIT_ARRAY" }, + { SHT_FINI_ARRAY, "FINI_ARRAY" }, + { SHT_PREINIT_ARRAY, "PREINIT_ARRAY" }, + { SHT_GROUP, "GROUP" }, + { SHT_SYMTAB_SHNDX, "SYMTAB_SHNDX" }, + { SHT_GNU_ATTRIBUTES, "GNU_ATTRIBUTES" }, + { SHT_GNU_HASH, "GNU_HASH" }, + { SHT_GNU_LIBLIST, "GNU_LIBLIST" }, + { SHT_CHECKSUM, "CHECKSUM" }, + { SHT_LOSUNW, "LOSUNW" }, + { SHT_SUNW_move, "SUNW_move" }, + { SHT_SUNW_COMDAT, "SUNW_COMDAT" }, + { SHT_SUNW_syminfo, "SUNW_syminfo" }, + { SHT_GNU_verdef, "GNU_verdef" }, + { SHT_GNU_verneed, "GNU_verneed" }, + { SHT_GNU_versym, "GNU_versym" }, + { SHT_ARM_EXIDX, "ARM_EXIDX" }, + { SHT_ARM_PREEMPTMAP, "ARM_PREEMPTMAP" }, + { SHT_ARM_ATTRIBUTES, "ARM_ATTRIBUTES" }, + { SHT_ARM_DEBUGOVERLAY, "ARM_DEBUGOVERLAY" }, + { SHT_ARM_OVERLAYSECTION, "ARM_OVERLAYSECTION" }, + +}; + +static const struct segment_type_table_t +{ + const Elf_Word key; + const char* str; +} segment_type_table[] = { + { PT_NULL, "NULL" }, + { PT_LOAD, "LOAD" }, + { PT_DYNAMIC, "DYNAMIC" }, + { PT_INTERP, "INTERP" }, + { PT_NOTE, "NOTE" }, + { PT_SHLIB, "SHLIB" }, + { PT_PHDR, "PHDR" }, + { PT_TLS, "TLS" }, + { PT_GNU_EH_FRAME, "GNU_EH_FRAME" }, + { PT_GNU_STACK, "GNU_STACK" }, + { PT_GNU_RELRO, "GNU_RELRO" }, + { PT_GNU_PROPERTY, "GNU_PROPERTY" }, + { PT_GNU_MBIND_LO, "GNU_MBIND_LO" }, + { PT_GNU_MBIND_HI, "GNU_MBIND_HI" }, + { PT_PAX_FLAGS, "PAX_FLAGS" }, + { PT_OPENBSD_RANDOMIZE, "OPENBSD_RANDOMIZE" }, + { PT_OPENBSD_WXNEEDED, "OPENBSD_WXNEEDED " }, + { PT_OPENBSD_BOOTDATA, "OPENBSD_BOOTDATA " }, + { PT_SUNWBSS, "PT_SUNWBSS" }, + { PT_SUNWSTACK, "SUNWSTACK" }, +}; + +static const struct segment_flag_table_t +{ + const Elf_Word key; + const char* str; +} segment_flag_table[] = { + { 0, " " }, { 1, " E" }, { 2, " W " }, { 3, " WE" }, + { 4, "R " }, { 5, "R E" }, { 6, "RW " }, { 7, "RWE" }, +}; + +static const struct symbol_bind_t +{ + const Elf_Word key; + const char* str; +} symbol_bind_table[] = { + { STB_LOCAL, "LOCAL" }, { STB_GLOBAL, "GLOBAL" }, + { STB_WEAK, "WEAK" }, { STB_LOOS, "LOOS" }, + { STB_HIOS, "HIOS" }, { STB_MULTIDEF, "MULTIDEF" }, + { STB_LOPROC, "LOPROC" }, { STB_HIPROC, "HIPROC" }, +}; + +static const struct symbol_type_t +{ + const Elf_Word key; + const char* str; +} symbol_type_table[] = { + { STT_NOTYPE, "NOTYPE" }, { STT_OBJECT, "OBJECT" }, + { STT_FUNC, "FUNC" }, { STT_SECTION, "SECTION" }, + { STT_FILE, "FILE" }, { STT_COMMON, "COMMON" }, + { STT_TLS, "TLS" }, { STT_LOOS, "LOOS" }, + { STT_HIOS, "HIOS" }, { STT_LOPROC, "LOPROC" }, + { STT_HIPROC, "HIPROC" }, +}; + +static const struct dynamic_tag_t +{ + const Elf_Word key; + const char* str; +} dynamic_tag_table[] = { + { DT_NULL, "NULL" }, + { DT_NEEDED, "NEEDED" }, + { DT_PLTRELSZ, "PLTRELSZ" }, + { DT_PLTGOT, "PLTGOT" }, + { DT_HASH, "HASH" }, + { DT_STRTAB, "STRTAB" }, + { DT_SYMTAB, "SYMTAB" }, + { DT_RELA, "RELA" }, + { DT_RELASZ, "RELASZ" }, + { DT_RELAENT, "RELAENT" }, + { DT_STRSZ, "STRSZ" }, + { DT_SYMENT, "SYMENT" }, + { DT_INIT, "INIT" }, + { DT_FINI, "FINI" }, + { DT_SONAME, "SONAME" }, + { DT_RPATH, "RPATH" }, + { DT_SYMBOLIC, "SYMBOLIC" }, + { DT_REL, "REL" }, + { DT_RELSZ, "RELSZ" }, + { DT_RELENT, "RELENT" }, + { DT_PLTREL, "PLTREL" }, + { DT_DEBUG, "DEBUG" }, + { DT_TEXTREL, "TEXTREL" }, + { DT_JMPREL, "JMPREL" }, + { DT_BIND_NOW, "BIND_NOW" }, + { DT_INIT_ARRAY, "INIT_ARRAY" }, + { DT_FINI_ARRAY, "FINI_ARRAY" }, + { DT_INIT_ARRAYSZ, "INIT_ARRAYSZ" }, + { DT_FINI_ARRAYSZ, "FINI_ARRAYSZ" }, + { DT_RUNPATH, "RUNPATH" }, + { DT_FLAGS, "FLAGS" }, + { DT_ENCODING, "ENCODING" }, + { DT_PREINIT_ARRAY, "PREINIT_ARRAY" }, + { DT_PREINIT_ARRAYSZ, "PREINIT_ARRAYSZ" }, + { DT_MAXPOSTAGS, "MAXPOSTAGS" }, + { DT_GNU_HASH, "GNU_HASH" }, + { DT_TLSDESC_PLT, "TLSDESC_PLT" }, + { DT_TLSDESC_GOT, "TLSDESC_GOT" }, + { DT_GNU_CONFLICT, "GNU_CONFLICT" }, + { DT_GNU_LIBLIST, "GNU_LIBLIST" }, + { DT_CONFIG, "CONFIG" }, + { DT_DEPAUDIT, "DEPAUDIT" }, + { DT_AUDIT, "AUDIT" }, + { DT_PLTPAD, "PLTPAD" }, + { DT_MOVETAB, "MOVETAB" }, + { DT_SYMINFO, "SYMINFO" }, + { DT_ADDRRNGHI, "ADDRRNGHI" }, + { DT_VERSYM, "VERSYM" }, + { DT_RELACOUNT, "RELACOUNT" }, + { DT_RELCOUNT, "RELCOUNT" }, + { DT_FLAGS_1, "FLAGS_1" }, + { DT_VERDEF, "VERDEF" }, + { DT_VERDEFNUM, "VERDEFNUM" }, + { DT_VERNEED, "VERNEED" }, + { DT_VERNEEDNUM, "VERNEEDNUM" }, +}; + +// clang-format off +static const struct note_tag_t +{ + struct note_values_t + { + Elf64_Word type; + std::string type_str; + std::string description; + }; + std::string name; + std::vector values; +} note_tag_table[] = { + { "", + { { NT_PRSTATUS, "NT_PRSTATUS", "prstatus struct" }, + { NT_FPREGSET, "NT_FPREGSET", "fpregset struct" }, + { NT_PRPSINFO, "NT_PRPSINFO", "prpsinfo struct" }, + { NT_TASKSTRUCT, "NT_TASKSTRUCT", "task struct" }, + { NT_AUXV, "NT_AUXV", "Elfxx_auxv_t" }, + { NT_PSTATUS, "NT_PSTATUS", "pstatus struct" }, + { NT_FPREGS, "NT_FPREGS", "fpregset struct" }, + { NT_PSINFO, "NT_PSINFO", "psinfo struct" }, + { NT_LWPSTATUS, "NT_LWPSTATUS", "lwpstatus_t struct" }, + { NT_LWPSINFO, "NT_LWPSINFO", "lwpsinfo_t struct" }, + { NT_WIN32PSTATUS, "NT_WIN32PSTATUS", "win32_pstatus struct" }, + } }, + { "LINUX", + { { NT_PRXFPREG, "NT_PRXFPREG", "Contains a user_xfpregs_struct;" }, + { NT_PPC_VMX, "NT_PPC_VMX", "PowerPC Altivec/VMX registers" }, + { NT_PPC_VSX, "NT_PPC_VSX", "PowerPC VSX registers" }, + { NT_PPC_TAR, "NT_PPC_TAR", "PowerPC Target Address Register" }, + { NT_PPC_PPR, "NT_PPC_PPR", "PowerPC Program Priority Register" }, + { NT_PPC_DSCR, "NT_PPC_DSCR", "PowerPC Data Stream Control Register" }, + { NT_PPC_EBB, "NT_PPC_EBB", "PowerPC Event Based Branch Registers" }, + { NT_PPC_PMU, "NT_PPC_PMU", "PowerPC Performance Monitor Registers" }, + { NT_PPC_TM_CGPR, "NT_PPC_TM_CGPR", "PowerPC TM checkpointed GPR Registers" }, + { NT_PPC_TM_CFPR, "NT_PPC_TM_CFPR", "PowerPC TM checkpointed FPR Registers" }, + { NT_PPC_TM_CVMX, "NT_PPC_TM_CVMX", "PowerPC TM checkpointed VMX Registers" }, + { NT_PPC_TM_CVSX, "NT_PPC_TM_CVSX", "PowerPC TM checkpointed VSX Registers" }, + { NT_PPC_TM_SPR, "NT_PPC_TM_SPR", "PowerPC TM Special Purpose Registers" }, + { NT_PPC_TM_CTAR, "NT_PPC_TM_CTAR", "PowerPC TM checkpointed TAR" }, + { NT_PPC_TM_CPPR, "NT_PPC_TM_CPPR", "PowerPC TM checkpointed PPR" }, + { NT_PPC_TM_CDSCR, "NT_PPC_TM_CDSCR", "PowerPC TM checkpointed Data SCR" }, + { NT_386_TLS, "NT_386_TLS", "x86 TLS information" }, + { NT_386_IOPERM, "NT_386_IOPERM", "x86 io permissions" }, + { NT_X86_XSTATE, "NT_X86_XSTATE", "x86 XSAVE extended state" }, + { NT_X86_CET, "NT_X86_CET", "x86 CET state" }, + { NT_S390_HIGH_GPRS, "NT_S390_HIGH_GPRS", "S/390 upper halves of GPRs " }, + { NT_S390_TIMER, "NT_S390_TIMER", "S390 timer" }, + { NT_S390_TODCMP, "NT_S390_TODCMP", "S390 TOD clock comparator" }, + { NT_S390_TODPREG, "NT_S390_TODPREG", "S390 TOD programmable register" }, + { NT_S390_CTRS, "NT_S390_CTRS", "S390 control registers" }, + { NT_S390_PREFIX, "NT_S390_PREFIX", "S390 prefix register" }, + { NT_S390_LAST_BREAK, "NT_S390_LAST_BREAK", "S390 breaking event address" }, + { NT_S390_SYSTEM_CALL, "NT_S390_SYSTEM_CALL", "S390 system call restart data" }, + { NT_S390_TDB, "NT_S390_TDB", "S390 transaction diagnostic block" }, + { NT_S390_VXRS_LOW, "NT_S390_VXRS_LOW", "S390 vector registers 0-15 upper half" }, + { NT_S390_VXRS_HIGH, "NT_S390_VXRS_HIGH", "S390 vector registers 16-31" }, + { NT_S390_GS_CB, "NT_S390_GS_CB", "s390 guarded storage registers" }, + { NT_S390_GS_BC, "NT_S390_GS_BC", "s390 guarded storage broadcast control block" }, + { NT_ARM_VFP, "NT_ARM_VFP", "ARM VFP registers" }, + { NT_ARM_TLS, "NT_ARM_TLS", "AArch TLS registers" }, + { NT_ARM_HW_BREAK, "NT_ARM_HW_BREAK", "AArch hardware breakpoint registers" }, + { NT_ARM_HW_WATCH, "NT_ARM_HW_WATCH", "AArch hardware watchpoint registers" }, + { NT_ARM_SVE, "NT_ARM_SVE", "AArch SVE registers. " }, + { NT_ARM_PAC_MASK, "NT_ARM_PAC_MASK", "AArch pointer authentication code masks" }, + { NT_ARM_PACA_KEYS, "NT_ARM_PACA_KEYS", "ARM pointer authentication address keys" }, + { NT_ARM_PACG_KEYS, "NT_ARM_PACG_KEYS", "ARM pointer authentication generic keys" }, + { NT_ARM_TAGGED_ADDR_CTRL, "NT_ARM_TAGGED_ADDR_CTRL", "AArch64 tagged address control (prctl())" }, + { NT_ARM_PAC_ENABLED_KEYS, "NT_ARM_PAC_ENABLED_KEYS", "AArch64 pointer authentication enabled keys (prctl())" }, + { NT_ARC_V2, "NT_ARC_V2", "ARC HS accumulator/extra registers. " }, + { NT_LARCH_CPUCFG, "NT_LARCH_CPUCFG", "LoongArch CPU config registers" }, + { NT_LARCH_CSR, "NT_LARCH_CSR", "LoongArch Control State Registers" }, + { NT_LARCH_LSX, "NT_LARCH_LSX", "LoongArch SIMD eXtension registers" }, + { NT_LARCH_LASX, "NT_LARCH_LASX", "LoongArch Advanced SIMD eXtension registers" }, + { NT_RISCV_CSR, "NT_RISCV_CSR", "RISC-V Control and Status Registers" }, + } }, + { "CORE", + { { NT_LARCH_LBT, "NT_LARCH_LBT", "LoongArch Binary Translation registers" } + } }, + { "FreeBSD", + { { NT_FREEBSD_THRMISC, "NT_FREEBSD_THRMISC", "Thread miscellaneous info." }, + { NT_FREEBSD_PROCSTAT_PROC, "NT_FREEBSD_PROCSTAT_PROC", "Procstat proc data." }, + { NT_FREEBSD_PROCSTAT_FILES, "NT_FREEBSD_PROCSTAT_FILES", "Procstat files data." }, + { NT_FREEBSD_PROCSTAT_VMMAP, "NT_FREEBSD_PROCSTAT_VMMAP", "Procstat vmmap data." }, + { NT_FREEBSD_PROCSTAT_GROUPS, "NT_FREEBSD_PROCSTAT_GROUPS", "Procstat groups data." }, + { NT_FREEBSD_PROCSTAT_UMASK, "NT_FREEBSD_PROCSTAT_UMASK", "Procstat umask data." }, + { NT_FREEBSD_PROCSTAT_RLIMIT, "NT_FREEBSD_PROCSTAT_RLIMIT", "Procstat rlimit data." }, + { NT_FREEBSD_PROCSTAT_OSREL, "NT_FREEBSD_PROCSTAT_OSREL", "Procstat osreldate data." }, + { NT_FREEBSD_PROCSTAT_PSSTRINGS, "NT_FREEBSD_PROCSTAT_PSSTRINGS", "Procstat ps_strings data." }, + { NT_FREEBSD_PROCSTAT_AUXV, "NT_FREEBSD_PROCSTAT_AUXV", "Procstat auxv data." }, + { NT_FREEBSD_PTLWPINFO, "NT_FREEBSD_PTLWPINFO", "Thread ptrace miscellaneous info." }, + } }, + { "NetBSD-CORE", + { { NT_NETBSDCORE_PROCINFO, "NT_NETBSDCORE_PROCINFO", "Has a struct procinfo" }, + { NT_NETBSDCORE_AUXV, "NT_NETBSDCORE_AUXV", "Has auxv data" }, + { NT_NETBSDCORE_LWPSTATUS, "NT_NETBSDCORE_LWPSTATUS", "Has LWPSTATUS data" }, + { NT_NETBSDCORE_FIRSTMACH, "NT_NETBSDCORE_FIRSTMACH", "start of machdep note types" }, + } }, + { "OpenBSD", + { { NT_OPENBSD_PROCINFO, "NT_OPENBSD_PROCINFO", "" }, + { NT_OPENBSD_AUXV, "NT_OPENBSD_AUXV", "" }, + { NT_OPENBSD_REGS, "NT_OPENBSD_REGS", "" }, + { NT_OPENBSD_FPREGS, "NT_OPENBSD_FPREGS", "" }, + { NT_OPENBSD_XFPREGS, "NT_OPENBSD_XFPREGS", "" }, + { NT_OPENBSD_WCOOKIE, "NT_OPENBSD_WCOOKIE", "" }, + } }, + { "SPU", + { { NT_SPU, "NT_SPU", "" } + } }, + { "GNU", + { + { NT_GNU_ABI_TAG, "NT_GNU_ABI_TAG", "GNU ABI tag" }, + { NT_GNU_HWCAP, "NT_GNU_HWCAP", "Used by ld.so and kernel vDSO" }, + { NT_GNU_BUILD_ID, "NT_GNU_BUILD_ID", "Build ID of the binary" }, + { NT_GNU_GOLD_VERSION, "NT_GNU_GOLD_VERSION", "Version of GNU gold used to link the binary" }, + { NT_GNU_PROPERTY_TYPE_0, "NT_GNU_PROPERTY_TYPE_0", "Property type 0" }, + // { NT_GNU_PROPERTY_TYPE_1, "NT_GNU_PROPERTY_TYPE_1", "Property type 1" }, + // { NT_GNU_PROPERTY_TYPE_2, "NT_GNU_PROPERTY_TYPE_2", "Property type 2" }, + // { NT_GNU_PROPERTY_TYPE_3, "NT_GNU_PROPERTY_TYPE_3", "Property type 3" }, + // { NT_GNU_PROPERTY_TYPE_4, "NT_GNU_PROPERTY_TYPE_4", "Property type 4" }, + // { NT_GNU_PROPERTY_TYPE_5, "NT_GNU_PROPERTY_TYPE_5", "Property type 5" }, + // { NT_GNU_PROPERTY_TYPE_6, "NT_GNU_PROPERTY_TYPE_6", "Property type 6" }, + // { NT_GNU_PROPERTY_TYPE_7, "NT_GNU_PROPERTY_TYPE_7", "Property type 7" }, + // { NT_GNU_PROPERTY_TYPE_8, "NT_GNU_PROPERTY_TYPE_8", "Property type 8" }, + // { NT_GNU_PROPERTY_TYPE_9, "NT_GNU_PROPERTY_TYPE_9", "Property type 9" }, + // { NT_GNU_PROPERTY_TYPE_10, "NT_GNU_PROPERTY_TYPE_10", "Property type 10" }, + // { NT_GNU_PROPERTY_TYPE_11, "NT_GNU_PROPERTY_TYPE_11", "Property type 11" }, + // { NT_GNU_PROPERTY_TYPE_12, "NT_GNU_PROPERTY_TYPE_12", "Property type 12" }, + // { NT_GNU_PROPERTY_TYPE_13, "NT_GNU_PROPERTY_TYPE_13", "Property type 13" }, + // { NT_GNU_PROPERTY_TYPE_14, "NT_GNU_PROPERTY_TYPE_14", "Property type 14" }, + } }, + // { "SOLARIS", + // { { NT_SOLARIS_AUXV, "NT_SOLARIS_AUXV", "" } + // } }, + // { "AIX", + // { { NT_AIX_AUXV, "NT_AIX_AUXV", "" } + // } }, + // { "IRIX", + // { { NT_IRIX_FPREGS, "NT_IRIX_FPREGS", "" } + // } }, +}; +// clang-format on + +static const ELFIO::Elf_Xword MAX_DATA_ENTRIES = 64; + +//------------------------------------------------------------------------------ +// Class representing the ELF dump functionality +class dump +{ +#define DUMP_DEC_FORMAT( width ) \ + std::setw( width ) << std::setfill( ' ' ) << std::dec << std::right +#define DUMP_HEX0x_FORMAT( width ) \ + "0x" << std::setw( width ) << std::setfill( '0' ) << std::hex << std::right +#define DUMP_HEX_FORMAT( width ) \ + std::setw( width ) << std::setfill( '0' ) << std::hex << std::right +#define DUMP_STR_FORMAT( width ) \ + std::setw( width ) << std::setfill( ' ' ) << std::hex << std::left + + public: + //------------------------------------------------------------------------------ + // Dumps the ELF header information + static void header( std::ostream& out, const elfio& reader ) + { + if ( !reader.get_header_size() ) { + return; + } + out << "ELF Header" << std::endl + << std::endl + << " Class: " << str_class( reader.get_class() ) << std::endl + << " Encoding: " << str_endian( reader.get_encoding() ) + << std::endl + << " ELFVersion: " << str_version( reader.get_elf_version() ) + << std::endl + << " OS/ABI: " << str_os_abi( reader.get_os_abi() ) + << std::endl + << " ABI Version:" << (int)reader.get_abi_version() << std::endl + << " Type: " << str_type( reader.get_type() ) << std::endl + << " Machine: " << str_machine( reader.get_machine() ) + << std::endl + << " Version: " << str_version( reader.get_version() ) + << std::endl + << " Entry: " << "0x" << std::hex << reader.get_entry() + << std::endl + << " Flags: " << "0x" << std::hex << reader.get_flags() + << std::endl + << std::endl; + } + + //------------------------------------------------------------------------------ + // Dumps the section headers information + static void section_headers( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.sections.size(); + + if ( n == 0 ) { + return; + } + + out << "Section Headers:" << std::endl; + if ( reader.get_class() == ELFCLASS32 ) { // Output for 32-bit + out << "[ Nr ] Type Addr Size ES Flg " + "Lk Inf Al Name" + << std::endl; + } + else { // Output for 64-bit + out << "[ Nr ] Type Addr Size " + " Offset Flg" + << std::endl + << " ES Lk Inf Al Name" << std::endl; + } + + for ( Elf_Half i = 0; i < n; ++i ) { // For all sections + const section* sec = reader.sections[i]; + section_header( out, i, sec, reader.get_class() ); + } + + out << "Key to Flags: W (write), A (alloc), X (execute), " << std::endl; + out << " M (merge), S (strings), I (info)," << std::endl; + out << " L (link order), O (extra OS processing required)," + << std::endl; + out << " G (group), T (TLS), C (compressed), E (exclude)" + << std::endl; + } + + //------------------------------------------------------------------------------ + // Dumps a single section header information + static void section_header( std::ostream& out, + Elf_Half no, + const section* sec, + unsigned char elf_class ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + // clang-format off + if ( elf_class == ELFCLASS32 ) { // Output for 32-bit + out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " + << DUMP_STR_FORMAT( 17 ) << str_section_type( sec->get_type() ) + << " " << DUMP_HEX0x_FORMAT( 8 ) << sec->get_address() << " " + << DUMP_HEX0x_FORMAT( 8 ) << sec->get_size() << " " + << DUMP_HEX0x_FORMAT( 2 ) << sec->get_entry_size() << " " + << DUMP_STR_FORMAT( 3 ) << section_flags( sec->get_flags() ) + << " " << DUMP_HEX0x_FORMAT( 2 ) << sec->get_link() << " " + << DUMP_HEX0x_FORMAT( 3 ) << sec->get_info() << " " + << DUMP_HEX0x_FORMAT( 2 ) << sec->get_addr_align() << " " + << DUMP_STR_FORMAT( 17 ) << sec->get_name() << " " << std::endl; + } + else { // Output for 64-bit + out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " + << DUMP_STR_FORMAT( 17 ) << str_section_type( sec->get_type() ) << " " + << DUMP_HEX0x_FORMAT( 16 ) << sec->get_address() << " " + << DUMP_HEX0x_FORMAT( 16 ) << sec->get_size() << " " + << DUMP_HEX0x_FORMAT( 8 ) << sec->get_offset() << " " + << DUMP_STR_FORMAT( 3) << section_flags( sec->get_flags() ) + << std::endl + << DUMP_STR_FORMAT( 8 ) << " " + << DUMP_HEX0x_FORMAT( 4 ) << sec->get_entry_size() << " " + << DUMP_HEX0x_FORMAT( 4 ) << sec->get_link() << " " + << DUMP_HEX0x_FORMAT( 4 ) << sec->get_info() << " " + << DUMP_HEX0x_FORMAT( 4 ) << sec->get_addr_align() << " " + << DUMP_STR_FORMAT( 17 ) << sec->get_name() + << std::endl; + } + // clang-format on + + out.flags( original_flags ); + + return; + } + + //------------------------------------------------------------------------------ + // Dumps the segment headers information + static void segment_headers( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.segments.size(); + if ( n == 0 ) { + return; + } + + out << "Program Headers:" << std::endl; + if ( reader.get_class() == ELFCLASS32 ) { // Output for 32-bit + out << "[ Nr ] Type VirtAddr PhysAddr FileSize " + "Mem.Size Flags Align" + << std::endl; + } + else { // Output for 64-bit + out << "[ Nr ] Type Offset VirtAddr " + " PhysAddr" + + << std::endl + << " FileSize MemSize " + " Flags Align" + << std::endl; + } + + for ( Elf_Half i = 0; i < n; ++i ) { + const segment* seg = reader.segments[i]; + segment_header( out, i, seg, reader.get_class() ); + } + + out << std::endl; + for ( Elf_Half i = 0; i < n; ++i ) { + out << "[" << i << "]" << " "; + const segment* seg = reader.segments[i]; + for ( Elf_Half j = 0; j < seg->get_sections_num(); j++ ) { + const section* sec = + reader.sections[seg->get_section_index_at( j )]; + out << sec->get_name() << " "; + } + out << std::endl; + } + + out << std::endl; + } + + //------------------------------------------------------------------------------ + // Dumps a single segment header information + static void segment_header( std::ostream& out, + Elf_Half no, + const segment* seg, + unsigned int elf_class ) + { + std::ios_base::fmtflags original_flags = out.flags(); + // clang-format off + if ( elf_class == ELFCLASS32 ) { // Output for 32-bit + out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " + << DUMP_STR_FORMAT( 14 ) << str_segment_type( seg->get_type() ) + << " " << DUMP_HEX0x_FORMAT( 8 ) << seg->get_virtual_address() + << " " << DUMP_HEX0x_FORMAT( 8 ) << seg->get_physical_address() + << " " << DUMP_HEX0x_FORMAT( 8 ) << seg->get_file_size() << " " + << DUMP_HEX0x_FORMAT( 8 ) << seg->get_memory_size() << " " + << DUMP_STR_FORMAT( 8 ) << str_segment_flag( seg->get_flags() ) + << " " << DUMP_HEX0x_FORMAT( 8 ) << seg->get_align() << " " + << std::endl; + } + else { // Output for 64-bit + out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " + << DUMP_STR_FORMAT( 14 ) << str_segment_type( seg->get_type() ) << " " + << DUMP_HEX0x_FORMAT( 16 ) << seg->get_offset() << " " + << DUMP_HEX0x_FORMAT( 16 ) << seg->get_virtual_address() << " " + << DUMP_HEX0x_FORMAT( 16 ) << seg->get_physical_address() + << std::endl + << DUMP_STR_FORMAT( 23 ) << " " + << DUMP_HEX0x_FORMAT( 16 ) << seg->get_file_size() << " " + << DUMP_HEX0x_FORMAT( 16 ) << seg->get_memory_size() << " " + << DUMP_STR_FORMAT( 3 ) << str_segment_flag( seg->get_flags() ) << " " + << DUMP_HEX0x_FORMAT( 1 ) << seg->get_align() + << std::endl; + } + // clang-format on + + out.flags( original_flags ); + } + + //------------------------------------------------------------------------------ + // Dumps the symbol tables information + static void symbol_tables( std::ostream& out, const elfio& reader ) + { + for ( const auto& sec : reader.sections ) { // For all sections + if ( SHT_SYMTAB == sec->get_type() || + SHT_DYNSYM == sec->get_type() ) { + const_symbol_section_accessor symbols( reader, sec.get() ); + + Elf_Xword sym_no = symbols.get_symbols_num(); + if ( sym_no == 0 ) { + continue; + } + + out << "Symbol table (" << sec->get_name() << ")" << std::endl; + if ( reader.get_class() == ELFCLASS32 ) { // Output for 32-bit + out << "[ Nr ] Value Size Type Bind " + " Sect Name" + << std::endl; + } + else { // Output for 64-bit + out << "[ Nr ] Value Size " + "Type Bind Sect" + << std::endl + << " Name" << std::endl; + } + for ( Elf_Xword i = 0; i < sym_no; ++i ) { + std::string name; + Elf64_Addr value = 0; + Elf_Xword size = 0; + unsigned char bind = 0; + unsigned char type = 0; + Elf_Half section = 0; + unsigned char other = 0; + symbols.get_symbol( i, name, value, size, bind, type, + section, other ); + symbol_table( out, i, name, value, size, bind, type, + section, reader.get_class() ); + } + + out << std::endl; + } + } + } + + //------------------------------------------------------------------------------ + // Dumps a single symbol table entry information + static void symbol_table( std::ostream& out, + Elf_Xword no, + const std::string& name, + Elf64_Addr value, + Elf_Xword size, + unsigned char bind, + unsigned char type, + Elf_Half section, + unsigned int elf_class ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + if ( elf_class == ELFCLASS32 ) { // Output for 32-bit + out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " + << DUMP_HEX0x_FORMAT( 8 ) << value << " " + << DUMP_HEX0x_FORMAT( 8 ) << size << " " << DUMP_STR_FORMAT( 7 ) + << str_symbol_type( type ) << " " << DUMP_STR_FORMAT( 8 ) + << str_symbol_bind( bind ) << " " << DUMP_DEC_FORMAT( 5 ) + << section << " " << DUMP_STR_FORMAT( 1 ) << name << " " + << std::endl; + } + else { // Output for 64-bit + out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " + << DUMP_HEX0x_FORMAT( 16 ) << value << " " + << DUMP_HEX0x_FORMAT( 16 ) << size << " " + << DUMP_STR_FORMAT( 7 ) << str_symbol_type( type ) << " " + << DUMP_STR_FORMAT( 8 ) << str_symbol_bind( bind ) << " " + << DUMP_DEC_FORMAT( 5 ) << section << " " << std::endl + << " " << DUMP_STR_FORMAT( 1 ) << name << " " + << std::endl; + } + + out.flags( original_flags ); + } + + //------------------------------------------------------------------------------ + // Dumps the notes information + static void notes( std::ostream& out, const elfio& reader ) + { + for ( const auto& sec : reader.sections ) { // For all sections + if ( SHT_NOTE == sec->get_type() ) { // Look at notes + note_section_accessor notes( reader, sec.get() ); + Elf_Word no_notes = notes.get_notes_num(); + + if ( no_notes == 0 ) + continue; + + out << "Note section (" << sec->get_name() << ")" << std::endl + << " No Name Data size Description" + << std::endl; + for ( Elf_Word j = 0; j < no_notes; ++j ) { // For all notes + Elf_Word type; + std::string name; + char* desc; + Elf_Word descsz; + + if ( notes.get_note( j, type, name, desc, descsz ) ) { + // 'name' usually contains \0 at the end. Remove it + name = name.c_str(); + note( out, j, type, name, desc, descsz ); + out << std::endl; + } + } + + out << std::endl; + } + } + + Elf_Half no = reader.segments.size(); + for ( Elf_Half i = 0; i < no; ++i ) { // For all segments + segment* seg = reader.segments[i]; + if ( PT_NOTE == seg->get_type() ) { // Look at notes + note_segment_accessor notes( reader, seg ); + Elf_Word no_notes = notes.get_notes_num(); + + if ( no_notes == 0 ) + continue; + + out << "Note segment (" << i << ")" << std::endl + << " No Name Data size Description" + << std::endl; + for ( Elf_Word j = 0; j < no_notes; ++j ) { // For all notes + Elf_Word type; + std::string name; + char* desc; + Elf_Word descsz; + + if ( notes.get_note( j, type, name, desc, descsz ) ) { + // 'name' usually contains \0 at the end. Remove it + name = name.c_str(); + note( out, j, type, name, desc, descsz ); + out << std::endl; + } + } + + out << std::endl; + } + } + } + + //------------------------------------------------------------------------------ + // Dumps a single note information + static void note( std::ostream& out, + int no, + Elf_Word type, + const std::string& name, + void* desc, + Elf_Word descsz ) + { + out << " [" << DUMP_DEC_FORMAT( 2 ) << no << "] "; + + const auto name_group = std::find_if( + std::begin( note_tag_table ), std::end( note_tag_table ), + [&name]( const note_tag_t& entry ) { return entry.name == name; } ); + + std::vector::const_iterator type_value; + if ( name_group != std::end( note_tag_table ) ) { + type_value = std::find_if( + name_group->values.begin(), name_group->values.end(), + [&type]( const note_tag_t::note_values_t& e ) { + return e.type == type; + } ); + } + + if ( name_group != std::end( note_tag_table ) && + type_value != name_group->values.end() ) { + out << DUMP_STR_FORMAT( 12 ) << name_group->name << " " + << DUMP_HEX0x_FORMAT( 8 ) << descsz << " " + << type_value->type_str << " (" << type_value->description + << ")"; + } + else { + out << DUMP_STR_FORMAT( 12 ) << name << " " + << DUMP_HEX0x_FORMAT( 8 ) << descsz << " " + << DUMP_HEX0x_FORMAT( 8 ) << type; + } + + if ( descsz != 0 ) { + for ( Elf_Word i = 0; i < descsz; ++i ) { + if ( i % 16 == 0 ) { + out << std::endl << " "; + } + out << DUMP_HEX_FORMAT( 2 ) + << ( std::uint32_t )( (std::uint8_t*)( desc ) )[i]; + } + } + } + + //------------------------------------------------------------------------------ + // Dumps the module information + static void modinfo( std::ostream& out, const elfio& reader ) + { + for ( const auto& sec : reader.sections ) { // For all sections + if ( ".modinfo" == sec->get_name() ) { // Look for the section + out << "Section .modinfo" << std::endl; + + const_modinfo_section_accessor modinfo( sec.get() ); + for ( Elf_Word i = 0; i < modinfo.get_attribute_num(); i++ ) { + std::string field; + std::string value; + if ( modinfo.get_attribute( i, field, value ) ) { + out << " " << std::setw( 20 ) << field + << std::setw( 0 ) << " = " << value << std::endl; + } + } + + out << std::endl; + break; + } + } + } + + //------------------------------------------------------------------------------ + // Dumps the dynamic tags information + static void dynamic_tags( std::ostream& out, + const elfio& reader, + bool name_only = false ) + { + for ( const auto& sec : reader.sections ) { // For all sections + if ( SHT_DYNAMIC == sec->get_type() ) { + dynamic_section_accessor dynamic( reader, sec.get() ); + + Elf_Xword dyn_no = dynamic.get_entries_num(); + if ( dyn_no == 0 ) + continue; + if ( !name_only ) { + out << "Dynamic section (" << sec->get_name() << ")" + << std::endl; + out << "[ Nr ] Tag Name/Value" << std::endl; + } + for ( Elf_Xword i = 0; i < dyn_no; ++i ) { + Elf_Xword tag = 0; + Elf_Xword value = 0; + std::string str; + dynamic.get_entry( i, tag, value, str ); + dynamic_tag( out, i, tag, value, str, reader.get_class(), + name_only ); + if ( DT_NULL == tag ) { + break; + } + } + if ( !name_only ) { + out << std::endl; + } + } + } + } + + //------------------------------------------------------------------------------ + // Dumps a single dynamic tag information + static void dynamic_tag( std::ostream& out, + Elf_Xword no, + Elf_Xword tag, + Elf_Xword value, + const std::string& str, + unsigned int /*elf_class*/, + bool name_only = false ) + { + if ( name_only ) { + if ( str.empty() || tag != DT_NEEDED ) { + return; + } + out << str << std::endl; + return; + } + out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " + << DUMP_STR_FORMAT( 16 ) << str_dynamic_tag( tag ) << " "; + if ( str.empty() ) { + out << DUMP_HEX0x_FORMAT( 16 ) << value << " "; + } + else { + out << DUMP_STR_FORMAT( 32 ) << str << " "; + } + out << std::endl; + } + + //------------------------------------------------------------------------------ + // Dumps the section data + static void section_data( std::ostream& out, const section* sec ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + out << sec->get_name() << std::endl; + const char* pdata = sec->get_data(); + if ( pdata ) { + ELFIO::Elf_Xword i; + for ( i = 0; i < std::min( sec->get_size(), MAX_DATA_ENTRIES ); + ++i ) { + if ( i % 16 == 0 ) { + out << "[" << DUMP_HEX0x_FORMAT( 8 ) << i << "]"; + } + + out << " " << DUMP_HEX0x_FORMAT( 2 ) + << ( pdata[i] & 0x000000FF ); + + if ( i % 16 == 15 ) { + out << std::endl; + } + } + if ( i % 16 != 0 ) { + out << std::endl; + } + + out.flags( original_flags ); + } + + return; + } + + //------------------------------------------------------------------------------ + // Dumps all sections data + static void section_datas( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.sections.size(); + + if ( n == 0 ) { + return; + } + + out << "Section Data:" << std::endl; + + for ( Elf_Half i = 1; i < n; ++i ) { // For all sections + const section* sec = reader.sections[i]; + if ( sec->get_type() == SHT_NOBITS ) { + continue; + } + section_data( out, sec ); + } + + out << std::endl; + } + + //------------------------------------------------------------------------------ + // Dumps the segment data + static void + segment_data( std::ostream& out, Elf_Half no, const segment* seg ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + out << "Segment # " << no << std::endl; + const char* pdata = seg->get_data(); + if ( pdata ) { + ELFIO::Elf_Xword i; + for ( i = 0; i < std::min( seg->get_file_size(), MAX_DATA_ENTRIES ); + ++i ) { + if ( i % 16 == 0 ) { + out << "[" << DUMP_HEX0x_FORMAT( 8 ) << i << "]"; + } + + out << " " << DUMP_HEX0x_FORMAT( 2 ) + << ( pdata[i] & 0x000000FF ); + + if ( i % 16 == 15 ) { + out << std::endl; + } + } + if ( i % 16 != 0 ) { + out << std::endl; + } + + out.flags( original_flags ); + } + + return; + } + + //------------------------------------------------------------------------------ + // Dumps all segments data + static void segment_datas( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.segments.size(); + + if ( n == 0 ) { + return; + } + + out << "Segment Data:" << std::endl; + + for ( Elf_Half i = 0; i < n; ++i ) { // For all sections + const segment* seg = reader.segments[i]; + segment_data( out, i, seg ); + } + + out << std::endl; + } + +//------------------------------------------------------------------------------ +#define STR_FUNC_TABLE( name ) \ + template static std::string str_##name( const T key ) \ + { \ + return format_assoc( name##_table, key ); \ + } + + STR_FUNC_TABLE( class ) + STR_FUNC_TABLE( endian ) + STR_FUNC_TABLE( version ) + STR_FUNC_TABLE( os_abi ) + STR_FUNC_TABLE( type ) + STR_FUNC_TABLE( machine ) + STR_FUNC_TABLE( section_type ) + STR_FUNC_TABLE( segment_type ) + STR_FUNC_TABLE( segment_flag ) + STR_FUNC_TABLE( symbol_bind ) + STR_FUNC_TABLE( symbol_type ) + STR_FUNC_TABLE( dynamic_tag ) + +#undef STR_FUNC_TABLE + + private: + //------------------------------------------------------------------------------ + template + std::string static find_value_in_table( const T& table, const K& key ) + { + std::string res = "?"; + for ( unsigned int i = 0; i < sizeof( table ) / sizeof( table[0] ); + ++i ) { + if ( table[i].key == key ) { + res = table[i].str; + break; + } + } + + return res; + } + + //------------------------------------------------------------------------------ + template + static std::string format_assoc( const T& table, const K& key ) + { + std::string str = find_value_in_table( table, key ); + if ( str == "?" ) { + std::ostringstream oss; + oss << str << " (0x" << std::hex << key << ")"; + str = oss.str(); + } + + return str; + } + + //------------------------------------------------------------------------------ + template + static std::string format_assoc( const T& table, const char key ) + { + return format_assoc( table, (const int)key ); + } + + //------------------------------------------------------------------------------ + static std::string section_flags( Elf_Xword flags ) + { + std::string ret = ""; + if ( flags & SHF_WRITE ) { + ret += "W"; + } + if ( flags & SHF_ALLOC ) { + ret += "A"; + } + if ( flags & SHF_EXECINSTR ) { + ret += "X"; + } + if ( flags & SHF_MERGE ) { + ret += "M"; + } + if ( flags & SHF_STRINGS ) { + ret += "S"; + } + if ( flags & SHF_INFO_LINK ) { + ret += "I"; + } + if ( flags & SHF_LINK_ORDER ) { + ret += "L"; + } + if ( flags & SHF_OS_NONCONFORMING ) { + ret += "O"; + } + if ( flags & SHF_GROUP ) { + ret += "G"; + } + if ( flags & SHF_TLS ) { + ret += "T"; + } + if ( flags & SHF_COMPRESSED ) { + ret += "C"; + } + if ( flags & SHF_EXCLUDE ) { + ret += "E"; + } + if ( flags & SHF_GNU_MBIND ) { + ret += "D"; + } + + return ret; + } + +#undef DUMP_DEC_FORMAT +#undef DUMP_HEX0x_FORMAT +#undef DUMP_STR_FORMAT +}; // class dump +} // namespace ELFIO + +#endif // ELFIO_DUMP_HPP diff --git a/emulator/include/elfio/elfio_dynamic.hpp b/emulator/include/elfio/elfio_dynamic.hpp new file mode 100644 index 0000000..83c55bb --- /dev/null +++ b/emulator/include/elfio/elfio_dynamic.hpp @@ -0,0 +1,300 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_DYNAMIC_HPP +#define ELFIO_DYNAMIC_HPP + +#include + +namespace ELFIO { + +//------------------------------------------------------------------------------ +// Template class for accessing dynamic sections +template class dynamic_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + // Constructor + explicit dynamic_section_accessor_template( const elfio& elf_file, + S* section ) + : elf_file( elf_file ), dynamic_section( section ), entries_num( 0 ) + { + } + + //------------------------------------------------------------------------------ + // Returns the number of entries in the dynamic section + Elf_Xword get_entries_num() const + { + size_t needed_entry_size = -1; + if ( elf_file.get_class() == ELFCLASS32 ) { + needed_entry_size = sizeof( Elf32_Dyn ); + } + else { + needed_entry_size = sizeof( Elf64_Dyn ); + } + + if ( ( 0 == entries_num ) && + ( 0 != dynamic_section->get_entry_size() && + dynamic_section->get_entry_size() >= needed_entry_size ) ) { + entries_num = + dynamic_section->get_size() / dynamic_section->get_entry_size(); + Elf_Xword i; + Elf_Xword tag = DT_NULL; + Elf_Xword value = 0; + std::string str; + for ( i = 0; i < entries_num; i++ ) { + get_entry( i, tag, value, str ); + if ( tag == DT_NULL ) + break; + } + entries_num = std::min( entries_num, i + 1 ); + } + + return entries_num; + } + + //------------------------------------------------------------------------------ + // Retrieves an entry from the dynamic section + bool get_entry( Elf_Xword index, + Elf_Xword& tag, + Elf_Xword& value, + std::string& str ) const + { + if ( index >= get_entries_num() ) { // Is index valid + return false; + } + + if ( elf_file.get_class() == ELFCLASS32 ) { + generic_get_entry_dyn( index, tag, value ); + } + else { + generic_get_entry_dyn( index, tag, value ); + } + + // If the tag has a string table reference - prepare the string + if ( tag == DT_NEEDED || tag == DT_SONAME || tag == DT_RPATH || + tag == DT_RUNPATH ) { + string_section_accessor strsec( + elf_file.sections[get_string_table_index()] ); + const char* result = strsec.get_string( (Elf_Word)value ); + if ( nullptr == result ) { + str.clear(); + return false; + } + str = result; + } + else { + str.clear(); + } + + return true; + } + + //------------------------------------------------------------------------------ + // Adds an entry to the dynamic section + void add_entry( Elf_Xword tag, Elf_Xword value ) + { + if ( elf_file.get_class() == ELFCLASS32 ) { + generic_add_entry_dyn( tag, value ); + } + else { + generic_add_entry_dyn( tag, value ); + } + } + + //------------------------------------------------------------------------------ + // Adds an entry with a string value to the dynamic section + void add_entry( Elf_Xword tag, const std::string& str ) + { + string_section_accessor strsec( + elf_file.sections[get_string_table_index()] ); + Elf_Xword value = strsec.add_string( str ); + add_entry( tag, value ); + } + + private: + //------------------------------------------------------------------------------ + // Returns the index of the string table + Elf_Half get_string_table_index() const + { + return (Elf_Half)dynamic_section->get_link(); + } + + //------------------------------------------------------------------------------ + // Retrieves a generic entry from the dynamic section + template + void generic_get_entry_dyn( Elf_Xword index, + Elf_Xword& tag, + Elf_Xword& value ) const + { + const auto& convertor = elf_file.get_convertor(); + + // Check unusual case when dynamic section has no data + if ( dynamic_section->get_data() == nullptr || + dynamic_section->get_entry_size() < sizeof( T ) ) { + tag = DT_NULL; + value = 0; + return; + } + + // Check for integer overflow in size calculation + if ( index > ( dynamic_section->get_size() / + dynamic_section->get_entry_size() ) - + 1 ) { + tag = DT_NULL; + value = 0; + return; + } + + // Check for integer overflow in pointer arithmetic + Elf_Xword offset = index * dynamic_section->get_entry_size(); + if ( offset > dynamic_section->get_size() - sizeof( T ) ) { + tag = DT_NULL; + value = 0; + return; + } + + const T* pEntry = + reinterpret_cast( dynamic_section->get_data() + offset ); + tag = ( *convertor )( pEntry->d_tag ); + switch ( tag ) { + case DT_NULL: + case DT_SYMBOLIC: + case DT_TEXTREL: + case DT_BIND_NOW: + value = 0; + break; + case DT_NEEDED: + case DT_PLTRELSZ: + case DT_RELASZ: + case DT_RELAENT: + case DT_STRSZ: + case DT_SYMENT: + case DT_SONAME: + case DT_RPATH: + case DT_RELSZ: + case DT_RELENT: + case DT_PLTREL: + case DT_INIT_ARRAYSZ: + case DT_FINI_ARRAYSZ: + case DT_RUNPATH: + case DT_FLAGS: + case DT_PREINIT_ARRAYSZ: + value = ( *convertor )( pEntry->d_un.d_val ); + break; + case DT_PLTGOT: + case DT_HASH: + case DT_STRTAB: + case DT_SYMTAB: + case DT_RELA: + case DT_INIT: + case DT_FINI: + case DT_REL: + case DT_DEBUG: + case DT_JMPREL: + case DT_INIT_ARRAY: + case DT_FINI_ARRAY: + case DT_PREINIT_ARRAY: + default: + value = ( *convertor )( pEntry->d_un.d_ptr ); + break; + } + } + + //------------------------------------------------------------------------------ + // Adds a generic entry to the dynamic section + template + void generic_add_entry_dyn( Elf_Xword tag, Elf_Xword value ) + { + const auto& convertor = elf_file.get_convertor(); + + T entry; + + switch ( tag ) { + case DT_NULL: + case DT_SYMBOLIC: + case DT_TEXTREL: + case DT_BIND_NOW: + entry.d_un.d_val = + ( *convertor )( decltype( entry.d_un.d_val )( 0 ) ); + break; + case DT_NEEDED: + case DT_PLTRELSZ: + case DT_RELASZ: + case DT_RELAENT: + case DT_STRSZ: + case DT_SYMENT: + case DT_SONAME: + case DT_RPATH: + case DT_RELSZ: + case DT_RELENT: + case DT_PLTREL: + case DT_INIT_ARRAYSZ: + case DT_FINI_ARRAYSZ: + case DT_RUNPATH: + case DT_FLAGS: + case DT_PREINIT_ARRAYSZ: + entry.d_un.d_val = + ( *convertor )( decltype( entry.d_un.d_val )( value ) ); + break; + case DT_PLTGOT: + case DT_HASH: + case DT_STRTAB: + case DT_SYMTAB: + case DT_RELA: + case DT_INIT: + case DT_FINI: + case DT_REL: + case DT_DEBUG: + case DT_JMPREL: + case DT_INIT_ARRAY: + case DT_FINI_ARRAY: + case DT_PREINIT_ARRAY: + default: + entry.d_un.d_ptr = + ( *convertor )( decltype( entry.d_un.d_val )( value ) ); + break; + } + + entry.d_tag = ( *convertor )( decltype( entry.d_tag )( tag ) ); + + dynamic_section->append_data( reinterpret_cast( &entry ), + sizeof( entry ) ); + } + + private: + // Reference to the ELF file + const elfio& elf_file; + // Pointer to the dynamic section + S* dynamic_section; + // Number of entries in the dynamic section + mutable Elf_Xword entries_num; +}; + +// Type aliases for dynamic section accessors +using dynamic_section_accessor = dynamic_section_accessor_template
; +using const_dynamic_section_accessor = + dynamic_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_DYNAMIC_HPP diff --git a/emulator/include/elfio/elfio_header.hpp b/emulator/include/elfio/elfio_header.hpp new file mode 100644 index 0000000..80c4b3f --- /dev/null +++ b/emulator/include/elfio/elfio_header.hpp @@ -0,0 +1,192 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELF_HEADER_HPP +#define ELF_HEADER_HPP + +#include + +namespace ELFIO { + +/** + * @class elf_header + * @brief Abstract base class for ELF header. + */ +class elf_header +{ + public: + /** + * @brief Virtual destructor. + */ + virtual ~elf_header() = default; + + /** + * @brief Load ELF header from stream. + * @param stream Input stream. + * @return True if successful, false otherwise. + */ + virtual bool load( std::istream& stream ) = 0; + + /** + * @brief Save ELF header to stream. + * @param stream Output stream. + * @return True if successful, false otherwise. + */ + virtual bool save( std::ostream& stream ) const = 0; + + // ELF header functions + ELFIO_GET_ACCESS_DECL( unsigned char, class ); + ELFIO_GET_ACCESS_DECL( unsigned char, elf_version ); + ELFIO_GET_ACCESS_DECL( unsigned char, encoding ); + ELFIO_GET_ACCESS_DECL( Elf_Half, header_size ); + ELFIO_GET_ACCESS_DECL( Elf_Half, section_entry_size ); + ELFIO_GET_ACCESS_DECL( Elf_Half, segment_entry_size ); + + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, version ); + ELFIO_GET_SET_ACCESS_DECL( unsigned char, os_abi ); + ELFIO_GET_SET_ACCESS_DECL( unsigned char, abi_version ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, type ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, machine ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, entry ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, sections_num ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, sections_offset ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, segments_num ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, segments_offset ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, section_name_str_index ); +}; + +/** + * @struct elf_header_impl_types + * @brief Template specialization for ELF header implementation types. + */ +template struct elf_header_impl_types; +template <> struct elf_header_impl_types +{ + using Phdr_type = Elf32_Phdr; + using Shdr_type = Elf32_Shdr; + static const unsigned char file_class = ELFCLASS32; +}; +template <> struct elf_header_impl_types +{ + using Phdr_type = Elf64_Phdr; + using Shdr_type = Elf64_Shdr; + static const unsigned char file_class = ELFCLASS64; +}; + +/** + * @class elf_header_impl + * @brief Template class for ELF header implementation. + */ +template class elf_header_impl : public elf_header +{ + public: + /** + * @brief Constructor. + * @param convertor Endianness convertor. + * @param encoding Encoding type. + * @param translator Address translator. + */ + elf_header_impl( std::shared_ptr convertor, + unsigned char encoding, + std::shared_ptr translator ) + : convertor( convertor ), translator( translator ) + { + header.e_ident[EI_MAG0] = ELFMAG0; + header.e_ident[EI_MAG1] = ELFMAG1; + header.e_ident[EI_MAG2] = ELFMAG2; + header.e_ident[EI_MAG3] = ELFMAG3; + header.e_ident[EI_CLASS] = elf_header_impl_types::file_class; + header.e_ident[EI_DATA] = encoding; + header.e_ident[EI_VERSION] = EV_CURRENT; + header.e_version = ( *convertor )( (Elf_Word)EV_CURRENT ); + header.e_ehsize = ( sizeof( header ) ); + header.e_ehsize = ( *convertor )( header.e_ehsize ); + header.e_shstrndx = ( *convertor )( (Elf_Half)1 ); + header.e_phentsize = + sizeof( typename elf_header_impl_types::Phdr_type ); + header.e_shentsize = + sizeof( typename elf_header_impl_types::Shdr_type ); + header.e_phentsize = ( *convertor )( header.e_phentsize ); + header.e_shentsize = ( *convertor )( header.e_shentsize ); + } + + /** + * @brief Load ELF header from stream. + * @param stream Input stream. + * @return True if successful, false otherwise. + */ + bool load( std::istream& stream ) override + { + stream.seekg( ( *translator )[0] ); + stream.read( reinterpret_cast( &header ), sizeof( header ) ); + + return ( stream.gcount() == sizeof( header ) ); + } + + /** + * @brief Save ELF header to stream. + * @param stream Output stream. + * @return True if successful, false otherwise. + */ + bool save( std::ostream& stream ) const override + { + stream.seekp( ( *translator )[0] ); + stream.write( reinterpret_cast( &header ), + sizeof( header ) ); + + return stream.good(); + } + + //------------------------------------------------------------------------------ + // ELF header functions + ELFIO_GET_ACCESS( unsigned char, class, header.e_ident[EI_CLASS] ); + ELFIO_GET_ACCESS( unsigned char, elf_version, header.e_ident[EI_VERSION] ); + ELFIO_GET_ACCESS( unsigned char, encoding, header.e_ident[EI_DATA] ); + ELFIO_GET_ACCESS( Elf_Half, header_size, header.e_ehsize ); + ELFIO_GET_ACCESS( Elf_Half, section_entry_size, header.e_shentsize ); + ELFIO_GET_ACCESS( Elf_Half, segment_entry_size, header.e_phentsize ); + + ELFIO_GET_SET_ACCESS( Elf_Word, version, header.e_version ); + ELFIO_GET_SET_ACCESS( unsigned char, os_abi, header.e_ident[EI_OSABI] ); + ELFIO_GET_SET_ACCESS( unsigned char, + abi_version, + header.e_ident[EI_ABIVERSION] ); + ELFIO_GET_SET_ACCESS( Elf_Half, type, header.e_type ); + ELFIO_GET_SET_ACCESS( Elf_Half, machine, header.e_machine ); + ELFIO_GET_SET_ACCESS( Elf_Word, flags, header.e_flags ); + ELFIO_GET_SET_ACCESS( Elf_Half, section_name_str_index, header.e_shstrndx ); + ELFIO_GET_SET_ACCESS( Elf64_Addr, entry, header.e_entry ); + ELFIO_GET_SET_ACCESS( Elf_Half, sections_num, header.e_shnum ); + ELFIO_GET_SET_ACCESS( Elf64_Off, sections_offset, header.e_shoff ); + ELFIO_GET_SET_ACCESS( Elf_Half, segments_num, header.e_phnum ); + ELFIO_GET_SET_ACCESS( Elf64_Off, segments_offset, header.e_phoff ); + + private: + T header = {}; + std::shared_ptr convertor = nullptr; + std::shared_ptr translator = nullptr; +}; + +} // namespace ELFIO + +#endif // ELF_HEADER_HPP diff --git a/emulator/include/elfio/elfio_modinfo.hpp b/emulator/include/elfio/elfio_modinfo.hpp new file mode 100644 index 0000000..ee7fe2d --- /dev/null +++ b/emulator/include/elfio/elfio_modinfo.hpp @@ -0,0 +1,168 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_MODINFO_HPP +#define ELFIO_MODINFO_HPP + +#include +#include + +namespace ELFIO { + +//------------------------------------------------------------------------------ +/** + * @class modinfo_section_accessor_template + * @brief A template class to access modinfo section. + * + * @tparam S The section type. + */ +template class modinfo_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + /** + * @brief Construct a new modinfo section accessor template object. + * + * @param section The section to be accessed. + */ + explicit modinfo_section_accessor_template( S* section ) + : modinfo_section( section ) + { + process_section(); + } + + //------------------------------------------------------------------------------ + /** + * @brief Get the number of attributes. + * + * @return Elf_Word The number of attributes. + */ + Elf_Word get_attribute_num() const { return (Elf_Word)content.size(); } + + //------------------------------------------------------------------------------ + /** + * @brief Get the attribute by index. + * + * @param no The index of the attribute. + * @param field The field name of the attribute. + * @param value The value of the attribute. + * @return true If the attribute is found. + * @return false If the attribute is not found. + */ + bool + get_attribute( Elf_Word no, std::string& field, std::string& value ) const + { + if ( no < content.size() ) { + field = content[no].first; + value = content[no].second; + return true; + } + + return false; + } + + //------------------------------------------------------------------------------ + /** + * @brief Get the attribute by field name. + * + * @param field_name The field name of the attribute. + * @param value The value of the attribute. + * @return true If the attribute is found. + * @return false If the attribute is not found. + */ + bool get_attribute( const std::string_view& field_name, + std::string& value ) const + { + for ( const auto& [first, second] : content ) { + if ( field_name == first ) { + value = second; + return true; + } + } + + return false; + } + + //------------------------------------------------------------------------------ + /** + * @brief Add a new attribute. + * + * @param field The field name of the attribute. + * @param value The value of the attribute. + * @return Elf_Word The position of the new attribute. + */ + Elf_Word add_attribute( const std::string& field, const std::string& value ) + { + Elf_Word current_position = 0; + + if ( modinfo_section ) { + // Strings are addeded to the end of the current section data + current_position = (Elf_Word)modinfo_section->get_size(); + + std::string attribute = field + "=" + value; + + modinfo_section->append_data( attribute + '\0' ); + content.emplace_back( field, value ); + } + + return current_position; + } + + //------------------------------------------------------------------------------ + private: + /** + * @brief Process the section to extract attributes. + */ + void process_section() + { + const char* pdata = modinfo_section->get_data(); + if ( pdata ) { + ELFIO::Elf_Xword i = 0; + while ( i < modinfo_section->get_size() ) { + while ( i < modinfo_section->get_size() && !pdata[i] ) + i++; + if ( i < modinfo_section->get_size() ) { + std::string info = pdata + i; + size_t loc = info.find( '=' ); + content.emplace_back( info.substr( 0, loc ), + info.substr( loc + 1 ) ); + + i += info.length(); + } + } + } + } + + //------------------------------------------------------------------------------ + private: + S* modinfo_section; ///< The section to be accessed. + std::vector> + content; ///< The list of attributes. +}; + +using modinfo_section_accessor = modinfo_section_accessor_template
; +using const_modinfo_section_accessor = + modinfo_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_MODINFO_HPP diff --git a/emulator/include/elfio/elfio_note.hpp b/emulator/include/elfio/elfio_note.hpp new file mode 100644 index 0000000..c246fb5 --- /dev/null +++ b/emulator/include/elfio/elfio_note.hpp @@ -0,0 +1,208 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_NOTE_HPP +#define ELFIO_NOTE_HPP + +namespace ELFIO { + +//------------------------------------------------------------------------------ +// There are discrepancies in documentations. SCO documentation +// (http://www.sco.com/developers/gabi/latest/ch5.pheader.html#note_section) +// requires 8 byte entries alignment for 64-bit ELF file, +// but Oracle's definition uses the same structure +// for 32-bit and 64-bit formats. +// (https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-18048.html) +// +// It looks like EM_X86_64 Linux implementation is similar to Oracle's +// definition. Therefore, the same alignment works for both formats +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +//! \class note_section_accessor_template +//! \brief Class for accessing note section data +template +class note_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + //! \brief Constructor + //! \param elf_file Reference to the ELF file + //! \param section Pointer to the section + explicit note_section_accessor_template( const elfio& elf_file, S* section ) + : elf_file( elf_file ), notes( section ) + { + process_section(); + } + + //------------------------------------------------------------------------------ + //! \brief Get the number of notes + //! \return Number of notes + Elf_Word get_notes_num() const + { + return (Elf_Word)note_start_positions.size(); + } + + //------------------------------------------------------------------------------ + //! \brief Get a note + //! \param index Index of the note + //! \param type Type of the note + //! \param name Name of the note + //! \param desc Pointer to the descriptor + //! \param descSize Size of the descriptor + //! \return True if successful, false otherwise + bool get_note( Elf_Word index, + Elf_Word& type, + std::string& name, + char*& desc, + Elf_Word& descSize ) const + { + if ( index >= ( notes->*F_get_size )() ) { + return false; + } + + const char* pData = notes->get_data() + note_start_positions[index]; + int align = sizeof( Elf_Word ); + + const auto& convertor = elf_file.get_convertor(); + type = + ( *convertor )( *(const Elf_Word*)( pData + 2 * (size_t)align ) ); + Elf_Word namesz = ( *convertor )( *(const Elf_Word*)( pData ) ); + descSize = + ( *convertor )( *(const Elf_Word*)( pData + sizeof( namesz ) ) ); + + Elf_Xword max_name_size = + ( notes->*F_get_size )() - note_start_positions[index]; + if ( namesz < 1 || namesz > max_name_size || + (Elf_Xword)namesz + descSize > max_name_size ) { + return false; + } + name.assign( pData + 3 * (size_t)align, namesz - 1 ); + if ( 0 == descSize ) { + desc = nullptr; + } + else { + desc = const_cast( pData + 3 * (size_t)align + + ( ( namesz + align - 1 ) / align ) * + (size_t)align ); + } + + return true; + } + + //------------------------------------------------------------------------------ + //! \brief Add a note + //! \param type Type of the note + //! \param name Name of the note + //! \param desc Pointer to the descriptor + //! \param descSize Size of the descriptor + void add_note( Elf_Word type, + const std::string& name, + const char* desc, + Elf_Word descSize ) + { + const auto& convertor = elf_file.get_convertor(); + + int align = sizeof( Elf_Word ); + Elf_Word nameLen = (Elf_Word)name.size() + 1; + Elf_Word nameLenConv = ( *convertor )( nameLen ); + std::string buffer( reinterpret_cast( &nameLenConv ), align ); + Elf_Word descSizeConv = ( *convertor )( descSize ); + + buffer.append( reinterpret_cast( &descSizeConv ), align ); + type = ( *convertor )( type ); + buffer.append( reinterpret_cast( &type ), align ); + buffer.append( name ); + buffer.append( 1, '\x00' ); + const char pad[] = { '\0', '\0', '\0', '\0' }; + if ( nameLen % align != 0 ) { + buffer.append( pad, (size_t)align - nameLen % align ); + } + if ( desc != nullptr && descSize != 0 ) { + buffer.append( desc, descSize ); + if ( descSize % align != 0 ) { + buffer.append( pad, (size_t)align - descSize % align ); + } + } + + note_start_positions.emplace_back( ( notes->*F_get_size )() ); + notes->append_data( buffer ); + } + + private: + //------------------------------------------------------------------------------ + //! \brief Process the section to extract note start positions + void process_section() + { + const auto& convertor = elf_file.get_convertor(); + const char* data = notes->get_data(); + Elf_Xword size = ( notes->*F_get_size )(); + Elf_Xword current = 0; + + note_start_positions.clear(); + + // Is it empty? + if ( nullptr == data || 0 == size ) { + return; + } + + Elf_Word align = sizeof( Elf_Word ); + while ( current + (Elf_Xword)3 * align <= size ) { + Elf_Word namesz = + ( *convertor )( *(const Elf_Word*)( data + current ) ); + Elf_Word descsz = ( *convertor )( + *(const Elf_Word*)( data + current + sizeof( namesz ) ) ); + Elf_Word advance = + (Elf_Xword)3 * sizeof( Elf_Word ) + + ( ( namesz + align - 1 ) / align ) * (Elf_Xword)align + + ( ( descsz + align - 1 ) / align ) * (Elf_Xword)align; + if ( namesz < size && descsz < size && current + advance <= size ) { + note_start_positions.emplace_back( current ); + } + else { + break; + } + + current += advance; + } + } + + //------------------------------------------------------------------------------ + private: + const elfio& elf_file; //!< Reference to the ELF file + S* notes; //!< Pointer to the section or segment + std::vector + note_start_positions; //!< Vector of note start positions +}; + +using note_section_accessor = + note_section_accessor_template; +using const_note_section_accessor = + note_section_accessor_template; +using note_segment_accessor = + note_section_accessor_template; +using const_note_segment_accessor = + note_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_NOTE_HPP diff --git a/emulator/include/elfio/elfio_relocation.hpp b/emulator/include/elfio/elfio_relocation.hpp new file mode 100644 index 0000000..e6aa963 --- /dev/null +++ b/emulator/include/elfio/elfio_relocation.hpp @@ -0,0 +1,596 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_RELOCATION_HPP +#define ELFIO_RELOCATION_HPP + +namespace ELFIO { + +template struct get_sym_and_type; +template <> struct get_sym_and_type +{ + //------------------------------------------------------------------------------ + //! \brief Get the symbol from the relocation info + //! \param info Relocation info + //! \return Symbol + static int get_r_sym( Elf_Xword info ) + { + return ELF32_R_SYM( (Elf_Word)info ); + } + //------------------------------------------------------------------------------ + //! \brief Get the type from the relocation info + //! \param info Relocation info + //! \return Type + static int get_r_type( Elf_Xword info ) + { + return ELF32_R_TYPE( (Elf_Word)info ); + } +}; +template <> struct get_sym_and_type +{ + //------------------------------------------------------------------------------ + //! \brief Get the symbol from the relocation info + //! \param info Relocation info + //! \return Symbol + static int get_r_sym( Elf_Xword info ) + { + return ELF32_R_SYM( (Elf_Word)info ); + } + //------------------------------------------------------------------------------ + //! \brief Get the type from the relocation info + //! \param info Relocation info + //! \return Type + static int get_r_type( Elf_Xword info ) + { + return ELF32_R_TYPE( (Elf_Word)info ); + } +}; +template <> struct get_sym_and_type +{ + //------------------------------------------------------------------------------ + //! \brief Get the symbol from the relocation info + //! \param info Relocation info + //! \return Symbol + static int get_r_sym( Elf_Xword info ) { return ELF64_R_SYM( info ); } + //------------------------------------------------------------------------------ + //! \brief Get the type from the relocation info + //! \param info Relocation info + //! \return Type + static int get_r_type( Elf_Xword info ) { return ELF64_R_TYPE( info ); } +}; +template <> struct get_sym_and_type +{ + //------------------------------------------------------------------------------ + //! \brief Get the symbol from the relocation info + //! \param info Relocation info + //! \return Symbol + static int get_r_sym( Elf_Xword info ) { return ELF64_R_SYM( info ); } + //------------------------------------------------------------------------------ + //! \brief Get the type from the relocation info + //! \param info Relocation info + //! \return Type + static int get_r_type( Elf_Xword info ) { return ELF64_R_TYPE( info ); } +}; + +//------------------------------------------------------------------------------ +//! \class relocation_section_accessor_template +//! \brief Class for accessing relocation section data +template class relocation_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + //! \brief Constructor + //! \param elf_file Reference to the ELF file + //! \param section Pointer to the section + explicit relocation_section_accessor_template( const elfio& elf_file, + S* section ) + : elf_file( elf_file ), relocation_section( section ) + { + } + + //------------------------------------------------------------------------------ + //! \brief Get the number of entries + //! \return Number of entries + Elf_Xword get_entries_num() const + { + Elf_Xword nRet = 0; + + if ( 0 != relocation_section->get_entry_size() ) { + nRet = relocation_section->get_size() / + relocation_section->get_entry_size(); + } + + return nRet; + } + + //------------------------------------------------------------------------------ + //! \brief Get an entry + //! \param index Index of the entry + //! \param offset Offset of the entry + //! \param symbol Symbol of the entry + //! \param type Type of the entry + //! \param addend Addend of the entry + //! \return True if successful, false otherwise + bool get_entry( Elf_Xword index, + Elf64_Addr& offset, + Elf_Word& symbol, + unsigned& type, + Elf_Sxword& addend ) const + { + if ( index >= get_entries_num() ) { // Is index valid + return false; + } + + if ( elf_file.get_class() == ELFCLASS32 ) { + if ( SHT_REL == relocation_section->get_type() ) { + return generic_get_entry_rel( index, offset, symbol, + type, addend ); + } + else if ( SHT_RELA == relocation_section->get_type() ) { + return generic_get_entry_rela( + index, offset, symbol, type, addend ); + } + } + else { + if ( SHT_REL == relocation_section->get_type() ) { + return generic_get_entry_rel( index, offset, symbol, + type, addend ); + } + else if ( SHT_RELA == relocation_section->get_type() ) { + return generic_get_entry_rela( + index, offset, symbol, type, addend ); + } + } + // Unknown relocation section type. + return false; + } + + //------------------------------------------------------------------------------ + //! \brief Get an entry with additional information + //! \param index Index of the entry + //! \param offset Offset of the entry + //! \param symbolValue Value of the symbol + //! \param symbolName Name of the symbol + //! \param type Type of the entry + //! \param addend Addend of the entry + //! \param calcValue Calculated value + //! \return True if successful, false otherwise + bool get_entry( Elf_Xword index, + Elf64_Addr& offset, + Elf64_Addr& symbolValue, + std::string& symbolName, + unsigned& type, + Elf_Sxword& addend, + Elf_Sxword& calcValue ) const + { + // Do regular job + Elf_Word symbol = 0; + bool ret = get_entry( index, offset, symbol, type, addend ); + + // Find the symbol + Elf_Xword size; + unsigned char bind; + unsigned char symbolType; + Elf_Half section; + unsigned char other; + + symbol_section_accessor symbols( + elf_file, elf_file.sections[get_symbol_table_index()] ); + ret = ret && symbols.get_symbol( symbol, symbolName, symbolValue, size, + bind, symbolType, section, other ); + + if ( ret ) { // Was it successful? + switch ( type ) { + case R_386_NONE: // none + calcValue = 0; + break; + case R_386_32: // S + A + calcValue = symbolValue + addend; + break; + case R_386_PC32: // S + A - P + calcValue = symbolValue + addend - offset; + break; + case R_386_GOT32: // G + A - P + calcValue = 0; + break; + case R_386_PLT32: // L + A - P + calcValue = 0; + break; + case R_386_COPY: // none + calcValue = 0; + break; + case R_386_GLOB_DAT: // S + case R_386_JMP_SLOT: // S + calcValue = symbolValue; + break; + case R_386_RELATIVE: // B + A + calcValue = addend; + break; + case R_386_GOTOFF: // S + A - GOT + calcValue = 0; + break; + case R_386_GOTPC: // GOT + A - P + calcValue = 0; + break; + default: // Not recognized symbol! + calcValue = 0; + break; + } + } + + return ret; + } + + //------------------------------------------------------------------------------ + //! \brief Set an entry + //! \param index Index of the entry + //! \param offset Offset of the entry + //! \param symbol Symbol of the entry + //! \param type Type of the entry + //! \param addend Addend of the entry + //! \return True if successful, false otherwise + bool set_entry( Elf_Xword index, + Elf64_Addr offset, + Elf_Word symbol, + unsigned type, + Elf_Sxword addend ) + { + if ( index >= get_entries_num() ) { // Is index valid + return false; + } + + if ( elf_file.get_class() == ELFCLASS32 ) { + if ( SHT_REL == relocation_section->get_type() ) { + generic_set_entry_rel( index, offset, symbol, type, + addend ); + } + else if ( SHT_RELA == relocation_section->get_type() ) { + generic_set_entry_rela( index, offset, symbol, type, + addend ); + } + } + else { + if ( SHT_REL == relocation_section->get_type() ) { + generic_set_entry_rel( index, offset, symbol, type, + addend ); + } + else if ( SHT_RELA == relocation_section->get_type() ) { + generic_set_entry_rela( index, offset, symbol, type, + addend ); + } + } + + return true; + } + + //------------------------------------------------------------------------------ + //! \brief Add an entry + //! \param offset Offset of the entry + //! \param info Information of the entry + void add_entry( Elf64_Addr offset, Elf_Xword info ) + { + if ( elf_file.get_class() == ELFCLASS32 ) { + generic_add_entry( offset, info ); + } + else { + generic_add_entry( offset, info ); + } + } + + //------------------------------------------------------------------------------ + //! \brief Add an entry + //! \param offset Offset of the entry + //! \param symbol Symbol of the entry + //! \param type Type of the entry + void add_entry( Elf64_Addr offset, Elf_Word symbol, unsigned type ) + { + Elf_Xword info; + if ( elf_file.get_class() == ELFCLASS32 ) { + info = ELF32_R_INFO( (Elf_Xword)symbol, type ); + } + else { + info = ELF64_R_INFO( (Elf_Xword)symbol, type ); + } + + add_entry( offset, info ); + } + + //------------------------------------------------------------------------------ + //! \brief Add an entry + //! \param offset Offset of the entry + //! \param info Information of the entry + //! \param addend Addend of the entry + void add_entry( Elf64_Addr offset, Elf_Xword info, Elf_Sxword addend ) + { + if ( elf_file.get_class() == ELFCLASS32 ) { + generic_add_entry( offset, info, addend ); + } + else { + generic_add_entry( offset, info, addend ); + } + } + + //------------------------------------------------------------------------------ + //! \brief Add an entry + //! \param offset Offset of the entry + //! \param symbol Symbol of the entry + //! \param type Type of the entry + //! \param addend Addend of the entry + void add_entry( Elf64_Addr offset, + Elf_Word symbol, + unsigned type, + Elf_Sxword addend ) + { + Elf_Xword info; + if ( elf_file.get_class() == ELFCLASS32 ) { + info = ELF32_R_INFO( (Elf_Xword)symbol, type ); + } + else { + info = ELF64_R_INFO( (Elf_Xword)symbol, type ); + } + + add_entry( offset, info, addend ); + } + + //------------------------------------------------------------------------------ + //! \brief Add an entry with additional information + //! \param str_writer String section accessor + //! \param str String + //! \param sym_writer Symbol section accessor + //! \param value Value of the symbol + //! \param size Size of the symbol + //! \param sym_info Symbol information + //! \param other Other information + //! \param shndx Section index + //! \param offset Offset of the entry + //! \param type Type of the entry + void add_entry( string_section_accessor str_writer, + const char* str, + symbol_section_accessor sym_writer, + Elf64_Addr value, + Elf_Word size, + unsigned char sym_info, + unsigned char other, + Elf_Half shndx, + Elf64_Addr offset, + unsigned type ) + { + Elf_Word str_index = str_writer.add_string( str ); + Elf_Word sym_index = sym_writer.add_symbol( str_index, value, size, + sym_info, other, shndx ); + add_entry( offset, sym_index, type ); + } + + //------------------------------------------------------------------------------ + //! \brief Swap symbols + //! \param first First symbol + //! \param second Second symbol + void swap_symbols( Elf_Xword first, Elf_Xword second ) + { + Elf64_Addr offset = 0; + Elf_Word symbol = 0; + unsigned rtype = 0; + Elf_Sxword addend = 0; + for ( Elf_Word i = 0; i < get_entries_num(); i++ ) { + get_entry( i, offset, symbol, rtype, addend ); + if ( symbol == first ) { + set_entry( i, offset, (Elf_Word)second, rtype, addend ); + } + if ( symbol == second ) { + set_entry( i, offset, (Elf_Word)first, rtype, addend ); + } + } + } + + //------------------------------------------------------------------------------ + private: + //------------------------------------------------------------------------------ + //! \brief Get the symbol table index + //! \return Symbol table index + Elf_Half get_symbol_table_index() const + { + return (Elf_Half)relocation_section->get_link(); + } + + //------------------------------------------------------------------------------ + //! \brief Get a generic entry for REL type + //! \param index Index of the entry + //! \param offset Offset of the entry + //! \param symbol Symbol of the entry + //! \param type Type of the entry + //! \param addend Addend of the entry + //! \return True if successful, false otherwise + template + bool generic_get_entry_rel( Elf_Xword index, + Elf64_Addr& offset, + Elf_Word& symbol, + unsigned& type, + Elf_Sxword& addend ) const + { + const auto& convertor = elf_file.get_convertor(); + + if ( relocation_section->get_entry_size() < sizeof( T ) ) { + return false; + } + const T* pEntry = reinterpret_cast( + relocation_section->get_data() + + index * relocation_section->get_entry_size() ); + offset = ( *convertor )( pEntry->r_offset ); + Elf_Xword tmp = ( *convertor )( pEntry->r_info ); + symbol = get_sym_and_type::get_r_sym( tmp ); + type = get_sym_and_type::get_r_type( tmp ); + addend = 0; + return true; + } + + //------------------------------------------------------------------------------ + //! \brief Get a generic entry for RELA type + //! \param index Index of the entry + //! \param offset Offset of the entry + //! \param symbol Symbol of the entry + //! \param type Type of the entry + //! \param addend Addend of the entry + //! \return True if successful, false otherwise + template + bool generic_get_entry_rela( Elf_Xword index, + Elf64_Addr& offset, + Elf_Word& symbol, + unsigned& type, + Elf_Sxword& addend ) const + { + const auto& convertor = elf_file.get_convertor(); + + if ( relocation_section->get_entry_size() < sizeof( T ) ) { + return false; + } + + const T* pEntry = reinterpret_cast( + relocation_section->get_data() + + index * relocation_section->get_entry_size() ); + offset = ( *convertor )( pEntry->r_offset ); + Elf_Xword tmp = ( *convertor )( pEntry->r_info ); + symbol = get_sym_and_type::get_r_sym( tmp ); + type = get_sym_and_type::get_r_type( tmp ); + addend = ( *convertor )( pEntry->r_addend ); + return true; + } + + //------------------------------------------------------------------------------ + //! \brief Set a generic entry for REL type + //! \param index Index of the entry + //! \param offset Offset of the entry + //! \param symbol Symbol of the entry + //! \param type Type of the entry + //! \param addend Addend of the entry + template + void generic_set_entry_rel( Elf_Xword index, + Elf64_Addr offset, + Elf_Word symbol, + unsigned type, + Elf_Sxword ) + { + const auto& convertor = elf_file.get_convertor(); + + T* pEntry = const_cast( reinterpret_cast( + relocation_section->get_data() + + index * relocation_section->get_entry_size() ) ); + + if ( elf_file.get_class() == ELFCLASS32 ) { + pEntry->r_info = ELF32_R_INFO( (Elf_Xword)symbol, type ); + } + else { + pEntry->r_info = ELF64_R_INFO( (Elf_Xword)symbol, type ); + } + pEntry->r_offset = decltype( pEntry->r_offset )( offset ); + pEntry->r_offset = ( *convertor )( pEntry->r_offset ); + pEntry->r_info = ( *convertor )( pEntry->r_info ); + } + + //------------------------------------------------------------------------------ + //! \brief Set a generic entry for RELA type + //! \param index Index of the entry + //! \param offset Offset of the entry + //! \param symbol Symbol of the entry + //! \param type Type of the entry + //! \param addend Addend of the entry + template + void generic_set_entry_rela( Elf_Xword index, + Elf64_Addr offset, + Elf_Word symbol, + unsigned type, + Elf_Sxword addend ) + { + const auto& convertor = elf_file.get_convertor(); + + T* pEntry = const_cast( reinterpret_cast( + relocation_section->get_data() + + index * relocation_section->get_entry_size() ) ); + + if ( elf_file.get_class() == ELFCLASS32 ) { + pEntry->r_info = ELF32_R_INFO( (Elf_Xword)symbol, type ); + } + else { + pEntry->r_info = ELF64_R_INFO( (Elf_Xword)symbol, type ); + } + pEntry->r_offset = decltype( pEntry->r_offset )( offset ); + pEntry->r_addend = decltype( pEntry->r_addend )( addend ); + pEntry->r_offset = ( *convertor )( pEntry->r_offset ); + pEntry->r_info = ( *convertor )( pEntry->r_info ); + pEntry->r_addend = ( *convertor )( pEntry->r_addend ); + } + + //------------------------------------------------------------------------------ + //! \brief Add a generic entry for REL type + //! \param offset Offset of the entry + //! \param info Information of the entry + template + void generic_add_entry( Elf64_Addr offset, Elf_Xword info ) + { + const auto& convertor = elf_file.get_convertor(); + + T entry; + entry.r_offset = decltype( entry.r_offset )( offset ); + entry.r_info = decltype( entry.r_info )( info ); + entry.r_offset = ( *convertor )( entry.r_offset ); + entry.r_info = ( *convertor )( entry.r_info ); + + relocation_section->append_data( reinterpret_cast( &entry ), + sizeof( entry ) ); + } + + //------------------------------------------------------------------------------ + //! \brief Add a generic entry for RELA type + //! \param offset Offset of the entry + //! \param info Information of the entry + //! \param addend Addend of the entry + template + void + generic_add_entry( Elf64_Addr offset, Elf_Xword info, Elf_Sxword addend ) + { + const auto& convertor = elf_file.get_convertor(); + + T entry; + entry.r_offset = offset; + entry.r_info = info; + entry.r_addend = addend; + entry.r_offset = ( *convertor )( entry.r_offset ); + entry.r_info = ( *convertor )( entry.r_info ); + entry.r_addend = ( *convertor )( entry.r_addend ); + + relocation_section->append_data( reinterpret_cast( &entry ), + sizeof( entry ) ); + } + + //------------------------------------------------------------------------------ + private: + const elfio& elf_file; + S* relocation_section = nullptr; +}; + +using relocation_section_accessor = + relocation_section_accessor_template
; +using const_relocation_section_accessor = + relocation_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_RELOCATION_HPP diff --git a/emulator/include/elfio/elfio_section.hpp b/emulator/include/elfio/elfio_section.hpp new file mode 100644 index 0000000..c5e5bd9 --- /dev/null +++ b/emulator/include/elfio/elfio_section.hpp @@ -0,0 +1,611 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_SECTION_HPP +#define ELFIO_SECTION_HPP + +#include +#include +#include +#include + +namespace ELFIO { + +/** + * @class section + * @brief Represents a section in an ELF file. + */ +class section +{ + friend class elfio; + + public: + virtual ~section() = default; + + ELFIO_GET_ACCESS_DECL( Elf_Half, index ); + ELFIO_GET_SET_ACCESS_DECL( std::string, name ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, flags ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, info ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, link ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, addr_align ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, entry_size ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, address ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, size ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, name_string_offset ); + ELFIO_GET_ACCESS_DECL( Elf64_Off, offset ); + + /** + * @brief Get the data of the section. + * @return Pointer to the data. + */ + virtual const char* get_data() const = 0; + + /** + * @brief Free the data of the section. + */ + virtual void free_data() const = 0; + + /** + * @brief Set the data of the section. + * @param raw_data Pointer to the raw data. + * @param size Size of the data. + */ + virtual void set_data( const char* raw_data, Elf_Xword size ) = 0; + + /** + * @brief Set the data of the section. + * @param data String containing the data. + */ + virtual void set_data( const std::string& data ) = 0; + + /** + * @brief Append data to the section. + * @param raw_data Pointer to the raw data. + * @param size Size of the data. + */ + virtual void append_data( const char* raw_data, Elf_Xword size ) = 0; + + /** + * @brief Append data to the section. + * @param data String containing the data. + */ + virtual void append_data( const std::string& data ) = 0; + + /** + * @brief Insert data into the section at a specific position. + * @param pos Position to insert the data. + * @param raw_data Pointer to the raw data. + * @param size Size of the data. + */ + virtual void + insert_data( Elf_Xword pos, const char* raw_data, Elf_Xword size ) = 0; + + /** + * @brief Insert data into the section at a specific position. + * @param pos Position to insert the data. + * @param data String containing the data. + */ + virtual void insert_data( Elf_Xword pos, const std::string& data ) = 0; + + /** + * @brief Get the size of the stream. + * @return Size of the stream. + */ + virtual size_t get_stream_size() const = 0; + + /** + * @brief Set the size of the stream. + * @param value Size of the stream. + */ + virtual void set_stream_size( size_t value ) = 0; + + protected: + ELFIO_SET_ACCESS_DECL( Elf64_Off, offset ); + ELFIO_SET_ACCESS_DECL( Elf_Half, index ); + + /** + * @brief Load the section from a stream. + * @param stream Input stream. + * @param header_offset Offset of the header. + * @param is_lazy Whether to load lazily. + * @return True if successful, false otherwise. + */ + virtual bool load( std::istream& stream, + std::streampos header_offset, + bool is_lazy ) = 0; + + /** + * @brief Save the section to a stream. + * @param stream Output stream. + * @param header_offset Offset of the header. + * @param data_offset Offset of the data. + */ + virtual void save( std::ostream& stream, + std::streampos header_offset, + std::streampos data_offset ) = 0; + + /** + * @brief Check if the address is initialized. + * @return True if initialized, false otherwise. + */ + virtual bool is_address_initialized() const = 0; +}; + +/** + * @class section_impl + * @brief Implementation of the section class. + * @tparam T Type of the section header. + */ +template class section_impl : public section +{ + public: + /** + * @brief Constructor. + * @param convertor Pointer to the endianness convertor. + * @param translator Pointer to the address translator. + * @param compression Shared pointer to the compression interface. + */ + section_impl( std::shared_ptr convertor, + std::shared_ptr translator, + std::shared_ptr compression ) + : convertor( convertor ), translator( translator ), + compression( compression ) + { + } + + // Section info functions + ELFIO_GET_SET_ACCESS( Elf_Word, type, header.sh_type ); + ELFIO_GET_SET_ACCESS( Elf_Xword, flags, header.sh_flags ); + ELFIO_GET_SET_ACCESS( Elf_Xword, size, header.sh_size ); + ELFIO_GET_SET_ACCESS( Elf_Word, link, header.sh_link ); + ELFIO_GET_SET_ACCESS( Elf_Word, info, header.sh_info ); + ELFIO_GET_SET_ACCESS( Elf_Xword, addr_align, header.sh_addralign ); + ELFIO_GET_SET_ACCESS( Elf_Xword, entry_size, header.sh_entsize ); + ELFIO_GET_SET_ACCESS( Elf_Word, name_string_offset, header.sh_name ); + ELFIO_GET_ACCESS( Elf64_Addr, address, header.sh_addr ); + + /** + * @brief Get the index of the section. + * @return Index of the section. + */ + Elf_Half get_index() const override { return index; } + + /** + * @brief Get the name of the section. + * @return Name of the section. + */ + std::string get_name() const override { return name; } + + /** + * @brief Set the name of the section. + * @param name_prm Name of the section. + */ + void set_name( const std::string& name_prm ) override + { + this->name = name_prm; + } + + /** + * @brief Set the address of the section. + * @param value Address of the section. + */ + void set_address( const Elf64_Addr& value ) override + { + header.sh_addr = decltype( header.sh_addr )( value ); + header.sh_addr = ( *convertor )( header.sh_addr ); + is_address_set = true; + } + + /** + * @brief Check if the address is initialized. + * @return True if initialized, false otherwise. + */ + bool is_address_initialized() const override { return is_address_set; } + + /** + * @brief Get the data of the section. + * @return Pointer to the data. + */ + const char* get_data() const override + { + // If data load failed, the stream is corrupt + // When lazy loading, attempts to call get_data() on it after initial load are useless + // When loading non-lazily, that load_data() will attempt to read data from + // the stream specified on load() call, which might be freed by this point + if ( !is_loaded && can_be_loaded ) { + bool res = load_data(); + + if ( !res ) { + can_be_loaded = false; + } + } + return data.get(); + } + + /** + * @brief Free the data of the section. + */ + void free_data() const override + { + if ( is_lazy ) { + data.reset( nullptr ); + is_loaded = false; + } + } + + /** + * @brief Set the data of the section. + * @param raw_data Pointer to the raw data. + * @param size Size of the data. + */ + void set_data( const char* raw_data, Elf_Xword size ) override + { + if ( get_type() != SHT_NOBITS ) { + data = std::unique_ptr( + new ( std::nothrow ) char[(size_t)size] ); + if ( nullptr != data.get() && nullptr != raw_data ) { + data_size = size; + std::copy( raw_data, raw_data + size, data.get() ); + } + else { + data_size = 0; + } + } + + set_size( data_size ); + if ( translator->empty() ) { + set_stream_size( (size_t)data_size ); + } + } + + /** + * @brief Set the data of the section. + * @param str_data String containing the data. + */ + void set_data( const std::string& str_data ) override + { + return set_data( str_data.c_str(), (Elf_Word)str_data.size() ); + } + + /** + * @brief Append data to the section. + * @param raw_data Pointer to the raw data. + * @param size Size of the data. + */ + void append_data( const char* raw_data, Elf_Xword size ) override + { + insert_data( get_size(), raw_data, size ); + } + + /** + * @brief Append data to the section. + * @param str_data String containing the data. + */ + void append_data( const std::string& str_data ) override + { + return append_data( str_data.c_str(), (Elf_Word)str_data.size() ); + } + + /** + * @brief Insert data into the section at a specific position. + * @param pos Position to insert the data. + * @param raw_data Pointer to the raw data. + * @param size Size of the data. + */ + void + insert_data( Elf_Xword pos, const char* raw_data, Elf_Xword size ) override + { + if ( get_type() != SHT_NOBITS ) { + // Check for valid position + if ( pos > get_size() ) { + return; // Invalid position + } + + // Check for integer overflow in size calculation + Elf_Xword new_size = get_size(); + if ( size > std::numeric_limits::max() - new_size ) { + return; // Size would overflow + } + new_size += size; + + if ( new_size <= data_size ) { + char* d = data.get(); + std::copy_backward( d + pos, d + get_size(), + d + get_size() + size ); + std::copy( raw_data, raw_data + size, d + pos ); + } + else { + // Calculate new size with overflow check + Elf_Xword new_data_size = data_size; + if ( new_data_size > + std::numeric_limits::max() / 2 ) { + return; // Multiplication would overflow + } + new_data_size *= 2; + if ( size > + std::numeric_limits::max() - new_data_size ) { + return; // Addition would overflow + } + new_data_size += size; + + // Check if the size would overflow size_t + if ( new_data_size > std::numeric_limits::max() ) { + return; // Size would overflow size_t + } + + std::unique_ptr new_data( + new ( std::nothrow ) char[(size_t)new_data_size] ); + + if ( nullptr != new_data ) { + char* d = data.get(); + std::copy( d, d + pos, new_data.get() ); + std::copy( raw_data, raw_data + size, + new_data.get() + pos ); + std::copy( d + pos, d + get_size(), + new_data.get() + pos + size ); + data = std::move( new_data ); + data_size = new_data_size; + } + else { + return; // Allocation failed + } + } + set_size( new_size ); + if ( translator->empty() ) { + set_stream_size( get_stream_size() + (size_t)size ); + } + } + } + + /** + * @brief Insert data into the section at a specific position. + * @param pos Position to insert the data. + * @param str_data String containing the data. + */ + void insert_data( Elf_Xword pos, const std::string& str_data ) override + { + return insert_data( pos, str_data.c_str(), (Elf_Word)str_data.size() ); + } + + /** + * @brief Get the size of the stream. + * @return Size of the stream. + */ + size_t get_stream_size() const override { return stream_size; } + + /** + * @brief Set the size of the stream. + * @param value Size of the stream. + */ + void set_stream_size( size_t value ) override { stream_size = value; } + + protected: + ELFIO_GET_SET_ACCESS( Elf64_Off, offset, header.sh_offset ); + + /** + * @brief Set the index of the section. + * @param value Index of the section. + */ + void set_index( const Elf_Half& value ) override { index = value; } + + /** + * @brief Check if the section is compressed. + * @return True if compressed, false otherwise. + */ + bool is_compressed() const + { + return ( ( get_flags() & SHF_RPX_DEFLATE ) || + ( get_flags() & SHF_COMPRESSED ) ) && + compression != nullptr; + } + + /** + * @brief Load the section from a stream. + * @param stream Input stream. + * @param header_offset Offset of the header. + * @param is_lazy_ Whether to load lazily. + * @return True if successful, false otherwise. + */ + bool load( std::istream& stream, + std::streampos header_offset, + bool is_lazy_ ) override + { + pstream = &stream; + is_lazy = is_lazy_; + + if ( translator->empty() ) { + stream.seekg( 0, std::istream::end ); + set_stream_size( size_t( stream.tellg() ) ); + } + else { + set_stream_size( std::numeric_limits::max() ); + } + + stream.seekg( ( *translator )[header_offset] ); + stream.read( reinterpret_cast( &header ), sizeof( header ) ); + + if ( !( is_lazy || is_loaded ) ) { + bool ret = get_data(); + + if ( is_compressed() ) { + Elf_Xword size = get_size(); + Elf_Xword uncompressed_size = 0; + auto decompressed_data = compression->inflate( + data.get(), convertor, size, uncompressed_size ); + if ( decompressed_data != nullptr ) { + set_size( uncompressed_size ); + data = std::move( decompressed_data ); + } + } + + return ret; + } + + return true; + } + + /** + * @brief Load the data of the section. + * @return True if successful, false otherwise. + */ + bool load_data() const + { + Elf_Xword sh_offset = + ( *translator )[( *convertor )( header.sh_offset )]; + Elf_Xword size = get_size(); + + // Check for integer overflow in offset calculation + if ( sh_offset > get_stream_size() ) { + return false; + } + + // Check for integer overflow in size calculation + if ( size > get_stream_size() || + size > ( get_stream_size() - sh_offset ) ) { + return false; + } + + // Check if we need to load data + if ( nullptr == data && SHT_NULL != get_type() && + SHT_NOBITS != get_type() ) { + // Check if size can be safely converted to size_t + if ( size > std::numeric_limits::max() - 1 ) { + return false; + } + + data.reset( new ( std::nothrow ) char[size_t( size ) + 1] ); + + if ( ( 0 != size ) && ( nullptr != data ) ) { + pstream->seekg( sh_offset ); + pstream->read( data.get(), size ); + if ( static_cast( pstream->gcount() ) != size ) { + data.reset( nullptr ); + data_size = 0; + return false; + } + + data_size = size; + data.get()[size] = 0; // Safe now as we allocated size + 1 + } + else { + data_size = 0; + if ( size != 0 ) { + return false; // Failed to allocate required memory + } + } + + is_loaded = true; + return true; + } + + // Data already loaded or doesn't need loading + is_loaded = ( nullptr != data ) || ( SHT_NULL == get_type() ) || + ( SHT_NOBITS == get_type() ); + return is_loaded; + } + + /** + * @brief Save the section to a stream. + * @param stream Output stream. + * @param header_offset Offset of the header. + * @param data_offset Offset of the data. + */ + void save( std::ostream& stream, + std::streampos header_offset, + std::streampos data_offset ) override + { + if ( 0 != get_index() ) { + header.sh_offset = decltype( header.sh_offset )( data_offset ); + header.sh_offset = ( *convertor )( header.sh_offset ); + } + + save_header( stream, header_offset ); + if ( get_type() != SHT_NOBITS && get_type() != SHT_NULL && + get_size() != 0 && data != nullptr ) { + save_data( stream, data_offset ); + } + } + + private: + /** + * @brief Save the header of the section to a stream. + * @param stream Output stream. + * @param header_offset Offset of the header. + */ + void save_header( std::ostream& stream, std::streampos header_offset ) const + { + adjust_stream_size( stream, header_offset ); + stream.write( reinterpret_cast( &header ), + sizeof( header ) ); + } + + /** + * @brief Save the data of the section to a stream. + * @param stream Output stream. + * @param data_offset Offset of the data. + */ + void save_data( std::ostream& stream, std::streampos data_offset ) + { + adjust_stream_size( stream, data_offset ); + + if ( ( ( get_flags() & SHF_COMPRESSED ) || + ( get_flags() & SHF_RPX_DEFLATE ) ) && + compression != nullptr ) { + Elf_Xword decompressed_size = get_size(); + Elf_Xword compressed_size = 0; + auto compressed_ptr = compression->deflate( + data.get(), convertor, decompressed_size, compressed_size ); + stream.write( compressed_ptr.get(), compressed_size ); + } + else { + stream.write( get_data(), get_size() ); + } + } + + private: + mutable std::istream* pstream = + nullptr; /**< Pointer to the input stream. */ + T header = {}; /**< Section header. */ + Elf_Half index = 0; /**< Index of the section. */ + std::string name; /**< Name of the section. */ + mutable std::unique_ptr data; /**< Pointer to the data. */ + mutable Elf_Xword data_size = 0; /**< Size of the data. */ + std::shared_ptr convertor = + nullptr; /**< Pointer to the endianness convertor. */ + std::shared_ptr translator = + nullptr; /**< Pointer to the address translator. */ + std::shared_ptr compression = + nullptr; /**< Shared pointer to the compression interface. */ + bool is_address_set = false; /**< Flag indicating if the address is set. */ + size_t stream_size = 0; /**< Size of the stream. */ + mutable bool is_lazy = + false; /**< Flag indicating if lazy loading is enabled. */ + mutable bool is_loaded = + false; /**< Flag indicating if the data is loaded. */ + mutable bool can_be_loaded = + true; /**< Flag indicating if the data can loaded. This is not the case if the section is corrupted. */ +}; + +} // namespace ELFIO + +#endif // ELFIO_SECTION_HPP diff --git a/emulator/include/elfio/elfio_segment.hpp b/emulator/include/elfio/elfio_segment.hpp new file mode 100644 index 0000000..2c7b08c --- /dev/null +++ b/emulator/include/elfio/elfio_segment.hpp @@ -0,0 +1,405 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_SEGMENT_HPP +#define ELFIO_SEGMENT_HPP + +#include +#include +#include +#include + +namespace ELFIO { + +//------------------------------------------------------------------------------ +//! \class segment +//! \brief Class for accessing segment data +class segment +{ + friend class elfio; + + public: + virtual ~segment() = default; + + //------------------------------------------------------------------------------ + //! \brief Get the index of the segment + //! \return Index of the segment + ELFIO_GET_ACCESS_DECL( Elf_Half, index ); + //------------------------------------------------------------------------------ + //! \brief Get the type of the segment + //! \return Type of the segment + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type ); + //------------------------------------------------------------------------------ + //! \brief Get the flags of the segment + //! \return Flags of the segment + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags ); + //------------------------------------------------------------------------------ + //! \brief Get the alignment of the segment + //! \return Alignment of the segment + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, align ); + //------------------------------------------------------------------------------ + //! \brief Get the virtual address of the segment + //! \return Virtual address of the segment + ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, virtual_address ); + //------------------------------------------------------------------------------ + //! \brief Get the physical address of the segment + //! \return Physical address of the segment + ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, physical_address ); + //------------------------------------------------------------------------------ + //! \brief Get the file size of the segment + //! \return File size of the segment + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, file_size ); + //------------------------------------------------------------------------------ + //! \brief Get the memory size of the segment + //! \return Memory size of the segment + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, memory_size ); + //------------------------------------------------------------------------------ + //! \brief Get the offset of the segment + //! \return Offset of the segment + ELFIO_GET_ACCESS_DECL( Elf64_Off, offset ); + + //------------------------------------------------------------------------------ + //! \brief Get the data of the segment + //! \return Pointer to the data + virtual const char* get_data() const = 0; + //------------------------------------------------------------------------------ + //! \brief Free the data of the segment + virtual void free_data() const = 0; + + //------------------------------------------------------------------------------ + //! \brief Add a section to the segment + //! \param psec Pointer to the section + //! \param addr_align Alignment of the section + //! \return Index of the added section + virtual Elf_Half add_section( section* psec, Elf_Xword addr_align ) = 0; + //------------------------------------------------------------------------------ + //! \brief Add a section index to the segment + //! \param index Index of the section + //! \param addr_align Alignment of the section + //! \return Index of the added section + virtual Elf_Half add_section_index( Elf_Half index, + Elf_Xword addr_align ) = 0; + //------------------------------------------------------------------------------ + //! \brief Get the number of sections in the segment + //! \return Number of sections in the segment + virtual Elf_Half get_sections_num() const = 0; + //------------------------------------------------------------------------------ + //! \brief Get the index of a section at a given position + //! \param num Position of the section + //! \return Index of the section + virtual Elf_Half get_section_index_at( Elf_Half num ) const = 0; + //------------------------------------------------------------------------------ + //! \brief Check if the offset is initialized + //! \return True if the offset is initialized, false otherwise + virtual bool is_offset_initialized() const = 0; + + protected: + //------------------------------------------------------------------------------ + //! \brief Set the offset of the segment + //! \param offset Offset of the segment + ELFIO_SET_ACCESS_DECL( Elf64_Off, offset ); + //------------------------------------------------------------------------------ + //! \brief Set the index of the segment + //! \param index Index of the segment + ELFIO_SET_ACCESS_DECL( Elf_Half, index ); + + //------------------------------------------------------------------------------ + //! \brief Get the sections of the segment + //! \return Vector of section indices + virtual const std::vector& get_sections() const = 0; + + //------------------------------------------------------------------------------ + //! \brief Load the segment from a stream + //! \param stream Input stream + //! \param header_offset Offset of the segment header + //! \param is_lazy Whether to load the segment lazily + //! \return True if successful, false otherwise + virtual bool load( std::istream& stream, + std::streampos header_offset, + bool is_lazy ) = 0; + //------------------------------------------------------------------------------ + //! \brief Save the segment to a stream + //! \param stream Output stream + //! \param header_offset Offset of the segment header + //! \param data_offset Offset of the segment data + virtual void save( std::ostream& stream, + std::streampos header_offset, + std::streampos data_offset ) = 0; +}; + +//------------------------------------------------------------------------------ +//! \class segment_impl +//! \brief Implementation of the segment class +template class segment_impl : public segment +{ + public: + //------------------------------------------------------------------------------ + //! \brief Constructor + //! \param convertor Pointer to the endianness convertor + //! \param translator Pointer to the address translator + segment_impl( std::shared_ptr convertor, + std::shared_ptr translator ) + : convertor( convertor ), translator( translator ) + { + } + + //------------------------------------------------------------------------------ + // Section info functions + ELFIO_GET_SET_ACCESS( Elf_Word, type, ph.p_type ); + ELFIO_GET_SET_ACCESS( Elf_Word, flags, ph.p_flags ); + ELFIO_GET_SET_ACCESS( Elf_Xword, align, ph.p_align ); + ELFIO_GET_SET_ACCESS( Elf64_Addr, virtual_address, ph.p_vaddr ); + ELFIO_GET_SET_ACCESS( Elf64_Addr, physical_address, ph.p_paddr ); + ELFIO_GET_SET_ACCESS( Elf_Xword, file_size, ph.p_filesz ); + ELFIO_GET_SET_ACCESS( Elf_Xword, memory_size, ph.p_memsz ); + ELFIO_GET_ACCESS( Elf64_Off, offset, ph.p_offset ); + + //------------------------------------------------------------------------------ + //! \brief Get the index of the segment + //! \return Index of the segment + Elf_Half get_index() const override { return index; } + + //------------------------------------------------------------------------------ + //! \brief Get the data of the segment + //! \return Pointer to the data + const char* get_data() const override + { + if ( !is_loaded ) { + load_data(); + } + return data.get(); + } + + //------------------------------------------------------------------------------ + //! \brief Free the data of the segment + void free_data() const override + { + if ( is_lazy ) { + data.reset( nullptr ); + is_loaded = false; + } + } + + //------------------------------------------------------------------------------ + //! \brief Add a section index to the segment + //! \param sec_index Index of the section + //! \param addr_align Alignment of the section + //! \return Index of the added section + Elf_Half add_section_index( Elf_Half sec_index, + Elf_Xword addr_align ) override + { + sections.emplace_back( sec_index ); + if ( addr_align > get_align() ) { + set_align( addr_align ); + } + + return (Elf_Half)sections.size(); + } + + //------------------------------------------------------------------------------ + //! \brief Add a section to the segment + //! \param psec Pointer to the section + //! \param addr_align Alignment of the section + //! \return Index of the added section + Elf_Half add_section( section* psec, Elf_Xword addr_align ) override + { + return add_section_index( psec->get_index(), addr_align ); + } + + //------------------------------------------------------------------------------ + //! \brief Get the number of sections in the segment + //! \return Number of sections in the segment + Elf_Half get_sections_num() const override + { + return (Elf_Half)sections.size(); + } + + //------------------------------------------------------------------------------ + //! \brief Get the index of a section at a given position + //! \param num Position of the section + //! \return Index of the section + Elf_Half get_section_index_at( Elf_Half num ) const override + { + if ( num < sections.size() ) { + return sections[num]; + } + + return Elf_Half( -1 ); + } + + //------------------------------------------------------------------------------ + protected: + //------------------------------------------------------------------------------ + //! \brief Set the offset of the segment + //! \param value Offset of the segment + void set_offset( const Elf64_Off& value ) override + { + ph.p_offset = decltype( ph.p_offset )( value ); + ph.p_offset = ( *convertor )( ph.p_offset ); + is_offset_set = true; + } + + //------------------------------------------------------------------------------ + //! \brief Check if the offset is initialized + //! \return True if the offset is initialized, false otherwise + bool is_offset_initialized() const override { return is_offset_set; } + + //------------------------------------------------------------------------------ + //! \brief Get the sections of the segment + //! \return Vector of section indices + const std::vector& get_sections() const override + { + return sections; + } + + //------------------------------------------------------------------------------ + //! \brief Set the index of the segment + //! \param value Index of the segment + void set_index( const Elf_Half& value ) override { index = value; } + + //------------------------------------------------------------------------------ + //! \brief Load the segment from a stream + //! \param stream Input stream + //! \param header_offset Offset of the segment header + //! \param is_lazy_ Whether to load the segment lazily + //! \return True if successful, false otherwise + bool load( std::istream& stream, + std::streampos header_offset, + bool is_lazy_ ) override + { + pstream = &stream; + is_lazy = is_lazy_; + + if ( translator->empty() ) { + stream.seekg( 0, std::istream::end ); + set_stream_size( size_t( stream.tellg() ) ); + } + else { + set_stream_size( std::numeric_limits::max() ); + } + + stream.seekg( ( *translator )[header_offset] ); + stream.read( reinterpret_cast( &ph ), sizeof( ph ) ); + + is_offset_set = true; + + if ( !( is_lazy || is_loaded ) ) { + return load_data(); + } + + return true; + } + + //------------------------------------------------------------------------------ + //! \brief Load the data of the segment + //! \return True if successful, false otherwise + bool load_data() const + { + if ( PT_NULL == get_type() || 0 == get_file_size() ) { + return true; + } + + Elf_Xword p_offset = ( *translator )[( *convertor )( ph.p_offset )]; + Elf_Xword size = get_file_size(); + + // Check for integer overflow in offset calculation + if ( p_offset > get_stream_size() ) { + data = nullptr; + return false; + } + + // Check for integer overflow in size calculation + if ( size > get_stream_size() || + size > ( get_stream_size() - p_offset ) ) { + data = nullptr; + return false; + } + + // Check if size can be safely converted to size_t + if ( size > std::numeric_limits::max() - 1 ) { + data = nullptr; + return false; + } + + data.reset( new ( std::nothrow ) char[(size_t)size + 1] ); + + pstream->seekg( p_offset ); + if ( nullptr != data.get() && pstream->read( data.get(), size ) ) { + data.get()[size] = 0; + } + else { + data = nullptr; + return false; + } + + is_loaded = true; + + return true; + } + + //------------------------------------------------------------------------------ + //! \brief Save the segment to a stream + //! \param stream Output stream + //! \param header_offset Offset of the segment header + //! \param data_offset Offset of the segment data + void save( std::ostream& stream, + std::streampos header_offset, + std::streampos data_offset ) override + { + ph.p_offset = decltype( ph.p_offset )( data_offset ); + ph.p_offset = ( *convertor )( ph.p_offset ); + adjust_stream_size( stream, header_offset ); + stream.write( reinterpret_cast( &ph ), sizeof( ph ) ); + } + + //------------------------------------------------------------------------------ + //! \brief Get the stream size + //! \return Stream size + size_t get_stream_size() const { return stream_size; } + + //------------------------------------------------------------------------------ + //! \brief Set the stream size + //! \param value Stream size + void set_stream_size( size_t value ) { stream_size = value; } + + //------------------------------------------------------------------------------ + private: + mutable std::istream* pstream = nullptr; //!< Pointer to the input stream + T ph = {}; //!< Segment header + Elf_Half index = 0; //!< Index of the segment + mutable std::unique_ptr data; //!< Pointer to the segment data + std::vector sections; //!< Vector of section indices + std::shared_ptr convertor = + nullptr; //!< Pointer to the endianness convertor + std::shared_ptr translator = + nullptr; //!< Pointer to the address translator + size_t stream_size = 0; //!< Stream size + bool is_offset_set = false; //!< Flag indicating if the offset is set + mutable bool is_lazy = + false; //!< Flag indicating if the segment is loaded lazily + mutable bool is_loaded = + false; //!< Flag indicating if the segment is loaded +}; + +} // namespace ELFIO + +#endif // ELFIO_SEGMENT_HPP diff --git a/emulator/include/elfio/elfio_strings.hpp b/emulator/include/elfio/elfio_strings.hpp new file mode 100644 index 0000000..d56f24b --- /dev/null +++ b/emulator/include/elfio/elfio_strings.hpp @@ -0,0 +1,143 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_STRINGS_HPP +#define ELFIO_STRINGS_HPP + +#include +#include +#include +#include + +namespace ELFIO { + +//------------------------------------------------------------------------------ +//! \class string_section_accessor_template +//! \brief Class for accessing string section data +template class string_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + //! \brief Constructor + //! \param section Pointer to the section + explicit string_section_accessor_template( S* section ) + : string_section( section ) + { + } + + //------------------------------------------------------------------------------ + //! \brief Get a string from the section + //! \param index Index of the string + //! \return Pointer to the string, or nullptr if not found + const char* get_string( Elf_Word index ) const + { + if ( string_section ) { + const char* data = string_section->get_data(); + size_t section_size = + static_cast( string_section->get_size() ); + + // Check if index is within bounds + if ( index >= section_size || nullptr == data ) { + return nullptr; + } + + // Check for integer overflow in size calculation + size_t remaining_size = section_size - index; + if ( remaining_size > section_size ) { // Check for underflow + return nullptr; + } + + // Use standard C++ functions to find string length + const char* str = data + index; + const char* end = + (const char*)std::memchr( str, '\0', remaining_size ); + if ( end != nullptr && end < str + remaining_size ) { + return str; + } + } + + return nullptr; + } + + //------------------------------------------------------------------------------ + //! \brief Add a string to the section + //! \param str Pointer to the string + //! \return Index of the added string + Elf_Word add_string( const char* str ) + { + if ( !str ) { + return 0; // Return index of empty string for null input + } + + Elf_Word current_position = 0; + + if ( string_section ) { + // Strings are added to the end of the current section data + current_position = + static_cast( string_section->get_size() ); + + if ( current_position == 0 ) { + char empty_string = '\0'; + string_section->append_data( &empty_string, 1 ); + current_position++; + } + + // Calculate string length and check for overflow + size_t str_len = std::strlen( str ); + if ( str_len > std::numeric_limits::max() - 1 ) { + return 0; // String too long + } + + // Check if appending would overflow section size + Elf_Word append_size = static_cast( str_len + 1 ); + if ( append_size > + std::numeric_limits::max() - current_position ) { + return 0; // Would overflow section size + } + + string_section->append_data( str, append_size ); + } + + return current_position; + } + + //------------------------------------------------------------------------------ + //! \brief Add a string to the section + //! \param str The string to add + //! \return Index of the added string + Elf_Word add_string( const std::string& str ) + { + return add_string( str.c_str() ); + } + + //------------------------------------------------------------------------------ + private: + S* string_section; //!< Pointer to the section +}; + +using string_section_accessor = string_section_accessor_template
; +using const_string_section_accessor = + string_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_STRINGS_HPP diff --git a/emulator/include/elfio/elfio_symbols.hpp b/emulator/include/elfio/elfio_symbols.hpp new file mode 100644 index 0000000..aeb3a7a --- /dev/null +++ b/emulator/include/elfio/elfio_symbols.hpp @@ -0,0 +1,716 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_SYMBOLS_HPP +#define ELFIO_SYMBOLS_HPP + +namespace ELFIO { + +//------------------------------------------------------------------------------ +// @class symbol_section_accessor_template +// @brief A template class for accessing symbol sections in an ELF file. +//------------------------------------------------------------------------------ +template class symbol_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + // @brief Constructor + // @param elf_file Reference to the ELF file + // @param symbol_section Pointer to the symbol section + //------------------------------------------------------------------------------ + explicit symbol_section_accessor_template( const elfio& elf_file, + S* symbol_section ) + : elf_file( elf_file ), symbol_section( symbol_section ) + { + find_hash_section(); + } + + //------------------------------------------------------------------------------ + // @brief Get the number of symbols in the section + // @return Number of symbols + //------------------------------------------------------------------------------ + Elf_Xword get_symbols_num() const + { + Elf_Xword nRet = 0; + + size_t minimum_symbol_size; + switch ( elf_file.get_class() ) { + case ELFCLASS32: + minimum_symbol_size = sizeof( Elf32_Sym ); + break; + case ELFCLASS64: + minimum_symbol_size = sizeof( Elf64_Sym ); + break; + default: + return nRet; + } + + if ( symbol_section->get_entry_size() >= minimum_symbol_size && + symbol_section->get_size() <= symbol_section->get_stream_size() ) { + nRet = + symbol_section->get_size() / symbol_section->get_entry_size(); + } + + return nRet; + } + + //------------------------------------------------------------------------------ + // @brief Get the symbol at the specified index + // @param index Index of the symbol + // @param name Name of the symbol + // @param value Value of the symbol + // @param size Size of the symbol + // @param bind Binding of the symbol + // @param type Type of the symbol + // @param section_index Section index of the symbol + // @param other Other attributes of the symbol + // @return True if the symbol is found, false otherwise + //------------------------------------------------------------------------------ + bool get_symbol( Elf_Xword index, + std::string& name, + Elf64_Addr& value, + Elf_Xword& size, + unsigned char& bind, + unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + bool ret = false; + + if ( elf_file.get_class() == ELFCLASS32 ) { + ret = generic_get_symbol( index, name, value, size, bind, + type, section_index, other ); + } + else { + ret = generic_get_symbol( index, name, value, size, bind, + type, section_index, other ); + } + + return ret; + } + + //------------------------------------------------------------------------------ + // @brief Get the symbol with the specified name + // @param name Name of the symbol + // @param value Value of the symbol + // @param size Size of the symbol + // @param bind Binding of the symbol + // @param type Type of the symbol + // @param section_index Section index of the symbol + // @param other Other attributes of the symbol + // @return True if the symbol is found, false otherwise + //------------------------------------------------------------------------------ + bool get_symbol( const std::string& name, + Elf64_Addr& value, + Elf_Xword& size, + unsigned char& bind, + unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + bool ret = false; + + if ( 0 != get_hash_table_index() ) { + if ( hash_section->get_type() == SHT_HASH ) { + ret = hash_lookup( name, value, size, bind, type, section_index, + other ); + } + if ( hash_section->get_type() == SHT_GNU_HASH || + hash_section->get_type() == DT_GNU_HASH ) { + if ( elf_file.get_class() == ELFCLASS32 ) { + ret = gnu_hash_lookup( + name, value, size, bind, type, section_index, other ); + } + else { + ret = gnu_hash_lookup( + name, value, size, bind, type, section_index, other ); + } + } + } + + if ( !ret ) { + for ( Elf_Xword i = 0; !ret && i < get_symbols_num(); i++ ) { + std::string symbol_name; + if ( get_symbol( i, symbol_name, value, size, bind, type, + section_index, other ) && + ( symbol_name == name ) ) { + ret = true; + } + } + } + + return ret; + } + + //------------------------------------------------------------------------------ + // @brief Get the symbol with the specified value + // @param value Value of the symbol + // @param name Name of the symbol + // @param size Size of the symbol + // @param bind Binding of the symbol + // @param type Type of the symbol + // @param section_index Section index of the symbol + // @param other Other attributes of the symbol + // @return True if the symbol is found, false otherwise + //------------------------------------------------------------------------------ + bool get_symbol( const Elf64_Addr& value, + std::string& name, + Elf_Xword& size, + unsigned char& bind, + unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + + const auto& convertor = elf_file.get_convertor(); + + Elf_Xword idx = 0; + bool match = false; + Elf64_Addr v = 0; + + if ( elf_file.get_class() == ELFCLASS32 ) { + match = generic_search_symbols( + [&]( const Elf32_Sym* sym ) { + return ( *convertor )( sym->st_value ) == value; + }, + idx ); + } + else { + match = generic_search_symbols( + [&]( const Elf64_Sym* sym ) { + return ( *convertor )( sym->st_value ) == value; + }, + idx ); + } + + if ( match ) { + return get_symbol( idx, name, v, size, bind, type, section_index, + other ); + } + + return false; + } + + //------------------------------------------------------------------------------ + // @brief Add a symbol to the section + // @param name Name of the symbol + // @param value Value of the symbol + // @param size Size of the symbol + // @param info Info of the symbol + // @param other Other attributes of the symbol + // @param shndx Section index of the symbol + // @return Index of the added symbol + //------------------------------------------------------------------------------ + Elf_Word add_symbol( Elf_Word name, + Elf64_Addr value, + Elf_Xword size, + unsigned char info, + unsigned char other, + Elf_Half shndx ) + { + Elf_Word nRet; + + if ( symbol_section->get_size() == 0 ) { + if ( elf_file.get_class() == ELFCLASS32 ) { + nRet = generic_add_symbol( 0, 0, 0, 0, 0, 0 ); + } + else { + nRet = generic_add_symbol( 0, 0, 0, 0, 0, 0 ); + } + } + + if ( elf_file.get_class() == ELFCLASS32 ) { + nRet = generic_add_symbol( name, value, size, info, + other, shndx ); + } + else { + nRet = generic_add_symbol( name, value, size, info, + other, shndx ); + } + + return nRet; + } + + //------------------------------------------------------------------------------ + // @brief Add a symbol to the section + // @param name Name of the symbol + // @param value Value of the symbol + // @param size Size of the symbol + // @param bind Binding of the symbol + // @param type Type of the symbol + // @param other Other attributes of the symbol + // @param shndx Section index of the symbol + // @return Index of the added symbol + //------------------------------------------------------------------------------ + Elf_Word add_symbol( Elf_Word name, + Elf64_Addr value, + Elf_Xword size, + unsigned char bind, + unsigned char type, + unsigned char other, + Elf_Half shndx ) + { + return add_symbol( name, value, size, ELF_ST_INFO( bind, type ), other, + shndx ); + } + + //------------------------------------------------------------------------------ + // @brief Add a symbol to the section + // @param pStrWriter String section accessor + // @param str Name of the symbol + // @param value Value of the symbol + // @param size Size of the symbol + // @param info Info of the symbol + // @param other Other attributes of the symbol + // @param shndx Section index of the symbol + // @return Index of the added symbol + //------------------------------------------------------------------------------ + Elf_Word add_symbol( string_section_accessor& pStrWriter, + const char* str, + Elf64_Addr value, + Elf_Xword size, + unsigned char info, + unsigned char other, + Elf_Half shndx ) + { + Elf_Word index = pStrWriter.add_string( str ); + return add_symbol( index, value, size, info, other, shndx ); + } + + //------------------------------------------------------------------------------ + // @brief Add a symbol to the section + // @param pStrWriter String section accessor + // @param str Name of the symbol + // @param value Value of the symbol + // @param size Size of the symbol + // @param bind Binding of the symbol + // @param type Type of the symbol + // @param other Other attributes of the symbol + // @param shndx Section index of the symbol + // @return Index of the added symbol + //------------------------------------------------------------------------------ + Elf_Word add_symbol( string_section_accessor& pStrWriter, + const char* str, + Elf64_Addr value, + Elf_Xword size, + unsigned char bind, + unsigned char type, + unsigned char other, + Elf_Half shndx ) + { + return add_symbol( pStrWriter, str, value, size, + ELF_ST_INFO( bind, type ), other, shndx ); + } + + //------------------------------------------------------------------------------ + // @brief Arrange local symbols in the section + // @param func Function to be called for each pair of symbols + // @return Number of local symbols + //------------------------------------------------------------------------------ + Elf_Xword arrange_local_symbols( + std::function func = + nullptr ) + { + Elf_Xword nRet = 0; + + if ( elf_file.get_class() == ELFCLASS32 ) { + nRet = generic_arrange_local_symbols( func ); + } + else { + nRet = generic_arrange_local_symbols( func ); + } + + return nRet; + } + + //------------------------------------------------------------------------------ + private: + //------------------------------------------------------------------------------ + // @brief Find the hash section + //------------------------------------------------------------------------------ + void find_hash_section() + { + Elf_Half nSecNo = elf_file.sections.size(); + for ( Elf_Half i = 0; i < nSecNo; ++i ) { + const section* sec = elf_file.sections[i]; + if ( sec->get_link() == symbol_section->get_index() && + ( sec->get_type() == SHT_HASH || + sec->get_type() == SHT_GNU_HASH || + sec->get_type() == DT_GNU_HASH ) ) { + hash_section = sec; + hash_section_index = i; + break; + } + } + } + + //------------------------------------------------------------------------------ + // @brief Get the index of the string table + // @return Index of the string table + //------------------------------------------------------------------------------ + Elf_Half get_string_table_index() const + { + return (Elf_Half)symbol_section->get_link(); + } + + //------------------------------------------------------------------------------ + // @brief Get the index of the hash table + // @return Index of the hash table + //------------------------------------------------------------------------------ + Elf_Half get_hash_table_index() const { return hash_section_index; } + + //------------------------------------------------------------------------------ + // @brief Lookup a symbol in the hash table + // @param name Name of the symbol + // @param value Value of the symbol + // @param size Size of the symbol + // @param bind Binding of the symbol + // @param type Type of the symbol + // @param section_index Section index of the symbol + // @param other Other attributes of the symbol + // @return True if the symbol is found, false otherwise + //------------------------------------------------------------------------------ + bool hash_lookup( const std::string& name, + Elf64_Addr& value, + Elf_Xword& size, + unsigned char& bind, + unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + bool ret = false; + const auto& convertor = elf_file.get_convertor(); + + Elf_Word nbucket = *(const Elf_Word*)hash_section->get_data(); + nbucket = ( *convertor )( nbucket ); + Elf_Word nchain = + *(const Elf_Word*)( hash_section->get_data() + sizeof( Elf_Word ) ); + nchain = ( *convertor )( nchain ); + Elf_Word val = elf_hash( (const unsigned char*)name.c_str() ); + Elf_Word y = + *(const Elf_Word*)( hash_section->get_data() + + ( 2 + val % nbucket ) * sizeof( Elf_Word ) ); + y = ( *convertor )( y ); + std::string str; + get_symbol( y, str, value, size, bind, type, section_index, other ); + while ( str != name && STN_UNDEF != y && y < nchain ) { + y = *(const Elf_Word*)( hash_section->get_data() + + ( 2 + nbucket + y ) * sizeof( Elf_Word ) ); + y = ( *convertor )( y ); + get_symbol( y, str, value, size, bind, type, section_index, other ); + } + + if ( str == name ) { + ret = true; + } + + return ret; + } + + //------------------------------------------------------------------------------ + // @brief Lookup a symbol in the GNU hash table + // @param name Name of the symbol + // @param value Value of the symbol + // @param size Size of the symbol + // @param bind Binding of the symbol + // @param type Type of the symbol + // @param section_index Section index of the symbol + // @param other Other attributes of the symbol + // @return True if the symbol is found, false otherwise + //------------------------------------------------------------------------------ + template + bool gnu_hash_lookup( const std::string& name, + Elf64_Addr& value, + Elf_Xword& size, + unsigned char& bind, + unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + bool ret = false; + const auto& convertor = elf_file.get_convertor(); + + std::uint32_t nbuckets = + *( (std::uint32_t*)hash_section->get_data() + 0 ); + std::uint32_t symoffset = + *( (std::uint32_t*)hash_section->get_data() + 1 ); + std::uint32_t bloom_size = + *( (std::uint32_t*)hash_section->get_data() + 2 ); + std::uint32_t bloom_shift = + *( (std::uint32_t*)hash_section->get_data() + 3 ); + nbuckets = ( *convertor )( nbuckets ); + symoffset = ( *convertor )( symoffset ); + bloom_size = ( *convertor )( bloom_size ); + bloom_shift = ( *convertor )( bloom_shift ); + + auto* bloom_filter = + (T*)( hash_section->get_data() + 4 * sizeof( std::uint32_t ) ); + + std::uint32_t hash = elf_gnu_hash( (const unsigned char*)name.c_str() ); + std::uint32_t bloom_index = ( hash / ( 8 * sizeof( T ) ) ) % bloom_size; + T bloom_bits = + ( (T)1 << ( hash % ( 8 * sizeof( T ) ) ) ) | + ( (T)1 << ( ( hash >> bloom_shift ) % ( 8 * sizeof( T ) ) ) ); + + if ( ( ( *convertor )( bloom_filter[bloom_index] ) & bloom_bits ) != + bloom_bits ) + return ret; + + std::uint32_t bucket = hash % nbuckets; + auto* buckets = (std::uint32_t*)( hash_section->get_data() + + 4 * sizeof( std::uint32_t ) + + bloom_size * sizeof( T ) ); + auto* chains = (std::uint32_t*)( hash_section->get_data() + + 4 * sizeof( std::uint32_t ) + + bloom_size * sizeof( T ) + + nbuckets * sizeof( std::uint32_t ) ); + + if ( ( *convertor )( buckets[bucket] ) >= symoffset ) { + std::uint32_t chain_index = + ( *convertor )( buckets[bucket] ) - symoffset; + std::uint32_t chain_hash = ( *convertor )( chains[chain_index] ); + std::string symname; + + while ( true ) { + if ( ( chain_hash >> 1 ) == ( hash >> 1 ) && + get_symbol( chain_index + symoffset, symname, value, size, + bind, type, section_index, other ) && + ( name == symname ) ) { + ret = true; + break; + } + + if ( chain_hash & 1 ) + break; + + chain_hash = ( *convertor )( chains[++chain_index] ); + } + } + + return ret; + } + + //------------------------------------------------------------------------------ + // @brief Get the symbol at the specified index + // @param index Index of the symbol + // @return Pointer to the symbol + //------------------------------------------------------------------------------ + template const T* generic_get_symbol_ptr( Elf_Xword index ) const + { + if ( 0 != symbol_section->get_data() && index < get_symbols_num() ) { + if ( symbol_section->get_entry_size() < sizeof( T ) ) { + return nullptr; + } + const auto* pSym = reinterpret_cast( + symbol_section->get_data() + + index * symbol_section->get_entry_size() ); + + return pSym; + } + + return nullptr; + } + + //------------------------------------------------------------------------------ + // @brief Search for a symbol in the section + // @param match Function to be called for each symbol + // @param idx Index of the found symbol + // @return True if the symbol is found, false otherwise + //------------------------------------------------------------------------------ + template + bool generic_search_symbols( std::function match, + Elf_Xword& idx ) const + { + for ( Elf_Xword i = 0; i < get_symbols_num(); i++ ) { + const T* symPtr = generic_get_symbol_ptr( i ); + + if ( symPtr == nullptr ) + return false; + + if ( match( symPtr ) ) { + idx = i; + return true; + } + } + + return false; + } + + //------------------------------------------------------------------------------ + // @brief Get the symbol at the specified index + // @param index Index of the symbol + // @param name Name of the symbol + // @param value Value of the symbol + // @param size Size of the symbol + // @param bind Binding of the symbol + // @param type Type of the symbol + // @param section_index Section index of the symbol + // @param other Other attributes of the symbol + // @return True if the symbol is found, false otherwise + //------------------------------------------------------------------------------ + template + bool generic_get_symbol( Elf_Xword index, + std::string& name, + Elf64_Addr& value, + Elf_Xword& size, + unsigned char& bind, + unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + bool ret = false; + + if ( nullptr != symbol_section->get_data() && + index < get_symbols_num() ) { + const auto* pSym = reinterpret_cast( + symbol_section->get_data() + + index * symbol_section->get_entry_size() ); + + const auto& convertor = elf_file.get_convertor(); + + section* string_section = + elf_file.sections[get_string_table_index()]; + string_section_accessor str_reader( string_section ); + const char* pStr = + str_reader.get_string( ( *convertor )( pSym->st_name ) ); + if ( nullptr != pStr ) { + name = pStr; + } + value = ( *convertor )( pSym->st_value ); + size = ( *convertor )( pSym->st_size ); + bind = ELF_ST_BIND( pSym->st_info ); + type = ELF_ST_TYPE( pSym->st_info ); + section_index = ( *convertor )( pSym->st_shndx ); + other = pSym->st_other; + + ret = true; + } + + return ret; + } + + //------------------------------------------------------------------------------ + // @brief Add a symbol to the section + // @param name Name of the symbol + // @param value Value of the symbol + // @param size Size of the symbol + // @param info Info of the symbol + // @param other Other attributes of the symbol + // @param shndx Section index of the symbol + // @return Index of the added symbol + //------------------------------------------------------------------------------ + template + Elf_Word generic_add_symbol( Elf_Word name, + Elf64_Addr value, + Elf_Xword size, + unsigned char info, + unsigned char other, + Elf_Half shndx ) + { + const auto& convertor = elf_file.get_convertor(); + + T entry; + entry.st_name = ( *convertor )( name ); + entry.st_value = decltype( entry.st_value )( value ); + entry.st_value = ( *convertor )( entry.st_value ); + entry.st_size = decltype( entry.st_size )( size ); + entry.st_size = ( *convertor )( entry.st_size ); + entry.st_info = ( *convertor )( info ); + entry.st_other = ( *convertor )( other ); + entry.st_shndx = ( *convertor )( shndx ); + + symbol_section->append_data( reinterpret_cast( &entry ), + sizeof( entry ) ); + + Elf_Word nRet = + Elf_Word( symbol_section->get_size() / sizeof( entry ) - 1 ); + + return nRet; + } + + //------------------------------------------------------------------------------ + // @brief Arrange local symbols in the section + // @param func Function to be called for each pair of symbols + // @return Number of local symbols + //------------------------------------------------------------------------------ + template + Elf_Xword generic_arrange_local_symbols( + std::function func ) + { + const auto& convertor = elf_file.get_convertor(); + + Elf_Word first_not_local = + 1; // Skip the first entry. It is always NOTYPE + Elf_Xword current = 0; + Elf_Xword count = get_symbols_num(); + + while ( true ) { + T* p1 = nullptr; + T* p2 = nullptr; + + while ( first_not_local < count ) { + p1 = const_cast( + generic_get_symbol_ptr( first_not_local ) ); + if ( ELF_ST_BIND( ( *convertor )( p1->st_info ) ) != STB_LOCAL ) + break; + ++first_not_local; + } + + current = first_not_local + 1; + while ( current < count ) { + p2 = const_cast( generic_get_symbol_ptr( current ) ); + if ( ELF_ST_BIND( ( *convertor )( p2->st_info ) ) == STB_LOCAL ) + break; + ++current; + } + + if ( first_not_local < count && current < count ) { + if ( func ) + func( first_not_local, current ); + + std::swap( *p1, *p2 ); + } + else { + // Update 'info' field of the section + symbol_section->set_info( first_not_local ); + break; + } + } + + return first_not_local; + } + + //------------------------------------------------------------------------------ + private: + const elfio& elf_file; ///< Reference to the ELF file + S* symbol_section; ///< Pointer to the symbol section + Elf_Half hash_section_index{ 0 }; ///< Index of the hash section + const section* hash_section{ nullptr }; ///< Pointer to the hash section +}; + +using symbol_section_accessor = symbol_section_accessor_template
; +using const_symbol_section_accessor = + symbol_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_SYMBOLS_HPP diff --git a/emulator/include/elfio/elfio_utils.hpp b/emulator/include/elfio/elfio_utils.hpp new file mode 100644 index 0000000..d24555e --- /dev/null +++ b/emulator/include/elfio/elfio_utils.hpp @@ -0,0 +1,373 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_UTILS_HPP +#define ELFIO_UTILS_HPP + +#include +#include +#include + +#define ELFIO_GET_ACCESS_DECL( TYPE, NAME ) virtual TYPE get_##NAME() const = 0 + +#define ELFIO_SET_ACCESS_DECL( TYPE, NAME ) \ + virtual void set_##NAME( const TYPE& value ) = 0 + +#define ELFIO_GET_SET_ACCESS_DECL( TYPE, NAME ) \ + virtual TYPE get_##NAME() const = 0; \ + virtual void set_##NAME( const TYPE& value ) = 0 + +#define ELFIO_GET_ACCESS( TYPE, NAME, FIELD ) \ + TYPE get_##NAME() const override { return ( *convertor )( FIELD ); } + +#define ELFIO_SET_ACCESS( TYPE, NAME, FIELD ) \ + void set_##NAME( const TYPE& value ) override \ + { \ + FIELD = decltype( FIELD )( value ); \ + FIELD = ( *convertor )( FIELD ); \ + } +#define ELFIO_GET_SET_ACCESS( TYPE, NAME, FIELD ) \ + TYPE get_##NAME() const override { return ( *convertor )( FIELD ); } \ + void set_##NAME( const TYPE& value ) override \ + { \ + FIELD = decltype( FIELD )( value ); \ + FIELD = ( *convertor )( FIELD ); \ + } + +namespace ELFIO { + +//------------------------------------------------------------------------------ +//! \class endianness_convertor +//! \brief Class for converting endianness of data +class endianness_convertor +{ + public: + //------------------------------------------------------------------------------ + //! \brief Setup the endianness convertor + //! \param elf_file_encoding The encoding of the ELF file + void setup( unsigned char elf_file_encoding ) + { + need_conversion = ( elf_file_encoding != get_host_encoding() ); + } + + //------------------------------------------------------------------------------ + //! \brief Convert a 64-bit unsigned integer + //! \param value The value to convert + //! \return The converted value + std::uint64_t operator()( std::uint64_t value ) const + { + if ( !need_conversion ) { + return value; + } + value = ( ( value & 0x00000000000000FFuLL ) << 56 ) | + ( ( value & 0x000000000000FF00uLL ) << 40 ) | + ( ( value & 0x0000000000FF0000uLL ) << 24 ) | + ( ( value & 0x00000000FF000000uLL ) << 8 ) | + ( ( value & 0x000000FF00000000uLL ) >> 8 ) | + ( ( value & 0x0000FF0000000000uLL ) >> 24 ) | + ( ( value & 0x00FF000000000000uLL ) >> 40 ) | + ( ( value & 0xFF00000000000000uLL ) >> 56 ); + + return value; + } + + //------------------------------------------------------------------------------ + //! \brief Convert a 64-bit signed integer + //! \param value The value to convert + //! \return The converted value + std::int64_t operator()( std::int64_t value ) const + { + if ( !need_conversion ) { + return value; + } + return ( std::int64_t )( *this )( (std::uint64_t)value ); + } + + //------------------------------------------------------------------------------ + //! \brief Convert a 32-bit unsigned integer + //! \param value The value to convert + //! \return The converted value + std::uint32_t operator()( std::uint32_t value ) const + { + if ( !need_conversion ) { + return value; + } + value = + ( ( value & 0x000000FF ) << 24 ) | ( ( value & 0x0000FF00 ) << 8 ) | + ( ( value & 0x00FF0000 ) >> 8 ) | ( ( value & 0xFF000000 ) >> 24 ); + + return value; + } + + //------------------------------------------------------------------------------ + //! \brief Convert a 32-bit signed integer + //! \param value The value to convert + //! \return The converted value + std::int32_t operator()( std::int32_t value ) const + { + if ( !need_conversion ) { + return value; + } + return ( std::int32_t )( *this )( (std::uint32_t)value ); + } + + //------------------------------------------------------------------------------ + //! \brief Convert a 16-bit unsigned integer + //! \param value The value to convert + //! \return The converted value + std::uint16_t operator()( std::uint16_t value ) const + { + if ( !need_conversion ) { + return value; + } + value = ( std::uint16_t )( ( value & 0x00FF ) << 8 ) | + ( ( value & 0xFF00 ) >> 8 ); + + return value; + } + + //------------------------------------------------------------------------------ + //! \brief Convert a 16-bit signed integer + //! \param value The value to convert + //! \return The converted value + std::int16_t operator()( std::int16_t value ) const + { + if ( !need_conversion ) { + return value; + } + return ( std::int16_t )( *this )( (std::uint16_t)value ); + } + + //------------------------------------------------------------------------------ + //! \brief Convert an 8-bit signed integer + //! \param value The value to convert + //! \return The converted value + std::int8_t operator()( std::int8_t value ) const { return value; } + + //------------------------------------------------------------------------------ + //! \brief Convert an 8-bit unsigned integer + //! \param value The value to convert + //! \return The converted value + std::uint8_t operator()( std::uint8_t value ) const { return value; } + + //------------------------------------------------------------------------------ + private: + //------------------------------------------------------------------------------ + //! \brief Get the host encoding + //! \return The host encoding + unsigned char get_host_encoding() const + { + static const int tmp = 1; + if ( 1 == *reinterpret_cast( &tmp ) ) { + return ELFDATA2LSB; + } + else { + return ELFDATA2MSB; + } + } + + //------------------------------------------------------------------------------ + bool need_conversion = false; //!< Flag indicating if conversion is needed +}; + +//------------------------------------------------------------------------------ +//! \struct address_translation +//! \brief Structure for address translation +struct address_translation +{ + //------------------------------------------------------------------------------ + //! \brief Constructor + //! \param start The start address + //! \param size The size of the address range + //! \param mapped_to The mapped address + address_translation( std::uint64_t start, + std::uint64_t size, + std::uint64_t mapped_to ) + : start( start ), size( size ), mapped_to( mapped_to ){}; + std::streampos start; //!< Start address + std::streampos size; //!< Size of the address range + std::streampos mapped_to; //!< Mapped address +}; + +//------------------------------------------------------------------------------ +//! \class address_translator +//! \brief Class for translating addresses +class address_translator +{ + public: + //------------------------------------------------------------------------------ + //! \brief Set address translation + //! \param addr_trans Vector of address translations + void set_address_translation( std::vector& addr_trans ) + { + addr_translations = addr_trans; + + std::sort( addr_translations.begin(), addr_translations.end(), + []( const address_translation& a, + const address_translation& b ) -> bool { + return a.start < b.start; + } ); + } + + //------------------------------------------------------------------------------ + //! \brief Translate an address + //! \param value The address to translate + //! \return The translated address + std::streampos operator[]( std::streampos value ) const + { + if ( addr_translations.empty() ) { + return value; + } + + for ( auto& t : addr_translations ) { + if ( ( t.start <= value ) && ( ( value - t.start ) < t.size ) ) { + return value - t.start + t.mapped_to; + } + } + + return value; + } + + //------------------------------------------------------------------------------ + //! \brief Check if the address translator is empty + //! \return True if empty, false otherwise + bool empty() const { return addr_translations.empty(); } + + private: + std::vector + addr_translations; //!< Vector of address translations +}; + +//------------------------------------------------------------------------------ +//! \brief Calculate the ELF hash of a name +//! \param name The name to hash +//! \return The ELF hash +inline std::uint32_t elf_hash( const unsigned char* name ) +{ + std::uint32_t h = 0; + std::uint32_t g = 0; + while ( *name != '\0' ) { + h = ( h << 4 ) + *name++; + g = h & 0xf0000000; + if ( g != 0 ) + h ^= g >> 24; + h &= ~g; + } + return h; +} + +//------------------------------------------------------------------------------ +//! \brief Calculate the GNU hash of a name +//! \param s The name to hash +//! \return The GNU hash +inline std::uint32_t elf_gnu_hash( const unsigned char* s ) +{ + std::uint32_t h = 0x1505; + for ( unsigned char c = *s; c != '\0'; c = *++s ) + h = ( h << 5 ) + h + c; + return h; +} + +//------------------------------------------------------------------------------ +//! \brief Convert a value to a hexadecimal string +//! \param value The value to convert +//! \return The hexadecimal string +inline std::string to_hex_string( std::uint64_t value ) +{ + std::string str; + + while ( value ) { + if ( auto digit = value & 0xF; digit < 0xA ) { + str = char( '0' + digit ) + str; + } + else { + str = char( 'A' + digit - 0xA ) + str; + } + value >>= 4; + } + + return "0x" + str; +} + +//------------------------------------------------------------------------------ +//! \brief Adjust the size of a stream +//! \param stream The stream to adjust +//! \param offset The offset to adjust to +inline void adjust_stream_size( std::ostream& stream, std::streamsize offset ) +{ + stream.seekp( 0, std::ios_base::end ); + if ( stream.tellp() < offset ) { + std::streamsize size = offset - stream.tellp(); + stream.write( std::string( size_t( size ), '\0' ).c_str(), size ); + } + stream.seekp( offset ); +} + +//------------------------------------------------------------------------------ +//! \brief Get the length of a string with a maximum length +//! \param s The string +//! \param n The maximum length +//! \return The length of the string +inline static size_t strnlength( const char* s, size_t n ) +{ + auto found = (const char*)std::memchr( s, '\0', n ); + return found ? (size_t)( found - s ) : n; +} + +//------------------------------------------------------------------------------ +//! \class compression_interface +//! \brief Interface for compression and decompression +class compression_interface +{ + public: + virtual ~compression_interface() = default; + + //------------------------------------------------------------------------------ + //! \brief Decompress a compressed section + //! \param data The buffer of compressed data + //! \param convertor Pointer to an endianness convertor instance + //! \param compressed_size The size of the compressed data buffer + //! \param uncompressed_size Reference to a variable to store the decompressed buffer size + //! \return A smart pointer to the decompressed data + virtual std::unique_ptr + inflate( const char* data, + std::shared_ptr convertor, + Elf_Xword compressed_size, + Elf_Xword& uncompressed_size ) const = 0; + + //------------------------------------------------------------------------------ + //! \brief Compress a section + //! \param data The buffer of uncompressed data + //! \param convertor Pointer to an endianness convertor instance + //! \param decompressed_size The size of the uncompressed data buffer + //! \param compressed_size Reference to a variable to store the compressed buffer size + //! \return A smart pointer to the compressed data + virtual std::unique_ptr + deflate( const char* data, + std::shared_ptr convertor, + Elf_Xword decompressed_size, + Elf_Xword& compressed_size ) const = 0; +}; + +} // namespace ELFIO + +#endif // ELFIO_UTILS_HPP diff --git a/emulator/include/elfio/elfio_version.hpp b/emulator/include/elfio/elfio_version.hpp new file mode 100644 index 0000000..0a1426d --- /dev/null +++ b/emulator/include/elfio/elfio_version.hpp @@ -0,0 +1,4 @@ +//------------------------------------------------------------------------------ +//! \def ELFIO_VERSION +//! \brief Defines the version of the ELFIO library +#define ELFIO_VERSION "3.14" diff --git a/emulator/include/elfio/elfio_versym.hpp b/emulator/include/elfio/elfio_versym.hpp new file mode 100644 index 0000000..16f735f --- /dev/null +++ b/emulator/include/elfio/elfio_versym.hpp @@ -0,0 +1,310 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_VERSYM_HPP +#define ELFIO_VERSYM_HPP + +namespace ELFIO { + +//------------------------------------------------------------------------------ +//! \class versym_section_accessor_template +//! \brief Class for accessing version symbol section data +template class versym_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + //! \brief Constructor + //! \param section Pointer to the section + explicit versym_section_accessor_template( S* section ) + : versym_section( section ) + { + if ( section != nullptr ) { + entries_num = decltype( entries_num )( section->get_size() / + sizeof( Elf_Half ) ); + } + } + + //------------------------------------------------------------------------------ + //! \brief Get the number of entries + //! \return Number of entries + Elf_Word get_entries_num() const + { + if ( versym_section ) { + return entries_num; + } + return 0; + } + + //------------------------------------------------------------------------------ + //! \brief Get an entry + //! \param no Index of the entry + //! \param value Value of the entry + //! \return True if successful, false otherwise + bool get_entry( Elf_Word no, Elf_Half& value ) const + { + if ( versym_section && ( no < get_entries_num() ) ) { + value = ( (Elf_Half*)versym_section->get_data() )[no]; + return true; + } + + return false; + } + + //------------------------------------------------------------------------------ + //! \brief Modify an entry + //! \param no Index of the entry + //! \param value New value of the entry + //! \return True if successful, false otherwise + bool modify_entry( Elf_Word no, Elf_Half value ) + { + if ( versym_section && ( no < get_entries_num() ) ) { + ( (Elf_Half*)versym_section->get_data() )[no] = value; + return true; + } + + return false; + } + + //------------------------------------------------------------------------------ + //! \brief Add an entry + //! \param value Value of the entry + //! \return True if successful, false otherwise + bool add_entry( Elf_Half value ) + { + if ( !versym_section ) { + return false; + } + + versym_section->append_data( (const char*)&value, sizeof( Elf_Half ) ); + ++entries_num; + + return true; + } + + //------------------------------------------------------------------------------ + private: + S* versym_section = nullptr; //!< Pointer to the section + Elf_Word entries_num = 0; //!< Number of entries +}; + +using versym_section_accessor = versym_section_accessor_template
; +using const_versym_section_accessor = + versym_section_accessor_template; + +//------------------------------------------------------------------------------ +//! \class versym_r_section_accessor_template +//! \brief Class for accessing version requirement section data +template class versym_r_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + //! \brief Constructor + //! \param elf_file Reference to the ELF file + //! \param versym_r_section Pointer to the version requirement section + versym_r_section_accessor_template( const elfio& elf_file, + S* versym_r_section ) + : elf_file( elf_file ), versym_r_section( versym_r_section ), + entries_num( 0 ) + { + // Find .dynamic section + const section* dynamic_section = elf_file.sections[".dynamic"]; + + if ( dynamic_section == nullptr ) { + return; + } + + const_dynamic_section_accessor dynamic_section_acc( elf_file, + dynamic_section ); + Elf_Xword dyn_sec_num = dynamic_section_acc.get_entries_num(); + for ( Elf_Xword i = 0; i < dyn_sec_num; ++i ) { + Elf_Xword tag; + Elf_Xword value; + std::string str; + + if ( dynamic_section_acc.get_entry( i, tag, value, str ) && + tag == DT_VERNEEDNUM ) { + entries_num = (Elf_Word)value; + break; + } + } + } + + //------------------------------------------------------------------------------ + //! \brief Get the number of entries + //! \return Number of entries + Elf_Word get_entries_num() const { return entries_num; } + + //------------------------------------------------------------------------------ + //! \brief Get an entry + //! \param no Index of the entry + //! \param version Version of the entry + //! \param file_name File name of the entry + //! \param hash Hash of the entry + //! \param flags Flags of the entry + //! \param other Other information of the entry + //! \param dep_name Dependency name of the entry + //! \return True if successful, false otherwise + bool get_entry( Elf_Word no, + Elf_Half& version, + std::string& file_name, + Elf_Word& hash, + Elf_Half& flags, + Elf_Half& other, + std::string& dep_name ) const + { + if ( versym_r_section == nullptr || ( no >= get_entries_num() ) ) { + return false; + } + + const_string_section_accessor string_section_acc( + elf_file.sections[versym_r_section->get_link()] ); + + Elfxx_Verneed* verneed = (Elfxx_Verneed*)versym_r_section->get_data(); + Elfxx_Vernaux* veraux = + (Elfxx_Vernaux*)( (char*)verneed + verneed->vn_aux ); + for ( Elf_Word i = 0; i < no; ++i ) { + verneed = (Elfxx_Verneed*)( (char*)verneed + verneed->vn_next ); + veraux = (Elfxx_Vernaux*)( (char*)verneed + verneed->vn_aux ); + } + + version = verneed->vn_version; + file_name = string_section_acc.get_string( verneed->vn_file ); + hash = veraux->vna_hash; + flags = veraux->vna_flags; + other = veraux->vna_other; + dep_name = string_section_acc.get_string( veraux->vna_name ); + + return true; + } + + //------------------------------------------------------------------------------ + private: + const elfio& elf_file; + S* versym_r_section = + nullptr; //!< Pointer to the version requirement section + Elf_Word entries_num = 0; //!< Number of entries +}; + +using versym_r_section_accessor = versym_r_section_accessor_template
; +using const_versym_r_section_accessor = + versym_r_section_accessor_template; + +//------------------------------------------------------------------------------ +//! \class versym_d_section_accessor_template +//! \brief Class for accessing version definition section data +template class versym_d_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + //! \brief Constructor + //! \param elf_file Reference to the ELF file + //! \param versym_d_section Pointer to the version definition section + versym_d_section_accessor_template( const elfio& elf_file, + S* versym_d_section ) + : elf_file( elf_file ), versym_d_section( versym_d_section ), + entries_num( 0 ) + { + // Find .dynamic section + const section* dynamic_section = elf_file.sections[".dynamic"]; + + if ( dynamic_section == nullptr ) { + return; + } + + const_dynamic_section_accessor dynamic_section_acc( elf_file, + dynamic_section ); + Elf_Xword dyn_sec_num = dynamic_section_acc.get_entries_num(); + for ( Elf_Xword i = 0; i < dyn_sec_num; ++i ) { + Elf_Xword tag; + Elf_Xword value; + std::string str; + + if ( dynamic_section_acc.get_entry( i, tag, value, str ) && + tag == DT_VERDEFNUM ) { + entries_num = (Elf_Word)value; + break; + } + } + } + + //------------------------------------------------------------------------------ + //! \brief Get the number of entries + //! \return Number of entries + Elf_Word get_entries_num() const { return entries_num; } + + //------------------------------------------------------------------------------ + //! \brief Get an entry + //! \param no Index of the entry + //! \param flags Flags of the entry + //! \param version_index Version index of the entry + //! \param hash Hash of the entry + //! \param dep_name Dependency name of the entry + //! \return True if successful, false otherwise + bool get_entry( Elf_Word no, + Elf_Half& flags, + Elf_Half& version_index, + Elf_Word& hash, + std::string& dep_name ) const + { + if ( versym_d_section == nullptr || ( no >= get_entries_num() ) ) { + return false; + } + + const_string_section_accessor string_section_acc( + elf_file.sections[versym_d_section->get_link()] ); + + Elfxx_Verdef* verdef = (Elfxx_Verdef*)versym_d_section->get_data(); + Elfxx_Verdaux* verdaux = + (Elfxx_Verdaux*)( (char*)verdef + verdef->vd_aux ); + for ( Elf_Word i = 0; i < no; ++i ) { + verdef = (Elfxx_Verdef*)( (char*)verdef + verdef->vd_next ); + verdaux = (Elfxx_Verdaux*)( (char*)verdef + verdef->vd_aux ); + } + + // verdef->vd_version should always be 1 + // see https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA.junk/symversion.html#VERDEFENTRIES + // verdef->vd_cnt should always be 1. + // see https://maskray.me/blog/2020-11-26-all-about-symbol-versioning + + flags = verdef->vd_flags; + version_index = verdef->vd_ndx; + hash = verdef->vd_hash; + dep_name = string_section_acc.get_string( verdaux->vda_name ); + + return true; + } + + //------------------------------------------------------------------------------ + private: + const elfio& elf_file; + S* versym_d_section = + nullptr; //!< Pointer to the version definition section + Elf_Word entries_num = 0; //!< Number of entries +}; + +using versym_d_section_accessor = versym_d_section_accessor_template
; +using const_versym_d_section_accessor = + versym_d_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_VERSYM_HPP diff --git a/emulator/include/foot-emulator.h b/emulator/include/foot-emulator.h index 3d57f03..cc4a2ce 100644 --- a/emulator/include/foot-emulator.h +++ b/emulator/include/foot-emulator.h @@ -47,20 +47,24 @@ class Emulator public: static constexpr uint8_t PC = 31; static constexpr uint8_t LC = 30; + static constexpr uint8_t RA = 29; + static constexpr uint8_t SP = 28; Emulator(); void run(const std::vector& program); + void run(std::istream& program); + void map_device(std::unique_ptr&& device); - uint32_t& memory_at(uint16_t address); + uint32_t& memory_at(uint32_t address); uint32_t& decode_operand(Operand operand); uint32_t& register_at(uint8_t index); void run_instruction(); private: - std::array memory; + std::array memory; std::array registers; enum class Status { @@ -72,9 +76,10 @@ private: uint32_t configuration; uint32_t dummy_value; std::vector> devices; - uint16_t mapped_base; + uint32_t mapped_base; bool keep_running; + void run_internal(); void read_instruction(); void CNST(); @@ -86,6 +91,7 @@ private: void BWOR(); void BAND(); void BXOR(); + void ZRSH(); void SRSH(); void ZLSH(); void CLSH(); @@ -95,6 +101,7 @@ private: void DIVI(); void MODU(); + bool should_run() const; bool repeats() const; uint8_t simd_elements() const; uint8_t shift() const; @@ -104,6 +111,7 @@ private: uint32_t op_arithmetic_negate(uint32_t a) const; uint32_t op_logical_negate(uint32_t a) const; + uint32_t op_pad_zero_right_shift(uint32_t a, uint32_t b) const; uint32_t op_signed_right_shift(uint32_t a, uint32_t b) const; uint32_t op_pad_zero_left_shift(uint32_t a, uint32_t b) const; uint32_t op_circular_left_shift(uint32_t a, uint32_t b) const; diff --git a/emulator/src/foot-emulator.cpp b/emulator/src/foot-emulator.cpp index 6edd161..145f9d3 100644 --- a/emulator/src/foot-emulator.cpp +++ b/emulator/src/foot-emulator.cpp @@ -2,6 +2,8 @@ #include +#include + namespace foot { @@ -28,36 +30,52 @@ Emulator::Emulator() : memory{}, registers{}, configuration(0), - mapped_base(0) -{} + mapped_base(0x00010000) +{ + registers[SP] = 0xFFFF; // stack pointer +} void Emulator::run(const std::vector& program) { std::copy(program.begin(), program.end(), memory.begin()); - keep_running = true; - while (keep_running) + run_internal(); +} + +void Emulator::run(std::istream& program) +{ + ELFIO::elfio reader; + reader.load(program); + + for (const auto& seg : reader.segments) { - run_instruction(); - for (auto& device : devices) + + uint64_t dest = seg->get_virtual_address(); + uint64_t msize = seg->get_memory_size(); + uint64_t fsize = seg->get_file_size(); + const char* data = seg->get_data(); + + if (seg->get_type() != ELFIO::PT_LOAD) { - if (device->update()) - { - keep_running = false; - } + continue; } + + memcpy(reinterpret_cast(memory.data()) + dest, data, fsize); } + + registers[PC] = reader.get_entry() / 4; + + run_internal(); } void Emulator::map_device(std::unique_ptr&& device) { - mapped_base -= device->mapped_memory_size(); device->assigned_memory_base = &memory[mapped_base]; - + mapped_base += device->mapped_memory_size(); devices.push_back(std::move(device)); } -uint32_t& Emulator::memory_at(uint16_t address) +uint32_t& Emulator::memory_at(uint32_t address) { return memory[address]; } @@ -77,7 +95,7 @@ uint32_t& Emulator::decode_operand(Operand operand) return memory[registers[operand.register_index]++]; case Operand::AddressingMode::Indirect: - return memory[registers[operand.register_index]]; + return memory[registers[operand.register_index]]; default: return dummy_value; @@ -93,6 +111,11 @@ void Emulator::run_instruction() { read_instruction(); + if (!should_run()) + { + return; + } + const bool rep = repeats(); const uint32_t loop_count = rep ? registers[LC] : 1; @@ -143,6 +166,10 @@ void Emulator::run_instruction() BXOR(); break; + case 5: + ZRSH(); + break; + case 6: SRSH(); break; @@ -183,6 +210,22 @@ void Emulator::run_instruction() if (rep) { registers[LC] = loop_count; } } +void Emulator::run_internal() +{ + keep_running = true; + while (keep_running) + { + run_instruction(); + for (const auto& device : devices) + { + if (device->update()) + { + keep_running = false; + } + } + } +} + void Emulator::read_instruction() { instruction = memory[registers[PC]++]; @@ -272,6 +315,15 @@ void Emulator::BXOR() d = a ^ b; } +void Emulator::ZRSH() +{ + uint32_t a = decode_operand(instruction & 0x000000FF); + uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8); + uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16); + + d = apply_many_binary(a, b, &Emulator::op_pad_zero_right_shift); +} + void Emulator::SRSH() { uint32_t a = decode_operand(instruction & 0x000000FF); @@ -344,6 +396,36 @@ void Emulator::MODU() d = apply_many_binary(a, b, &Emulator::op_mod); } +bool Emulator::should_run() const +{ + switch ((instruction & 0xE0000000) >> 29) + { + case 0: + return true; + + case 1: + return status_register == Status::Less; + + case 2: + return status_register == Status::Less || status_register == Status::Equal; + + case 3: + return status_register == Status::Equal; + + case 4: + return status_register == Status::Greater || status_register == Status::Equal; + + case 5: + return status_register == Status::Greater; + + case 6: + return status_register == Status::Less || status_register == Status::Greater; + + default: + return false; + } +} + bool Emulator::repeats() const { return instruction & 0x10000000; @@ -404,6 +486,11 @@ uint32_t Emulator::op_logical_negate(uint32_t a) const return !a; } +uint32_t Emulator::op_pad_zero_right_shift(uint32_t a, uint32_t b) const +{ + return a >> b; +} + uint32_t Emulator::op_signed_right_shift(uint32_t a, uint32_t b) const { return int32_t(a) >> b; diff --git a/emulator/src/main.cpp b/emulator/src/main.cpp index d221f62..6faa957 100644 --- a/emulator/src/main.cpp +++ b/emulator/src/main.cpp @@ -8,26 +8,6 @@ namespace { -std::vector read_file(std::istream& stream) -{ - std::vector buf; - - std::streampos pos = stream.tellg(); - stream.seekg(0, std::ios::end); - pos = stream.tellg() - pos; - buf.resize(pos / 4); - stream.seekg(0, std::ios::beg); - - for (int i = 0; i < buf.size(); i++) - { - unsigned char value[4] = {}; - stream.read((char*)value, 4); - buf[i] = uint32_t(value[0]) | (uint32_t(value[1]) << 8) | (uint32_t(value[2]) << 16) | (uint32_t(value[3]) << 24); - } - - return buf; -} - class PrintDevice : public foot::Device { public: @@ -41,7 +21,7 @@ public: uint32_t& value = memory(0); if (value != 0) { - std::cout << char(value); + SDL_Log("%1s", (char*)&value); value = 0; } @@ -134,7 +114,7 @@ int main(int argc, char** argv) emu.map_device(std::make_unique()); emu.map_device(std::make_unique(render, WIDTH, HEIGHT)); - emu.run(read_file(file)); + emu.run(file); SDL_DestroyRenderer(render); SDL_DestroyWindow(window); diff --git a/emulator/tests/CMakeLists.txt b/emulator/tests/CMakeLists.txt index 7960f0b..d6e426b 100644 --- a/emulator/tests/CMakeLists.txt +++ b/emulator/tests/CMakeLists.txt @@ -15,6 +15,7 @@ test(long-instruction) test(bwor-instruction) test(band-instruction) test(bxor-instruction) +test(zrsh-instruction) test(srsh-instruction) test(zlsh-instruction) test(clsh-instruction) @@ -22,4 +23,4 @@ test(addi-instruction) test(subt-instruction) test(mult-instruction) test(divi-instruction) -test(modu-instruction) +test(modu-instruction) \ No newline at end of file diff --git a/emulator/tests/zrsh-instruction.cpp b/emulator/tests/zrsh-instruction.cpp new file mode 100644 index 0000000..b9ccb7b --- /dev/null +++ b/emulator/tests/zrsh-instruction.cpp @@ -0,0 +1,36 @@ +#include "test-common.h" + +int main(int argc, char** argv) +{ + // CNST + // dst - 0, Direct + // imm - 0x4567 + // + // ZRSH + // dst - 0, Direct + // a - 0, Direct + // b - 2, Immediate + { + foot::Emulator emu = run_instructions({ 0x00204567, 0x05200220 }); + if (!check(0x1159, emu.register_at(0))) { return 1; } + } + + // CNST + // dst - 0, Direct + // imm - 0x4343 + // + // CNST + // dst - 1, Direct + // imm - 0x1122 + // + // ZRSH - 4-bit SIMD + // dst - 0, Direct + // a - 0, Direct + // b - 1, Direct + { + foot::Emulator emu = run_instructions({ 0x00204343, 0x00211122, 0x05A021A0 }); + if (!check(0x2110, emu.register_at(0))) { return 1; } + } + + return 0; +}