/*
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.
*/


/*** Start of inlined file: elfio_dump.hpp ***/
#ifndef ELFIO_DUMP_HPP
#define ELFIO_DUMP_HPP

#include <algorithm>
#include <string>
#include <ostream>
#include <sstream>
#include <iomanip>

/*** Start of inlined file: elfio.hpp ***/
#ifndef ELFIO_HPP
#define ELFIO_HPP

#ifdef _MSC_VER
#pragma warning( push )
#pragma warning( disable : 4996 )
#pragma warning( disable : 4355 )
#pragma warning( disable : 4244 )
#endif

#include <string>
#include <iostream>
#include <fstream>
#include <functional>
#include <algorithm>
#include <vector>
#include <deque>
#include <iterator>


/*** Start of inlined file: elf_types.hpp ***/
#ifndef ELFTYPES_H
#define ELFTYPES_H

#ifndef ELFIO_NO_OWN_TYPES
#if !defined( ELFIO_NO_CSTDINT ) && !defined( ELFIO_NO_INTTYPES )
#include <stdint.h>
#else
typedef unsigned char    uint8_t;
typedef signed char      int8_t;
typedef unsigned short   uint16_t;
typedef signed short     int16_t;
#ifdef _MSC_VER
typedef unsigned __int32 uint32_t;
typedef signed __int32   int32_t;
typedef unsigned __int64 uint64_t;
typedef signed __int64   int64_t;
#else
typedef unsigned int       uint32_t;
typedef signed int         int32_t;
typedef unsigned long long uint64_t;
typedef signed long long   int64_t;
#endif // _MSC_VER
#endif // ELFIO_NO_CSTDINT
#endif // ELFIO_NO_OWN_TYPES

namespace ELFIO {

// Attention! Platform depended definitions.
typedef uint16_t Elf_Half;
typedef uint32_t Elf_Word;
typedef int32_t  Elf_Sword;
typedef uint64_t Elf_Xword;
typedef int64_t  Elf_Sxword;

typedef uint32_t Elf32_Addr;
typedef uint32_t Elf32_Off;
typedef uint64_t Elf64_Addr;
typedef uint64_t Elf64_Off;

#define Elf32_Half  Elf_Half
#define Elf64_Half  Elf_Half
#define Elf32_Word  Elf_Word
#define Elf64_Word  Elf_Word
#define Elf32_Sword Elf_Sword
#define Elf64_Sword Elf_Sword

///////////////////////
// ELF Header Constants

// File type
#define ET_NONE   0
#define ET_REL    1
#define ET_EXEC   2
#define ET_DYN    3
#define ET_CORE   4
#define ET_LOOS   0xFE00
#define ET_HIOS   0xFEFF
#define ET_LOPROC 0xFF00
#define ET_HIPROC 0xFFFF

#define EM_NONE  0 // No machine
#define EM_M32   1 // AT&T WE 32100
#define EM_SPARC 2 // SUN SPARC
#define EM_386   3 // Intel 80386
#define EM_68K   4 // Motorola m68k family
#define EM_88K   5 // Motorola m88k family
#define EM_486   6 // Intel 80486// Reserved for future use
#define EM_860   7 // Intel 80860
#define EM_MIPS  8 // MIPS R3000 (officially, big-endian only)
#define EM_S370  9 // IBM System/370
#define EM_MIPS_RS3_LE \
	10 // MIPS R3000 little-endian (Oct 4 1999 Draft) Deprecated
#define EM_res011      11 // Reserved
#define EM_res012      12 // Reserved
#define EM_res013      13 // Reserved
#define EM_res014      14 // Reserved
#define EM_PARISC      15 // HPPA
#define EM_res016      16 // Reserved
#define EM_VPP550      17 // Fujitsu VPP500
#define EM_SPARC32PLUS 18 // Sun's "v8plus"
#define EM_960         19 // Intel 80960
#define EM_PPC         20 // PowerPC
#define EM_PPC64       21 // 64-bit PowerPC
#define EM_S390        22 // IBM S/390
#define EM_SPU         23 // Sony/Toshiba/IBM SPU
#define EM_res024      24 // Reserved
#define EM_res025      25 // Reserved
#define EM_res026      26 // Reserved
#define EM_res027      27 // Reserved
#define EM_res028      28 // Reserved
#define EM_res029      29 // Reserved
#define EM_res030      30 // Reserved
#define EM_res031      31 // Reserved
#define EM_res032      32 // Reserved
#define EM_res033      33 // Reserved
#define EM_res034      34 // Reserved
#define EM_res035      35 // Reserved
#define EM_V800        36 // NEC V800 series
#define EM_FR20        37 // Fujitsu FR20
#define EM_RH32        38 // TRW RH32
#define EM_MCORE       39 // Motorola M*Core // May also be taken by Fujitsu MMA
#define EM_RCE         39 // Old name for MCore
#define EM_ARM         40 // ARM
#define EM_OLD_ALPHA   41 // Digital Alpha
#define EM_SH          42 // Renesas (formerly Hitachi) / SuperH SH
#define EM_SPARCV9     43 // SPARC v9 64-bit
#define EM_TRICORE     44 // Siemens Tricore embedded processor
#define EM_ARC         45 // ARC Cores
#define EM_H8_300      46 // Renesas (formerly Hitachi) H8/300
#define EM_H8_300H     47 // Renesas (formerly Hitachi) H8/300H
#define EM_H8S         48 // Renesas (formerly Hitachi) H8S
#define EM_H8_500      49 // Renesas (formerly Hitachi) H8/500
#define EM_IA_64       50 // Intel IA-64 Processor
#define EM_MIPS_X      51 // Stanford MIPS-X
#define EM_COLDFIRE    52 // Motorola Coldfire
#define EM_68HC12      53 // Motorola M68HC12
#define EM_MMA         54 // Fujitsu Multimedia Accelerator
#define EM_PCP         55 // Siemens PCP
#define EM_NCPU        56 // Sony nCPU embedded RISC processor
#define EM_NDR1        57 // Denso NDR1 microprocesspr
#define EM_STARCORE    58 // Motorola Star*Core processor
#define EM_ME16        59 // Toyota ME16 processor
#define EM_ST100       60 // STMicroelectronics ST100 processor
#define EM_TINYJ       61 // Advanced Logic Corp. TinyJ embedded processor
#define EM_X86_64      62 // Advanced Micro Devices X86-64 processor
#define EM_PDSP        63 // Sony DSP Processor
#define EM_PDP10       64 // Digital Equipment Corp. PDP-10
#define EM_PDP11       65 // Digital Equipment Corp. PDP-11
#define EM_FX66        66 // Siemens FX66 microcontroller
#define EM_ST9PLUS     67 // STMicroelectronics ST9+ 8/16 bit microcontroller
#define EM_ST7         68 // STMicroelectronics ST7 8-bit microcontroller
#define EM_68HC16      69 // Motorola MC68HC16 Microcontroller
#define EM_68HC11      70 // Motorola MC68HC11 Microcontroller
#define EM_68HC08      71 // Motorola MC68HC08 Microcontroller
#define EM_68HC05      72 // Motorola MC68HC05 Microcontroller
#define EM_SVX         73 // Silicon Graphics SVx
#define EM_ST19        74 // STMicroelectronics ST19 8-bit cpu
#define EM_VAX         75 // Digital VAX
#define EM_CRIS        76 // Axis Communications 32-bit embedded processor
#define EM_JAVELIN     77 // Infineon Technologies 32-bit embedded cpu
#define EM_FIREPATH    78 // Element 14 64-bit DSP processor
#define EM_ZSP         79 // LSI Logic's 16-bit DSP processor
#define EM_MMIX        80 // Donald Knuth's educational 64-bit processor
#define EM_HUANY       81 // Harvard's machine-independent format
#define EM_PRISM       82 // SiTera Prism
#define EM_AVR         83 // Atmel AVR 8-bit microcontroller
#define EM_FR30        84 // Fujitsu FR30
#define EM_D10V        85 // Mitsubishi D10V
#define EM_D30V        86 // Mitsubishi D30V
#define EM_V850        87 // NEC v850
#define EM_M32R        88 // Renesas M32R (formerly Mitsubishi M32R)
#define EM_MN10300     89 // Matsushita MN10300
#define EM_MN10200     90 // Matsushita MN10200
#define EM_PJ          91 // picoJava
#define EM_OPENRISC    92 // OpenRISC 32-bit embedded processor
#define EM_ARC_A5      93 // ARC Cores Tangent-A5
#define EM_XTENSA      94 // Tensilica Xtensa Architecture
#define EM_VIDEOCORE   95 // Alphamosaic VideoCore processor
#define EM_TMM_GPP     96 // Thompson Multimedia General Purpose Processor
#define EM_NS32K       97 // National Semiconductor 32000 series
#define EM_TPC         98 // Tenor Network TPC processor
#define EM_SNP1K       99 // Trebia SNP 1000 processor
#define EM_ST200       100 // STMicroelectronics ST200 microcontroller
#define EM_IP2K        101 // Ubicom IP2022 micro controller
#define EM_MAX         102 // MAX Processor
#define EM_CR          103 // National Semiconductor CompactRISC
#define EM_F2MC16      104 // Fujitsu F2MC16
#define EM_MSP430      105 // TI msp430 micro controller
#define EM_BLACKFIN    106 // ADI Blackfin
#define EM_SE_C33      107 // S1C33 Family of Seiko Epson processors
#define EM_SEP         108 // Sharp embedded microprocessor
#define EM_ARCA        109 // Arca RISC Microprocessor
#define EM_UNICORE \
	110 // Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University
#define EM_EXCESS       111 // eXcess: 16/32/64-bit configurable embedded CPU
#define EM_DXP          112 // Icera Semiconductor Inc. Deep Execution Processor
#define EM_ALTERA_NIOS2 113 // Altera Nios II soft-core processor
#define EM_CRX          114 // National Semiconductor CRX
#define EM_XGATE        115 // Motorola XGATE embedded processor
#define EM_C166         116 // Infineon C16x/XC16x processor
#define EM_M16C         117 // Renesas M16C series microprocessors
#define EM_DSPIC30F \
	118 // Microchip Technology dsPIC30F Digital Signal Controller
#define EM_CE            119 // Freescale Communication Engine RISC core
#define EM_M32C          120 // Renesas M32C series microprocessors
#define EM_res121        121 // Reserved
#define EM_res122        122 // Reserved
#define EM_res123        123 // Reserved
#define EM_res124        124 // Reserved
#define EM_res125        125 // Reserved
#define EM_res126        126 // Reserved
#define EM_res127        127 // Reserved
#define EM_res128        128 // Reserved
#define EM_res129        129 // Reserved
#define EM_res130        130 // Reserved
#define EM_TSK3000       131 // Altium TSK3000 core
#define EM_RS08          132 // Freescale RS08 embedded processor
#define EM_res133        133 // Reserved
#define EM_ECOG2         134 // Cyan Technology eCOG2 microprocessor
#define EM_SCORE         135 // Sunplus Score
#define EM_SCORE7        135 // Sunplus S+core7 RISC processor
#define EM_DSP24         136 // New Japan Radio (NJR) 24-bit DSP Processor
#define EM_VIDEOCORE3    137 // Broadcom VideoCore III processor
#define EM_LATTICEMICO32 138 // RISC processor for Lattice FPGA architecture
#define EM_SE_C17        139 // Seiko Epson C17 family
#define EM_TI_C6000      140 // Texas Instruments TMS320C6000 DSP family
#define EM_TI_C2000      141 // Texas Instruments TMS320C2000 DSP family
#define EM_TI_C5500      142 // Texas Instruments TMS320C55x DSP family
#define EM_res143        143 // Reserved
#define EM_res144        144 // Reserved
#define EM_res145        145 // Reserved
#define EM_res146        146 // Reserved
#define EM_res147        147 // Reserved
#define EM_res148        148 // Reserved
#define EM_res149        149 // Reserved
#define EM_res150        150 // Reserved
#define EM_res151        151 // Reserved
#define EM_res152        152 // Reserved
#define EM_res153        153 // Reserved
#define EM_res154        154 // Reserved
#define EM_res155        155 // Reserved
#define EM_res156        156 // Reserved
#define EM_res157        157 // Reserved
#define EM_res158        158 // Reserved
#define EM_res159        159 // Reserved
#define EM_MMDSP_PLUS    160 // STMicroelectronics 64bit VLIW Data Signal Processor
#define EM_CYPRESS_M8C   161 // Cypress M8C microprocessor
#define EM_R32C          162 // Renesas R32C series microprocessors
#define EM_TRIMEDIA      163 // NXP Semiconductors TriMedia architecture family
#define EM_QDSP6         164 // QUALCOMM DSP6 Processor
#define EM_8051          165 // Intel 8051 and variants
#define EM_STXP7X        166 // STMicroelectronics STxP7x family
#define EM_NDS32 \
	167 // Andes Technology compact code size embedded RISC processor family
#define EM_ECOG1         168 // Cyan Technology eCOG1X family
#define EM_ECOG1X        168 // Cyan Technology eCOG1X family
#define EM_MAXQ30        169 // Dallas Semiconductor MAXQ30 Core Micro-controllers
#define EM_XIMO16        170 // New Japan Radio (NJR) 16-bit DSP Processor
#define EM_MANIK         171 // M2000 Reconfigurable RISC Microprocessor
#define EM_CRAYNV2       172 // Cray Inc. NV2 vector architecture
#define EM_RX            173 // Renesas RX family
#define EM_METAG         174 // Imagination Technologies META processor architecture
#define EM_MCST_ELBRUS   175 // MCST Elbrus general purpose hardware architecture
#define EM_ECOG16        176 // Cyan Technology eCOG16 family
#define EM_CR16          177 // National Semiconductor CompactRISC 16-bit processor
#define EM_ETPU          178 // Freescale Extended Time Processing Unit
#define EM_SLE9X         179 // Infineon Technologies SLE9X core
#define EM_L1OM          180 // Intel L1OM
#define EM_INTEL181      181 // Reserved by Intel
#define EM_INTEL182      182 // Reserved by Intel
#define EM_res183        183 // Reserved by ARM
#define EM_res184        184 // Reserved by ARM
#define EM_AVR32         185 // Atmel Corporation 32-bit microprocessor family
#define EM_STM8          186 // STMicroeletronics STM8 8-bit microcontroller
#define EM_TILE64        187 // Tilera TILE64 multicore architecture family
#define EM_TILEPRO       188 // Tilera TILEPro multicore architecture family
#define EM_MICROBLAZE    189 // Xilinx MicroBlaze 32-bit RISC soft processor core
#define EM_CUDA          190 // NVIDIA CUDA architecture
#define EM_TILEGX        191 // Tilera TILE-Gx multicore architecture family
#define EM_CLOUDSHIELD   192 // CloudShield architecture family
#define EM_COREA_1ST     193 // KIPO-KAIST Core-A 1st generation processor family
#define EM_COREA_2ND     194 // KIPO-KAIST Core-A 2nd generation processor family
#define EM_ARC_COMPACT2  195 // Synopsys ARCompact V2
#define EM_OPEN8         196 // Open8 8-bit RISC soft processor core
#define EM_RL78          197 // Renesas RL78 family
#define EM_VIDEOCORE5    198 // Broadcom VideoCore V processor
#define EM_78KOR         199 // Renesas 78KOR family
#define EM_56800EX       200 // Freescale 56800EX Digital Signal Controller (DSC)
#define EM_BA1           201 // Beyond BA1 CPU architecture
#define EM_BA2           202 // Beyond BA2 CPU architecture
#define EM_XCORE         203 // XMOS xCORE processor family
#define EM_MCHP_PIC      204 // Microchip 8-bit PIC(r) family
#define EM_INTEL205      205 // Reserved by Intel
#define EM_INTEL206      206 // Reserved by Intel
#define EM_INTEL207      207 // Reserved by Intel
#define EM_INTEL208      208 // Reserved by Intel
#define EM_INTEL209      209 // Reserved by Intel
#define EM_KM32          210 // KM211 KM32 32-bit processor
#define EM_KMX32         211 // KM211 KMX32 32-bit processor
#define EM_KMX16         212 // KM211 KMX16 16-bit processor
#define EM_KMX8          213 // KM211 KMX8 8-bit processor
#define EM_KVARC         214 // KM211 KVARC processor
#define EM_CDP           215 // Paneve CDP architecture family
#define EM_COGE          216 // Cognitive Smart Memory Processor
#define EM_COOL          217 // iCelero CoolEngine
#define EM_NORC          218 // Nanoradio Optimized RISC
#define EM_CSR_KALIMBA   219 // CSR Kalimba architecture family
#define EM_Z80           220 // Zilog Z80
#define EM_VISIUM        221 // Controls and Data Services VISIUMcore processor
#define EM_FT32          222 // FTDI Chip FT32 high performance 32-bit RISC architecture
#define EM_MOXIE         223 // Moxie processor family
#define EM_AMDGPU        224 // AMD GPU architecture
#define EM_RISCV         243 // RISC-V
#define EM_LANAI         244 // Lanai processor
#define EM_CEVA          245 // CEVA Processor Architecture Family
#define EM_CEVA_X2       246 // CEVA X2 Processor Family
#define EM_BPF           247 // Linux BPF – in-kernel virtual machine
#define EM_GRAPHCORE_IPU 248 // Graphcore Intelligent Processing Unit
#define EM_IMG1          249 // Imagination Technologies
#define EM_NFP           250 // Netronome Flow Processor (P)
#define EM_CSKY          252 // C-SKY processor family

// File version
#define EV_NONE    0
#define EV_CURRENT 1

// Identification index
#define EI_MAG0       0
#define EI_MAG1       1
#define EI_MAG2       2
#define EI_MAG3       3
#define EI_CLASS      4
#define EI_DATA       5
#define EI_VERSION    6
#define EI_OSABI      7
#define EI_ABIVERSION 8
#define EI_PAD        9
#define EI_NIDENT     16

// Magic number
#define ELFMAG0 0x7F
#define ELFMAG1 'E'
#define ELFMAG2 'L'
#define ELFMAG3 'F'

// File class
#define ELFCLASSNONE 0
#define ELFCLASS32   1
#define ELFCLASS64   2

// Encoding
#define ELFDATANONE 0
#define ELFDATA2LSB 1
#define ELFDATA2MSB 2

// OS extensions
#define ELFOSABI_NONE    0  // No extensions or unspecified
#define ELFOSABI_HPUX    1  // Hewlett-Packard HP-UX
#define ELFOSABI_NETBSD  2  // NetBSD
#define ELFOSABI_LINUX   3  // Linux
#define ELFOSABI_SOLARIS 6  // Sun Solaris
#define ELFOSABI_AIX     7  // AIX
#define ELFOSABI_IRIX    8  // IRIX
#define ELFOSABI_FREEBSD 9  // FreeBSD
#define ELFOSABI_TRU64   10 // Compaq TRU64 UNIX
#define ELFOSABI_MODESTO 11 // Novell Modesto
#define ELFOSABI_OPENBSD 12 // Open BSD
#define ELFOSABI_OPENVMS 13 // Open VMS
#define ELFOSABI_NSK     14 // Hewlett-Packard Non-Stop Kernel
#define ELFOSABI_AROS    15 // Amiga Research OS
#define ELFOSABI_FENIXOS 16 // The FenixOS highly scalable multi-core OS
//                             64-255 Architecture-specific value range
#define ELFOSABI_AMDGPU_HSA \
	64 // AMDGPU OS for HSA compatible compute 	// kernels.
#define ELFOSABI_AMDGPU_PAL \
	65 // AMDGPU OS for AMD PAL compatible graphics  // shaders and compute kernels.
#define ELFOSABI_AMDGPU_MESA3D \
	66 // AMDGPU OS for Mesa3D compatible graphics 	// shaders and compute kernels.

// AMDGPU specific e_flags
#define EF_AMDGPU_MACH 0x0ff // AMDGPU processor selection mask.
#define EF_AMDGPU_XNACK \
	0x100 // Indicates if the XNACK target feature is   // enabled for all code contained in the ELF.
// AMDGPU processors
#define EF_AMDGPU_MACH_NONE                0x000 // Unspecified processor.
#define EF_AMDGPU_MACH_R600_R600           0x001
#define EF_AMDGPU_MACH_R600_R630           0x002
#define EF_AMDGPU_MACH_R600_RS880          0x003
#define EF_AMDGPU_MACH_R600_RV670          0x004
#define EF_AMDGPU_MACH_R600_RV710          0x005
#define EF_AMDGPU_MACH_R600_RV730          0x006
#define EF_AMDGPU_MACH_R600_RV770          0x007
#define EF_AMDGPU_MACH_R600_CEDAR          0x008
#define EF_AMDGPU_MACH_R600_CYPRESS        0x009
#define EF_AMDGPU_MACH_R600_JUNIPER        0x00a
#define EF_AMDGPU_MACH_R600_REDWOOD        0x00b
#define EF_AMDGPU_MACH_R600_SUMO           0x00c
#define EF_AMDGPU_MACH_R600_BARTS          0x00d
#define EF_AMDGPU_MACH_R600_CAICOS         0x00e
#define EF_AMDGPU_MACH_R600_CAYMAN         0x00f
#define EF_AMDGPU_MACH_R600_TURKS          0x010
#define EF_AMDGPU_MACH_R600_RESERVED_FIRST 0x011
#define EF_AMDGPU_MACH_R600_RESERVED_LAST  0x01f
#define EF_AMDGPU_MACH_R600_FIRST          EF_AMDGPU_MACH_R600_R600
#define EF_AMDGPU_MACH_R600_LAST           EF_AMDGPU_MACH_R600_TURKS
#define EF_AMDGPU_MACH_AMDGCN_GFX600       0x020
#define EF_AMDGPU_MACH_AMDGCN_GFX601       0x021
#define EF_AMDGPU_MACH_AMDGCN_GFX700       0x022
#define EF_AMDGPU_MACH_AMDGCN_GFX701       0x023
#define EF_AMDGPU_MACH_AMDGCN_GFX702       0x024
#define EF_AMDGPU_MACH_AMDGCN_GFX703       0x025
#define EF_AMDGPU_MACH_AMDGCN_GFX704       0x026
#define EF_AMDGPU_MACH_AMDGCN_GFX801       0x028
#define EF_AMDGPU_MACH_AMDGCN_GFX802       0x029
#define EF_AMDGPU_MACH_AMDGCN_GFX803       0x02a
#define EF_AMDGPU_MACH_AMDGCN_GFX810       0x02b
#define EF_AMDGPU_MACH_AMDGCN_GFX900       0x02c
#define EF_AMDGPU_MACH_AMDGCN_GFX902       0x02d
#define EF_AMDGPU_MACH_AMDGCN_GFX904       0x02e
#define EF_AMDGPU_MACH_AMDGCN_GFX906       0x02f
#define EF_AMDGPU_MACH_AMDGCN_RESERVED0    0x027
#define EF_AMDGPU_MACH_AMDGCN_RESERVED1    0x030
#define EF_AMDGPU_MACH_AMDGCN_FIRST        EF_AMDGPU_MACH_AMDGCN_GFX600
#define EF_AMDGPU_MACH_AMDGCN_LAST         EF_AMDGPU_MACH_AMDGCN_GFX906

/////////////////////
// Sections constants

// Section indexes
#define SHN_UNDEF     0
#define SHN_LORESERVE 0xFF00
#define SHN_LOPROC    0xFF00
#define SHN_HIPROC    0xFF1F
#define SHN_LOOS      0xFF20
#define SHN_HIOS      0xFF3F
#define SHN_ABS       0xFFF1
#define SHN_COMMON    0xFFF2
#define SHN_XINDEX    0xFFFF
#define SHN_HIRESERVE 0xFFFF

// Section types
#define SHT_NULL          0
#define SHT_PROGBITS      1
#define SHT_SYMTAB        2
#define SHT_STRTAB        3
#define SHT_RELA          4
#define SHT_HASH          5
#define SHT_DYNAMIC       6
#define SHT_NOTE          7
#define SHT_NOBITS        8
#define SHT_REL           9
#define SHT_SHLIB         10
#define SHT_DYNSYM        11
#define SHT_INIT_ARRAY    14
#define SHT_FINI_ARRAY    15
#define SHT_PREINIT_ARRAY 16
#define SHT_GROUP         17
#define SHT_SYMTAB_SHNDX  18
#define SHT_LOOS          0x60000000
#define SHT_HIOS          0x6fffffff
#define SHT_LOPROC        0x70000000
#define SHT_HIPROC        0x7FFFFFFF
#define SHT_LOUSER        0x80000000
#define SHT_HIUSER        0xFFFFFFFF

// Section attribute flags
#define SHF_WRITE            0x1
#define SHF_ALLOC            0x2
#define SHF_EXECINSTR        0x4
#define SHF_MERGE            0x10
#define SHF_STRINGS          0x20
#define SHF_INFO_LINK        0x40
#define SHF_LINK_ORDER       0x80
#define SHF_OS_NONCONFORMING 0x100
#define SHF_GROUP            0x200
#define SHF_TLS              0x400
#define SHF_MASKOS           0x0ff00000
#define SHF_MASKPROC         0xF0000000

// Section group flags
#define GRP_COMDAT   0x1
#define GRP_MASKOS   0x0ff00000
#define GRP_MASKPROC 0xf0000000

// Symbol binding
#define STB_LOCAL    0
#define STB_GLOBAL   1
#define STB_WEAK     2
#define STB_LOOS     10
#define STB_HIOS     12
#define STB_MULTIDEF 13
#define STB_LOPROC   13
#define STB_HIPROC   15

// Note types
#define NT_AMDGPU_METADATA         1
#define NT_AMD_AMDGPU_HSA_METADATA 10
#define NT_AMD_AMDGPU_ISA          11
#define NT_AMD_AMDGPU_PAL_METADATA 12

// Symbol types
#define STT_NOTYPE            0
#define STT_OBJECT            1
#define STT_FUNC              2
#define STT_SECTION           3
#define STT_FILE              4
#define STT_COMMON            5
#define STT_TLS               6
#define STT_LOOS              10
#define STT_AMDGPU_HSA_KERNEL 10
#define STT_HIOS              12
#define STT_LOPROC            13
#define STT_HIPROC            15

// Symbol visibility
#define STV_DEFAULT   0
#define STV_INTERNAL  1
#define STV_HIDDEN    2
#define STV_PROTECTED 3

// Undefined name
#define STN_UNDEF 0

// Relocation types
#define R_386_NONE               0
#define R_X86_64_NONE            0
#define R_AMDGPU_NONE            0
#define R_386_32                 1
#define R_X86_64_64              1
#define R_AMDGPU_ABS32_LO        1
#define R_386_PC32               2
#define R_X86_64_PC32            2
#define R_AMDGPU_ABS32_HI        2
#define R_386_GOT32              3
#define R_X86_64_GOT32           3
#define R_AMDGPU_ABS64           3
#define R_386_PLT32              4
#define R_X86_64_PLT32           4
#define R_AMDGPU_REL32           4
#define R_386_COPY               5
#define R_X86_64_COPY            5
#define R_AMDGPU_REL64           5
#define R_386_GLOB_DAT           6
#define R_X86_64_GLOB_DAT        6
#define R_AMDGPU_ABS32           6
#define R_386_JMP_SLOT           7
#define R_X86_64_JUMP_SLOT       7
#define R_AMDGPU_GOTPCREL        7
#define R_386_RELATIVE           8
#define R_X86_64_RELATIVE        8
#define R_AMDGPU_GOTPCREL32_LO   8
#define R_386_GOTOFF             9
#define R_X86_64_GOTPCREL        9
#define R_AMDGPU_GOTPCREL32_HI   9
#define R_386_GOTPC              10
#define R_X86_64_32              10
#define R_AMDGPU_REL32_LO        10
#define R_386_32PLT              11
#define R_X86_64_32S             11
#define R_AMDGPU_REL32_HI        11
#define R_X86_64_16              12
#define R_X86_64_PC16            13
#define R_AMDGPU_RELATIVE64      13
#define R_386_TLS_TPOFF          14
#define R_X86_64_8               14
#define R_386_TLS_IE             15
#define R_X86_64_PC8             15
#define R_386_TLS_GOTIE          16
#define R_X86_64_DTPMOD64        16
#define R_386_TLS_LE             17
#define R_X86_64_DTPOFF64        17
#define R_386_TLS_GD             18
#define R_X86_64_TPOFF64         18
#define R_386_TLS_LDM            19
#define R_X86_64_TLSGD           19
#define R_386_16                 20
#define R_X86_64_TLSLD           20
#define R_386_PC16               21
#define R_X86_64_DTPOFF32        21
#define R_386_8                  22
#define R_X86_64_GOTTPOFF        22
#define R_386_PC8                23
#define R_X86_64_TPOFF32         23
#define R_386_TLS_GD_32          24
#define R_X86_64_PC64            24
#define R_386_TLS_GD_PUSH        25
#define R_X86_64_GOTOFF64        25
#define R_386_TLS_GD_CALL        26
#define R_X86_64_GOTPC32         26
#define R_386_TLS_GD_POP         27
#define R_X86_64_GOT64           27
#define R_386_TLS_LDM_32         28
#define R_X86_64_GOTPCREL64      28
#define R_386_TLS_LDM_PUSH       29
#define R_X86_64_GOTPC64         29
#define R_386_TLS_LDM_CALL       30
#define R_X86_64_GOTPLT64        30
#define R_386_TLS_LDM_POP        31
#define R_X86_64_PLTOFF64        31
#define R_386_TLS_LDO_32         32
#define R_386_TLS_IE_32          33
#define R_386_TLS_LE_32          34
#define R_X86_64_GOTPC32_TLSDESC 34
#define R_386_TLS_DTPMOD32       35
#define R_X86_64_TLSDESC_CALL    35
#define R_386_TLS_DTPOFF32       36
#define R_X86_64_TLSDESC         36
#define R_386_TLS_TPOFF32        37
#define R_X86_64_IRELATIVE       37
#define R_386_SIZE32             38
#define R_386_TLS_GOTDESC        39
#define R_386_TLS_DESC_CALL      40
#define R_386_TLS_DESC           41
#define R_386_IRELATIVE          42
#define R_386_GOT32X             43
#define R_X86_64_GNU_VTINHERIT   250
#define R_X86_64_GNU_VTENTRY     251

// Segment types
#define PT_NULL    0
#define PT_LOAD    1
#define PT_DYNAMIC 2
#define PT_INTERP  3
#define PT_NOTE    4
#define PT_SHLIB   5
#define PT_PHDR    6
#define PT_TLS     7
#define PT_LOOS    0x60000000
#define PT_HIOS    0x6fffffff
#define PT_LOPROC  0x70000000
#define PT_HIPROC  0x7FFFFFFF

// Segment flags
#define PF_X        1          // Execute
#define PF_W        2          // Write
#define PF_R        4          // Read
#define PF_MASKOS   0x0ff00000 // Unspecified
#define PF_MASKPROC 0xf0000000 // Unspecified

// Dynamic Array Tags
#define DT_NULL            0
#define DT_NEEDED          1
#define DT_PLTRELSZ        2
#define DT_PLTGOT          3
#define DT_HASH            4
#define DT_STRTAB          5
#define DT_SYMTAB          6
#define DT_RELA            7
#define DT_RELASZ          8
#define DT_RELAENT         9
#define DT_STRSZ           10
#define DT_SYMENT          11
#define DT_INIT            12
#define DT_FINI            13
#define DT_SONAME          14
#define DT_RPATH           15
#define DT_SYMBOLIC        16
#define DT_REL             17
#define DT_RELSZ           18
#define DT_RELENT          19
#define DT_PLTREL          20
#define DT_DEBUG           21
#define DT_TEXTREL         22
#define DT_JMPREL          23
#define DT_BIND_NOW        24
#define DT_INIT_ARRAY      25
#define DT_FINI_ARRAY      26
#define DT_INIT_ARRAYSZ    27
#define DT_FINI_ARRAYSZ    28
#define DT_RUNPATH         29
#define DT_FLAGS           30
#define DT_ENCODING        32
#define DT_PREINIT_ARRAY   32
#define DT_PREINIT_ARRAYSZ 33
#define DT_MAXPOSTAGS      34
#define DT_LOOS            0x6000000D
#define DT_HIOS            0x6ffff000
#define DT_LOPROC          0x70000000
#define DT_HIPROC          0x7FFFFFFF

// DT_FLAGS values
#define DF_ORIGIN     0x1
#define DF_SYMBOLIC   0x2
#define DF_TEXTREL    0x4
#define DF_BIND_NOW   0x8
#define DF_STATIC_TLS 0x10

// ELF file header
struct Elf32_Ehdr
{
	unsigned char e_ident[EI_NIDENT];
	Elf_Half      e_type;
	Elf_Half      e_machine;
	Elf_Word      e_version;
	Elf32_Addr    e_entry;
	Elf32_Off     e_phoff;
	Elf32_Off     e_shoff;
	Elf_Word      e_flags;
	Elf_Half      e_ehsize;
	Elf_Half      e_phentsize;
	Elf_Half      e_phnum;
	Elf_Half      e_shentsize;
	Elf_Half      e_shnum;
	Elf_Half      e_shstrndx;
};

struct Elf64_Ehdr
{
	unsigned char e_ident[EI_NIDENT];
	Elf_Half      e_type;
	Elf_Half      e_machine;
	Elf_Word      e_version;
	Elf64_Addr    e_entry;
	Elf64_Off     e_phoff;
	Elf64_Off     e_shoff;
	Elf_Word      e_flags;
	Elf_Half      e_ehsize;
	Elf_Half      e_phentsize;
	Elf_Half      e_phnum;
	Elf_Half      e_shentsize;
	Elf_Half      e_shnum;
	Elf_Half      e_shstrndx;
};

// Section header
struct Elf32_Shdr
{
	Elf_Word   sh_name;
	Elf_Word   sh_type;
	Elf_Word   sh_flags;
	Elf32_Addr sh_addr;
	Elf32_Off  sh_offset;
	Elf_Word   sh_size;
	Elf_Word   sh_link;
	Elf_Word   sh_info;
	Elf_Word   sh_addralign;
	Elf_Word   sh_entsize;
};

struct Elf64_Shdr
{
	Elf_Word   sh_name;
	Elf_Word   sh_type;
	Elf_Xword  sh_flags;
	Elf64_Addr sh_addr;
	Elf64_Off  sh_offset;
	Elf_Xword  sh_size;
	Elf_Word   sh_link;
	Elf_Word   sh_info;
	Elf_Xword  sh_addralign;
	Elf_Xword  sh_entsize;
};

// Segment header
struct Elf32_Phdr
{
	Elf_Word   p_type;
	Elf32_Off  p_offset;
	Elf32_Addr p_vaddr;
	Elf32_Addr p_paddr;
	Elf_Word   p_filesz;
	Elf_Word   p_memsz;
	Elf_Word   p_flags;
	Elf_Word   p_align;
};

struct Elf64_Phdr
{
	Elf_Word   p_type;
	Elf_Word   p_flags;
	Elf64_Off  p_offset;
	Elf64_Addr p_vaddr;
	Elf64_Addr p_paddr;
	Elf_Xword  p_filesz;
	Elf_Xword  p_memsz;
	Elf_Xword  p_align;
};

// Symbol table entry
struct Elf32_Sym
{
	Elf_Word      st_name;
	Elf32_Addr    st_value;
	Elf_Word      st_size;
	unsigned char st_info;
	unsigned char st_other;
	Elf_Half      st_shndx;
};

struct Elf64_Sym
{
	Elf_Word      st_name;
	unsigned char st_info;
	unsigned char st_other;
	Elf_Half      st_shndx;
	Elf64_Addr    st_value;
	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
{
	Elf32_Addr r_offset;
	Elf_Word   r_info;
};

struct Elf32_Rela
{
	Elf32_Addr r_offset;
	Elf_Word   r_info;
	Elf_Sword  r_addend;
};

struct Elf64_Rel
{
	Elf64_Addr r_offset;
	Elf_Xword  r_info;
};

struct Elf64_Rela
{
	Elf64_Addr r_offset;
	Elf_Xword  r_info;
	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 ) \
	( ( ( ( int64_t )( s ) ) << 32 ) + ( (t)&0xffffffffL ) )

// Dynamic structure
struct Elf32_Dyn
{
	Elf_Sword d_tag;
	union {
		Elf_Word   d_val;
		Elf32_Addr d_ptr;
	} d_un;
};

struct Elf64_Dyn
{
	Elf_Sxword d_tag;
	union {
		Elf_Xword  d_val;
		Elf64_Addr d_ptr;
	} d_un;
};

} // namespace ELFIO

#endif // ELFTYPES_H

/*** End of inlined file: elf_types.hpp ***/


/*** Start of inlined file: elfio_version.hpp ***/
#define ELFIO_VERSION "3.8"

/*** End of inlined file: elfio_version.hpp ***/


/*** Start of inlined file: elfio_utils.hpp ***/
#ifndef ELFIO_UTILS_HPP
#define ELFIO_UTILS_HPP

#define ELFIO_GET_ACCESS( TYPE, NAME, FIELD ) \
	TYPE get_##NAME() const { return ( *convertor )( FIELD ); }
#define ELFIO_SET_ACCESS( TYPE, NAME, FIELD ) \
	void set_##NAME( TYPE value )             \
	{                                         \
		FIELD = value;                        \
		FIELD = ( *convertor )( FIELD );      \
	}
#define ELFIO_GET_SET_ACCESS( TYPE, NAME, FIELD )               \
	TYPE get_##NAME() const { return ( *convertor )( FIELD ); } \
	void set_##NAME( TYPE value )                               \
	{                                                           \
		FIELD = value;                                          \
		FIELD = ( *convertor )( FIELD );                        \
	}

#define ELFIO_GET_ACCESS_DECL( TYPE, NAME ) virtual TYPE get_##NAME() const = 0

#define ELFIO_SET_ACCESS_DECL( TYPE, NAME ) \
	virtual void set_##NAME( TYPE value ) = 0

#define ELFIO_GET_SET_ACCESS_DECL( TYPE, NAME ) \
	virtual TYPE get_##NAME() const       = 0;  \
	virtual void set_##NAME( TYPE value ) = 0

namespace ELFIO {

//------------------------------------------------------------------------------
class endianess_convertor
{
  public:
	//------------------------------------------------------------------------------
	endianess_convertor() { need_conversion = false; }

	//------------------------------------------------------------------------------
	void setup( unsigned char elf_file_encoding )
	{
		need_conversion = ( elf_file_encoding != get_host_encoding() );
	}

	//------------------------------------------------------------------------------
	uint64_t operator()( 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;
	}

	//------------------------------------------------------------------------------
	int64_t operator()( int64_t value ) const
	{
		if ( !need_conversion ) {
			return value;
		}
		return ( int64_t )( *this )( (uint64_t)value );
	}

	//------------------------------------------------------------------------------
	uint32_t operator()( uint32_t value ) const
	{
		if ( !need_conversion ) {
			return value;
		}
		value =
			( ( value & 0x000000FF ) << 24 ) | ( ( value & 0x0000FF00 ) << 8 ) |
			( ( value & 0x00FF0000 ) >> 8 ) | ( ( value & 0xFF000000 ) >> 24 );

		return value;
	}

	//------------------------------------------------------------------------------
	int32_t operator()( int32_t value ) const
	{
		if ( !need_conversion ) {
			return value;
		}
		return ( int32_t )( *this )( (uint32_t)value );
	}

	//------------------------------------------------------------------------------
	uint16_t operator()( uint16_t value ) const
	{
		if ( !need_conversion ) {
			return value;
		}
		value = ( ( value & 0x00FF ) << 8 ) | ( ( value & 0xFF00 ) >> 8 );

		return value;
	}

	//------------------------------------------------------------------------------
	int16_t operator()( int16_t value ) const
	{
		if ( !need_conversion ) {
			return value;
		}
		return ( int16_t )( *this )( (uint16_t)value );
	}

	//------------------------------------------------------------------------------
	int8_t operator()( int8_t value ) const { return value; }

	//------------------------------------------------------------------------------
	uint8_t operator()( uint8_t value ) const { return value; }

	//------------------------------------------------------------------------------
  private:
	//------------------------------------------------------------------------------
	unsigned char get_host_encoding() const
	{
		static const int tmp = 1;
		if ( 1 == *(const char*)&tmp ) {
			return ELFDATA2LSB;
		}
		else {
			return ELFDATA2MSB;
		}
	}

	//------------------------------------------------------------------------------
  private:
	bool need_conversion;
};

//------------------------------------------------------------------------------
inline uint32_t elf_hash( const unsigned char* name )
{
	uint32_t h = 0, g;
	while ( *name ) {
		h = ( h << 4 ) + *name++;
		g = h & 0xf0000000;
		if ( g != 0 )
			h ^= g >> 24;
		h &= ~g;
	}
	return h;
}

} // namespace ELFIO

#endif // ELFIO_UTILS_HPP

/*** End of inlined file: elfio_utils.hpp ***/


/*** Start of inlined file: elfio_header.hpp ***/
#ifndef ELF_HEADER_HPP
#define ELF_HEADER_HPP

#include <iostream>

namespace ELFIO {

class elf_header
{
  public:
	virtual ~elf_header(){};
	virtual bool load( std::istream& stream )       = 0;
	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 );
};

template <class T> struct elf_header_impl_types;
template <> struct elf_header_impl_types<Elf32_Ehdr>
{
	typedef Elf32_Phdr         Phdr_type;
	typedef Elf32_Shdr         Shdr_type;
	static const unsigned char file_class = ELFCLASS32;
};
template <> struct elf_header_impl_types<Elf64_Ehdr>
{
	typedef Elf64_Phdr         Phdr_type;
	typedef Elf64_Shdr         Shdr_type;
	static const unsigned char file_class = ELFCLASS64;
};

template <class T> class elf_header_impl : public elf_header
{
  public:
	//------------------------------------------------------------------------------
	elf_header_impl( endianess_convertor* convertor_, unsigned char encoding )
	{
		convertor = convertor_;

		std::fill_n( reinterpret_cast<char*>( &header ), sizeof( header ),
					 '\0' );

		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<T>::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<T>::Phdr_type );
		header.e_shentsize =
			sizeof( typename elf_header_impl_types<T>::Shdr_type );
		header.e_phentsize = ( *convertor )( header.e_phentsize );
		header.e_shentsize = ( *convertor )( header.e_shentsize );
	}

	//------------------------------------------------------------------------------
	bool load( std::istream& stream )
	{
		stream.seekg( 0 );
		stream.read( reinterpret_cast<char*>( &header ), sizeof( header ) );

		return ( stream.gcount() == sizeof( header ) );
	}

	//------------------------------------------------------------------------------
	bool save( std::ostream& stream ) const
	{
		stream.seekp( 0 );
		stream.write( reinterpret_cast<const char*>( &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;
	endianess_convertor* convertor;
};

} // namespace ELFIO

#endif // ELF_HEADER_HPP

/*** End of inlined file: elfio_header.hpp ***/


/*** Start of inlined file: elfio_section.hpp ***/
#ifndef ELFIO_SECTION_HPP
#define ELFIO_SECTION_HPP

#include <string>
#include <iostream>
#include <new>

namespace ELFIO {

class section
{
	friend class elfio;

  public:
	virtual ~section(){};

	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 );

	virtual const char* get_data() const                                = 0;
	virtual void        set_data( const char* pData, Elf_Word size )    = 0;
	virtual void        set_data( const std::string& data )             = 0;
	virtual void        append_data( const char* pData, Elf_Word size ) = 0;
	virtual void        append_data( const std::string& data )          = 0;
	virtual size_t      get_stream_size() const                         = 0;
	virtual void        set_stream_size( size_t value )                 = 0;

  protected:
	ELFIO_SET_ACCESS_DECL( Elf64_Off, offset );
	ELFIO_SET_ACCESS_DECL( Elf_Half, index );

	virtual void load( std::istream& stream, std::streampos header_offset ) = 0;
	virtual void save( std::ostream&  stream,
					   std::streampos header_offset,
					   std::streampos data_offset )                         = 0;
	virtual bool is_address_initialized() const                             = 0;
};

template <class T> class section_impl : public section
{
  public:
	//------------------------------------------------------------------------------
	section_impl( const endianess_convertor* convertor_ )
		: convertor( convertor_ )
	{
		std::fill_n( reinterpret_cast<char*>( &header ), sizeof( header ),
					 '\0' );
		is_address_set = false;
		data           = 0;
		data_size      = 0;
		index          = 0;
		stream_size    = 0;
	}

	//------------------------------------------------------------------------------
	~section_impl() { delete[] data; }

	//------------------------------------------------------------------------------
	// 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 );

	//------------------------------------------------------------------------------
	Elf_Half get_index() const { return index; }

	//------------------------------------------------------------------------------
	std::string get_name() const { return name; }

	//------------------------------------------------------------------------------
	void set_name( std::string name_ ) { name = name_; }

	//------------------------------------------------------------------------------
	void set_address( Elf64_Addr value )
	{
		header.sh_addr = value;
		header.sh_addr = ( *convertor )( header.sh_addr );
		is_address_set = true;
	}

	//------------------------------------------------------------------------------
	bool is_address_initialized() const { return is_address_set; }

	//------------------------------------------------------------------------------
	const char* get_data() const { return data; }

	//------------------------------------------------------------------------------
	void set_data( const char* raw_data, Elf_Word size )
	{
		if ( get_type() != SHT_NOBITS ) {
			delete[] data;
			data = new ( std::nothrow ) char[size];
			if ( 0 != data && 0 != raw_data ) {
				data_size = size;
				std::copy( raw_data, raw_data + size, data );
			}
			else {
				data_size = 0;
			}
		}

		set_size( data_size );
	}

	//------------------------------------------------------------------------------
	void set_data( const std::string& str_data )
	{
		return set_data( str_data.c_str(), (Elf_Word)str_data.size() );
	}

	//------------------------------------------------------------------------------
	void append_data( const char* raw_data, Elf_Word size )
	{
		if ( get_type() != SHT_NOBITS ) {
			if ( get_size() + size < data_size ) {
				std::copy( raw_data, raw_data + size, data + get_size() );
			}
			else {
				data_size      = 2 * ( data_size + size );
				char* new_data = new ( std::nothrow ) char[data_size];

				if ( 0 != new_data ) {
					std::copy( data, data + get_size(), new_data );
					std::copy( raw_data, raw_data + size,
							   new_data + get_size() );
					delete[] data;
					data = new_data;
				}
				else {
					size = 0;
				}
			}
			set_size( get_size() + size );
		}
	}

	//------------------------------------------------------------------------------
	void append_data( const std::string& str_data )
	{
		return append_data( str_data.c_str(), (Elf_Word)str_data.size() );
	}

	//------------------------------------------------------------------------------
  protected:
	//------------------------------------------------------------------------------
	ELFIO_GET_SET_ACCESS( Elf64_Off, offset, header.sh_offset );

	//------------------------------------------------------------------------------
	void set_index( Elf_Half value ) { index = value; }

	//------------------------------------------------------------------------------
	void load( std::istream& stream, std::streampos header_offset )
	{
		std::fill_n( reinterpret_cast<char*>( &header ), sizeof( header ),
					 '\0' );

		stream.seekg( 0, stream.end );
		set_stream_size( stream.tellg() );

		stream.seekg( header_offset );
		stream.read( reinterpret_cast<char*>( &header ), sizeof( header ) );

		Elf_Xword size = get_size();
		if ( 0 == data && SHT_NULL != get_type() && SHT_NOBITS != get_type() &&
			 size < get_stream_size() ) {
			data = new ( std::nothrow ) char[size + 1];

			if ( ( 0 != size ) && ( 0 != data ) ) {
				stream.seekg( ( *convertor )( header.sh_offset ) );
				stream.read( data, size );
				data[size] = 0; // Ensure data is ended with 0 to avoid oob read
				data_size  = size;
			}
			else {
				data_size = 0;
			}
		}
	}

	//------------------------------------------------------------------------------
	void save( std::ostream&  stream,
			   std::streampos header_offset,
			   std::streampos data_offset )
	{
		if ( 0 != get_index() ) {
			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 != 0 ) {
			save_data( stream, data_offset );
		}
	}

	//------------------------------------------------------------------------------
  private:
	//------------------------------------------------------------------------------
	void save_header( std::ostream& stream, std::streampos header_offset ) const
	{
		stream.seekp( header_offset );
		stream.write( reinterpret_cast<const char*>( &header ),
					  sizeof( header ) );
	}

	//------------------------------------------------------------------------------
	void save_data( std::ostream& stream, std::streampos data_offset ) const
	{
		stream.seekp( data_offset );
		stream.write( get_data(), get_size() );
	}

	//------------------------------------------------------------------------------
	size_t get_stream_size() const { return stream_size; }

	//------------------------------------------------------------------------------
	void set_stream_size( size_t value ) { stream_size = value; }

	//------------------------------------------------------------------------------
  private:
	T                          header;
	Elf_Half                   index;
	std::string                name;
	char*                      data;
	Elf_Word                   data_size;
	const endianess_convertor* convertor;
	bool                       is_address_set;
	size_t                     stream_size;
};

} // namespace ELFIO

#endif // ELFIO_SECTION_HPP

/*** End of inlined file: elfio_section.hpp ***/


/*** Start of inlined file: elfio_segment.hpp ***/
#ifndef ELFIO_SEGMENT_HPP
#define ELFIO_SEGMENT_HPP

#include <iostream>
#include <vector>
#include <new>

namespace ELFIO {

class segment
{
	friend class elfio;

  public:
	virtual ~segment(){};

	ELFIO_GET_ACCESS_DECL( Elf_Half, index );
	ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type );
	ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags );
	ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, align );
	ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, virtual_address );
	ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, physical_address );
	ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, file_size );
	ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, memory_size );
	ELFIO_GET_ACCESS_DECL( Elf64_Off, offset );

	virtual const char* get_data() const = 0;

	virtual Elf_Half add_section_index( Elf_Half  index,
										Elf_Xword addr_align )  = 0;
	virtual Elf_Half get_sections_num() const                   = 0;
	virtual Elf_Half get_section_index_at( Elf_Half num ) const = 0;
	virtual bool     is_offset_initialized() const              = 0;

  protected:
	ELFIO_SET_ACCESS_DECL( Elf64_Off, offset );
	ELFIO_SET_ACCESS_DECL( Elf_Half, index );

	virtual const std::vector<Elf_Half>& get_sections() const               = 0;
	virtual void load( std::istream& stream, std::streampos header_offset ) = 0;
	virtual void save( std::ostream&  stream,
					   std::streampos header_offset,
					   std::streampos data_offset )                         = 0;
};

//------------------------------------------------------------------------------
template <class T> class segment_impl : public segment
{
  public:
	//------------------------------------------------------------------------------
	segment_impl( endianess_convertor* convertor_ )
		: stream_size( 0 ), index( 0 ), data( 0 ), convertor( convertor_ )
	{
		is_offset_set = false;
		std::fill_n( reinterpret_cast<char*>( &ph ), sizeof( ph ), '\0' );
	}

	//------------------------------------------------------------------------------
	virtual ~segment_impl() { delete[] data; }

	//------------------------------------------------------------------------------
	// 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 );
	size_t stream_size;

	//------------------------------------------------------------------------------
	size_t get_stream_size() const { return stream_size; }

	//------------------------------------------------------------------------------
	void set_stream_size( size_t value ) { stream_size = value; }

	//------------------------------------------------------------------------------
	Elf_Half get_index() const { return index; }

	//------------------------------------------------------------------------------
	const char* get_data() const { return data; }

	//------------------------------------------------------------------------------
	Elf_Half add_section_index( Elf_Half sec_index, Elf_Xword addr_align )
	{
		sections.push_back( sec_index );
		if ( addr_align > get_align() ) {
			set_align( addr_align );
		}

		return (Elf_Half)sections.size();
	}

	//------------------------------------------------------------------------------
	Elf_Half get_sections_num() const { return (Elf_Half)sections.size(); }

	//------------------------------------------------------------------------------
	Elf_Half get_section_index_at( Elf_Half num ) const
	{
		if ( num < sections.size() ) {
			return sections[num];
		}

		return Elf_Half( -1 );
	}

	//------------------------------------------------------------------------------
  protected:
	//------------------------------------------------------------------------------

	//------------------------------------------------------------------------------
	void set_offset( Elf64_Off value )
	{
		ph.p_offset   = value;
		ph.p_offset   = ( *convertor )( ph.p_offset );
		is_offset_set = true;
	}

	//------------------------------------------------------------------------------
	bool is_offset_initialized() const { return is_offset_set; }

	//------------------------------------------------------------------------------
	const std::vector<Elf_Half>& get_sections() const { return sections; }

	//------------------------------------------------------------------------------
	void set_index( Elf_Half value ) { index = value; }

	//------------------------------------------------------------------------------
	void load( std::istream& stream, std::streampos header_offset )
	{

		stream.seekg( 0, stream.end );
		set_stream_size( stream.tellg() );

		stream.seekg( header_offset );
		stream.read( reinterpret_cast<char*>( &ph ), sizeof( ph ) );
		is_offset_set = true;

		if ( PT_NULL != get_type() && 0 != get_file_size() ) {
			stream.seekg( ( *convertor )( ph.p_offset ) );
			Elf_Xword size = get_file_size();

			if ( size > get_stream_size() ) {
				data = 0;
			}
			else {
				data = new (std::nothrow) char[size + 1];

				if ( 0 != data ) {
					stream.read( data, size );
					data[size] = 0;
				}
			}
		}
	}

	//------------------------------------------------------------------------------
	void save( std::ostream&  stream,
			   std::streampos header_offset,
			   std::streampos data_offset )
	{
		ph.p_offset = data_offset;
		ph.p_offset = ( *convertor )( ph.p_offset );
		stream.seekp( header_offset );
		stream.write( reinterpret_cast<const char*>( &ph ), sizeof( ph ) );
	}

	//------------------------------------------------------------------------------
  private:
	T                     ph;
	Elf_Half              index;
	char*                 data;
	std::vector<Elf_Half> sections;
	endianess_convertor*  convertor;
	bool                  is_offset_set;
};

} // namespace ELFIO

#endif // ELFIO_SEGMENT_HPP

/*** End of inlined file: elfio_segment.hpp ***/


/*** Start of inlined file: elfio_strings.hpp ***/
#ifndef ELFIO_STRINGS_HPP
#define ELFIO_STRINGS_HPP

#include <cstdlib>
#include <cstring>
#include <string>

namespace ELFIO {

//------------------------------------------------------------------------------
template <class S> class string_section_accessor_template
{
  public:
	//------------------------------------------------------------------------------
	string_section_accessor_template( S* section_ ) : string_section( section_ )
	{
	}

	//------------------------------------------------------------------------------
	const char* get_string( Elf_Word index ) const
	{
		if ( string_section ) {
			if ( index < string_section->get_size() ) {
				const char* data = string_section->get_data();
				if ( 0 != data ) {
					return data + index;
				}
			}
		}

		return 0;
	}

	//------------------------------------------------------------------------------
	Elf_Word add_string( const char* str )
	{
		Elf_Word current_position = 0;

		if ( string_section ) {
			// Strings are addeded to the end of the current section data
			current_position = (Elf_Word)string_section->get_size();

			if ( current_position == 0 ) {
				char empty_string = '\0';
				string_section->append_data( &empty_string, 1 );
				current_position++;
			}
			string_section->append_data( str,
										 (Elf_Word)std::strlen( str ) + 1 );
		}

		return current_position;
	}

	//------------------------------------------------------------------------------
	Elf_Word add_string( const std::string& str )
	{
		return add_string( str.c_str() );
	}

	//------------------------------------------------------------------------------
  private:
	S* string_section;
};

using string_section_accessor = string_section_accessor_template<section>;
using const_string_section_accessor =
	string_section_accessor_template<const section>;

} // namespace ELFIO

#endif // ELFIO_STRINGS_HPP

/*** End of inlined file: elfio_strings.hpp ***/

#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
{
  public:
	//------------------------------------------------------------------------------
	elfio() : sections( this ), segments( this )
	{
		header           = 0;
		current_file_pos = 0;
		create( ELFCLASS32, ELFDATA2LSB );
	}

	//------------------------------------------------------------------------------
	~elfio() { clean(); }

	//------------------------------------------------------------------------------
	void create( unsigned char file_class, unsigned char encoding )
	{
		clean();
		convertor.setup( encoding );
		header = create_header( file_class, encoding );
		create_mandatory_sections();
	}

	//------------------------------------------------------------------------------
	bool load( const std::string& file_name )
	{
		std::ifstream stream;
		stream.open( file_name.c_str(), std::ios::in | std::ios::binary );
		if ( !stream ) {
			return false;
		}

		return load( stream );
	}

	//------------------------------------------------------------------------------
	bool load( std::istream& stream )
	{
		clean();

		unsigned char e_ident[EI_NIDENT];
		// Read ELF file signature
		stream.read( reinterpret_cast<char*>( &e_ident ), 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;
		}

		convertor.setup( e_ident[EI_DATA] );
		header = create_header( e_ident[EI_CLASS], e_ident[EI_DATA] );
		if ( 0 == header ) {
			return false;
		}
		if ( !header->load( stream ) ) {
			return false;
		}

		load_sections( stream );
		bool is_still_good = load_segments( stream );
		return is_still_good;
	}

	//------------------------------------------------------------------------------
	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 );
	}

	//------------------------------------------------------------------------------
	bool save( std::ostream& stream )
	{
		if ( !stream || !header ) {
			return false;
		}

		bool is_still_good = true;
		// 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() ? 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() *
							   (Elf_Xword)header->get_segments_num();

		calc_segment_alignment();

		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 );

	//------------------------------------------------------------------------------
	const endianess_convertor& get_convertor() const { return convertor; }

	//------------------------------------------------------------------------------
	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;
		}
	}

	//------------------------------------------------------------------------------
  private:
	bool is_offset_in_section( Elf64_Off offset, const section* sec ) const
	{
		return ( offset >= sec->get_offset() ) &&
			   ( offset < ( sec->get_offset() + sec->get_size() ) );
	}

	//------------------------------------------------------------------------------
  public:
	//! returns an empty string if no problems are detected,
	//! or a string containing an error message if problems are found
	std::string validate() const
	{

		// check for overlapping sections in the file
		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 ) &&
					 !( b->get_type() & SHT_NOBITS ) && ( a->get_size() > 0 ) &&
					 ( b->get_size() > 0 ) && ( a->get_offset() > 0 ) &&
					 ( b->get_offset() > 0 ) ) {
					if ( 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 ) ) {
						return "Sections " + a->get_name() + " and " +
							   b->get_name() + " overlap in file";
					}
				}
			}
		}

		// more checks to be added here...

		return "";
	}

	//------------------------------------------------------------------------------
  private:
	//------------------------------------------------------------------------------
	void clean()
	{
		delete header;
		header = 0;

		std::vector<section*>::const_iterator it;
		for ( it = sections_.begin(); it != sections_.end(); ++it ) {
			delete *it;
		}
		sections_.clear();

		std::vector<segment*>::const_iterator it1;
		for ( it1 = segments_.begin(); it1 != segments_.end(); ++it1 ) {
			delete *it1;
		}
		segments_.clear();
	}

	//------------------------------------------------------------------------------
	elf_header* create_header( unsigned char file_class,
							   unsigned char encoding )
	{
		elf_header* new_header = 0;

		if ( file_class == ELFCLASS64 ) {
			new_header =
				new elf_header_impl<Elf64_Ehdr>( &convertor, encoding );
		}
		else if ( file_class == ELFCLASS32 ) {
			new_header =
				new elf_header_impl<Elf32_Ehdr>( &convertor, encoding );
		}
		else {
			return 0;
		}

		return new_header;
	}

	//------------------------------------------------------------------------------
	section* create_section()
	{
		section*      new_section;
		unsigned char file_class = get_class();

		if ( file_class == ELFCLASS64 ) {
			new_section = new section_impl<Elf64_Shdr>( &convertor );
		}
		else if ( file_class == ELFCLASS32 ) {
			new_section = new section_impl<Elf32_Shdr>( &convertor );
		}
		else {
			return 0;
		}

		new_section->set_index( (Elf_Half)sections_.size() );
		sections_.push_back( new_section );

		return new_section;
	}

	//------------------------------------------------------------------------------
	segment* create_segment()
	{
		segment*      new_segment;
		unsigned char file_class = header->get_class();

		if ( file_class == ELFCLASS64 ) {
			new_segment = new segment_impl<Elf64_Phdr>( &convertor );
		}
		else if ( file_class == ELFCLASS32 ) {
			new_segment = new segment_impl<Elf32_Phdr>( &convertor );
		}
		else {
			return 0;
		}

		new_segment->set_index( (Elf_Half)segments_.size() );
		segments_.push_back( new_segment );

		return new_segment;
	}

	//------------------------------------------------------------------------------
	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 );
	}

	//------------------------------------------------------------------------------
	Elf_Half load_sections( std::istream& stream )
	{
		Elf_Half  entry_size = header->get_section_entry_size();
		Elf_Half  num        = header->get_sections_num();
		Elf64_Off offset     = header->get_sections_offset();

		for ( Elf_Half i = 0; i < num; ++i ) {
			section* sec = create_section();
			sec->load( stream, (std::streamoff)offset +
								   (std::streampos)i * entry_size );
			sec->set_index( i );
			// To mark that the section is not permitted to reassign address
			// during layout calculation
			sec->set_address( sec->get_address() );
		}

		Elf_Half shstrndx = get_section_name_str_index();

		if ( 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 != 0 ) {
					sections[i]->set_name( p );
				}
			}
		}

		return num;
	}

	//------------------------------------------------------------------------------
	//! 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
	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!
	}

	//------------------------------------------------------------------------------
	bool load_segments( std::istream& stream )
	{
		Elf_Half  entry_size = header->get_segment_entry_size();
		Elf_Half  num        = header->get_segments_num();
		Elf64_Off offset     = header->get_segments_offset();

		for ( Elf_Half i = 0; i < num; ++i ) {
			segment*      seg;
			unsigned char file_class = header->get_class();

			if ( file_class == ELFCLASS64 ) {
				seg = new segment_impl<Elf64_Phdr>( &convertor );
			}
			else if ( file_class == ELFCLASS32 ) {
				seg = new segment_impl<Elf32_Phdr>( &convertor );
			}
			else {
				return false;
			}

			seg->load( stream, (std::streamoff)offset +
								   (std::streampos)i * entry_size );
			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 ( Elf_Half j = 0; j < sections.size(); ++j ) {
				const section* psec = sections[j];

				// SHF_ALLOC sections are matched based on the virtual address
				// otherwise the file offset is matched
				if ( ( psec->get_flags() & 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 ) ) {
					// 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 );
				}
			}

			// Add section into the segments' container
			segments_.push_back( seg );
		}

		return true;
	}

	//------------------------------------------------------------------------------
	bool save_header( std::ostream& stream ) { return header->save( stream ); }

	//------------------------------------------------------------------------------
	bool save_sections( std::ostream& stream )
	{
		for ( unsigned int i = 0; i < sections_.size(); ++i ) {
			section* sec = sections_.at( i );

			std::streampos headerPosition =
				(std::streamoff)header->get_sections_offset() +
				(std::streampos)header->get_section_entry_size() *
					sec->get_index();

			sec->save( stream, headerPosition, sec->get_offset() );
		}
		return true;
	}

	//------------------------------------------------------------------------------
	bool save_segments( std::ostream& stream )
	{
		for ( unsigned int i = 0; i < segments_.size(); ++i ) {
			segment* seg = segments_.at( i );

			std::streampos headerPosition =
				header->get_segments_offset() +
				(std::streampos)header->get_segment_entry_size() *
					seg->get_index();

			seg->save( stream, headerPosition, seg->get_offset() );
		}
		return true;
	}

	//------------------------------------------------------------------------------
	bool is_section_without_segment( unsigned int section_index )
	{
		bool found = false;

		for ( unsigned int j = 0; !found && ( j < segments.size() ); ++j ) {
			for ( unsigned int k = 0;
				  !found && ( k < segments[j]->get_sections_num() ); ++k ) {
				found = segments[j]->get_section_index_at( k ) == section_index;
			}
		}

		return !found;
	}

	//------------------------------------------------------------------------------
	bool is_subsequence_of( segment* seg1, segment* seg2 )
	{
		// Return 'true' if sections of seg1 are a subset of sections in seg2
		const std::vector<Elf_Half>& sections1 = seg1->get_sections();
		const std::vector<Elf_Half>& 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;
	}

	//------------------------------------------------------------------------------
	std::vector<segment*> get_ordered_segments()
	{
		std::vector<segment*> res;
		std::deque<segment*>  worklist;

		res.reserve( segments.size() );
		std::copy( segments_.begin(), segments_.end(),
				   std::back_inserter( worklist ) );

		// 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.push_back( seg );
			else
				res.push_back( seg );
		}

		return res;
	}

	//------------------------------------------------------------------------------
	bool layout_sections_without_segments()
	{
		for ( unsigned int i = 0; i < sections_.size(); ++i ) {
			if ( is_section_without_segment( i ) ) {
				section* sec = sections_[i];

				Elf_Xword section_align = sec->get_addr_align();
				if ( 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;
	}

	//------------------------------------------------------------------------------
	void calc_segment_alignment()
	{
		for ( std::vector<segment*>::iterator s = segments_.begin();
			  s != segments_.end(); ++s ) {
			segment* seg = *s;
			for ( int i = 0; i < seg->get_sections_num(); ++i ) {
				section* sect = sections_[seg->get_section_index_at( i )];
				if ( sect->get_addr_align() > seg->get_align() ) {
					seg->set_align( sect->get_addr_align() );
				}
			}
		}
	}

	//------------------------------------------------------------------------------
	bool layout_segments_and_their_sections()
	{
		std::vector<segment*> worklist;
		std::vector<bool>     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 ( unsigned int i = 0; i < worklist.size(); ++i ) {
			Elf_Xword segment_memory   = 0;
			Elf_Xword segment_filesize = 0;
			Elf_Xword seg_start_pos    = current_file_pos;
			segment*  seg              = worklist[i];

			// 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() *
					(Elf_Xword)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() ) {
					segment_memory = segment_filesize = current_file_pos;
				}
			}
			// New segments with not generated sections
			// have to be aligned
			else if ( seg->get_sections_num() &&
					  !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 error = req_page_alignment - cur_page_alignment;

				current_file_pos += ( seg->get_align() + error ) % align;
				seg_start_pos = current_file_pos;
			}
			else if ( seg->get_sections_num() ) {
				seg_start_pos =
					sections[seg->get_section_index_at( 0 )]->get_offset();
			}

			// Write segment's data
			for ( unsigned int 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 secAlign = 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!
						// secAlign would turn out negative, seeking backwards and overwriting previous data
						return false;
					}
					secAlign = 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;
					secAlign        = ( align - error ) % align;
				}
				else if ( section_generated[index] ) {
					// Alignment for already generated sections
					secAlign =
						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 ) &&
					 !( ( sec->get_flags() & SHF_TLS ) &&
						( seg->get_type() != PT_TLS ) &&
						( SHT_NOBITS == sec->get_type() ) ) )
					segment_memory += sec->get_size() + secAlign;

				if ( SHT_NOBITS != sec->get_type() )
					segment_filesize += sec->get_size() + secAlign;

				// Nothing to be done when generating nested segments
				if ( section_generated[index] ) {
					continue;
				}

				current_file_pos += secAlign;

				// 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;
			}

			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;
	}

	//------------------------------------------------------------------------------
	bool layout_section_table()
	{
		// Simply place the section table at the end for now
		Elf64_Off alignmentError = current_file_pos % 4;
		current_file_pos += ( 4 - alignmentError ) % 4;
		header->set_sections_offset( current_file_pos );
		return true;
	}

	//------------------------------------------------------------------------------
  public:
	friend class Sections;
	class Sections
	{
	  public:
		//------------------------------------------------------------------------------
		Sections( elfio* parent_ ) : parent( parent_ ) {}

		//------------------------------------------------------------------------------
		Elf_Half size() const { return (Elf_Half)parent->sections_.size(); }

		//------------------------------------------------------------------------------
		section* operator[]( unsigned int index ) const
		{
			section* sec = 0;

			if ( index < parent->sections_.size() ) {
				sec = parent->sections_[index];
			}

			return sec;
		}

		//------------------------------------------------------------------------------
		section* operator[]( const std::string& name ) const
		{
			section* sec = 0;

			std::vector<section*>::const_iterator it;
			for ( it = parent->sections_.begin(); it != parent->sections_.end();
				  ++it ) {
				if ( ( *it )->get_name() == name ) {
					sec = *it;
					break;
				}
			}

			return sec;
		}

		//------------------------------------------------------------------------------
		section* add( const std::string& name )
		{
			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] );
			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;
		}

		//------------------------------------------------------------------------------
		std::vector<section*>::iterator begin()
		{
			return parent->sections_.begin();
		}

		//------------------------------------------------------------------------------
		std::vector<section*>::iterator end()
		{
			return parent->sections_.end();
		}

		//------------------------------------------------------------------------------
		std::vector<section*>::const_iterator begin() const
		{
			return parent->sections_.cbegin();
		}

		//------------------------------------------------------------------------------
		std::vector<section*>::const_iterator end() const
		{
			return parent->sections_.cend();
		}

		//------------------------------------------------------------------------------
	  private:
		elfio* parent;
	} sections;

	//------------------------------------------------------------------------------
  public:
	friend class Segments;
	class Segments
	{
	  public:
		//------------------------------------------------------------------------------
		Segments( elfio* parent_ ) : parent( parent_ ) {}

		//------------------------------------------------------------------------------
		Elf_Half size() const { return (Elf_Half)parent->segments_.size(); }

		//------------------------------------------------------------------------------
		segment* operator[]( unsigned int index ) const
		{
			return parent->segments_[index];
		}

		//------------------------------------------------------------------------------
		segment* add() { return parent->create_segment(); }

		//------------------------------------------------------------------------------
		std::vector<segment*>::iterator begin()
		{
			return parent->segments_.begin();
		}

		//------------------------------------------------------------------------------
		std::vector<segment*>::iterator end()
		{
			return parent->segments_.end();
		}

		//------------------------------------------------------------------------------
		std::vector<segment*>::const_iterator begin() const
		{
			return parent->segments_.cbegin();
		}

		//------------------------------------------------------------------------------
		std::vector<segment*>::const_iterator end() const
		{
			return parent->segments_.cend();
		}

		//------------------------------------------------------------------------------
	  private:
		elfio* parent;
	} segments;

	//------------------------------------------------------------------------------
  private:
	elf_header*           header;
	std::vector<section*> sections_;
	std::vector<segment*> segments_;
	endianess_convertor   convertor;

	Elf_Xword current_file_pos;
};

} // namespace ELFIO


/*** Start of inlined file: elfio_symbols.hpp ***/
#ifndef ELFIO_SYMBOLS_HPP
#define ELFIO_SYMBOLS_HPP

namespace ELFIO {

//------------------------------------------------------------------------------
template <class S> class symbol_section_accessor_template
{
  public:
	//------------------------------------------------------------------------------
	symbol_section_accessor_template( const elfio& elf_file_,
									  S*           symbol_section_ )
		: elf_file( elf_file_ ), symbol_section( symbol_section_ )
	{
		find_hash_section();
	}

	//------------------------------------------------------------------------------
	Elf_Xword get_symbols_num() const
	{
		Elf_Xword nRet = 0;
		if ( 0 != symbol_section->get_entry_size() ) {
			nRet =
				symbol_section->get_size() / symbol_section->get_entry_size();
		}

		return nRet;
	}

	//------------------------------------------------------------------------------
	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<Elf32_Sym>( index, name, value, size, bind,
												 type, section_index, other );
		}
		else {
			ret = generic_get_symbol<Elf64_Sym>( index, name, value, size, bind,
												 type, section_index, other );
		}

		return ret;
	}

	//------------------------------------------------------------------------------
	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() ) {
			Elf_Word    nbucket = *(const Elf_Word*)hash_section->get_data();
			Elf_Word    nchain  = *(const Elf_Word*)( hash_section->get_data() +
												  sizeof( Elf_Word ) );
			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 ) );
			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 ) );
				get_symbol( y, str, value, size, bind, type, section_index,
							other );
			}
			if ( str == name ) {
				ret = true;
			}
		}
		else {
			for ( Elf_Xword i = 0; i < get_symbols_num() && !ret; i++ ) {
				std::string symbol_name;
				if ( get_symbol( i, symbol_name, value, size, bind, type,
								 section_index, other ) ) {
					if ( symbol_name == name ) {
						ret = true;
					}
				}
			}
		}

		return ret;
	}

	//------------------------------------------------------------------------------
	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 endianess_convertor& 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<Elf32_Sym>(
				[&]( const Elf32_Sym* sym ) {
					return convertor( sym->st_value ) == value;
				},
				idx );
		}
		else {
			match = generic_search_symbols<Elf64_Sym>(
				[&]( 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;
	}

	//------------------------------------------------------------------------------
	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<Elf32_Sym>( 0, 0, 0, 0, 0, 0 );
			}
			else {
				nRet = generic_add_symbol<Elf64_Sym>( 0, 0, 0, 0, 0, 0 );
			}
		}

		if ( elf_file.get_class() == ELFCLASS32 ) {
			nRet = generic_add_symbol<Elf32_Sym>( name, value, size, info,
												  other, shndx );
		}
		else {
			nRet = generic_add_symbol<Elf64_Sym>( name, value, size, info,
												  other, shndx );
		}

		return nRet;
	}

	//------------------------------------------------------------------------------
	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 );
	}

	//------------------------------------------------------------------------------
	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 );
	}

	//------------------------------------------------------------------------------
	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 );
	}

	//------------------------------------------------------------------------------
	Elf_Xword arrange_local_symbols(
		std::function<void( Elf_Xword first, Elf_Xword second )> func =
			nullptr )
	{
		int nRet = 0;

		if ( elf_file.get_class() == ELFCLASS32 ) {
			nRet = generic_arrange_local_symbols<Elf32_Sym>( func );
		}
		else {
			nRet = generic_arrange_local_symbols<Elf64_Sym>( func );
		}

		return nRet;
	}

	//------------------------------------------------------------------------------
  private:
	//------------------------------------------------------------------------------
	void find_hash_section()
	{
		hash_section       = 0;
		hash_section_index = 0;
		Elf_Half nSecNo    = elf_file.sections.size();
		for ( Elf_Half i = 0; i < nSecNo && 0 == hash_section_index; ++i ) {
			const section* sec = elf_file.sections[i];
			if ( sec->get_link() == symbol_section->get_index() ) {
				hash_section       = sec;
				hash_section_index = i;
			}
		}
	}

	//------------------------------------------------------------------------------
	Elf_Half get_string_table_index() const
	{
		return (Elf_Half)symbol_section->get_link();
	}

	//------------------------------------------------------------------------------
	Elf_Half get_hash_table_index() const { return hash_section_index; }

	//------------------------------------------------------------------------------
	template <class T> const T* generic_get_symbol_ptr( Elf_Xword index ) const
	{
		if ( 0 != symbol_section->get_data() && index < get_symbols_num() ) {
			const T* pSym = reinterpret_cast<const T*>(
				symbol_section->get_data() +
				index * symbol_section->get_entry_size() );

			return pSym;
		}

		return nullptr;
	}

	//------------------------------------------------------------------------------
	template <class T>
	bool generic_search_symbols( std::function<bool( const T* )> match,
								 Elf_Xword&                      idx ) const
	{
		for ( Elf_Xword i = 0; i < get_symbols_num(); i++ ) {
			const T* symPtr = generic_get_symbol_ptr<T>( i );

			if ( symPtr == nullptr )
				return false;

			if ( match( symPtr ) ) {
				idx = i;
				return true;
			}
		}

		return false;
	}

	//------------------------------------------------------------------------------
	template <class T>
	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 ( 0 != symbol_section->get_data() && index < get_symbols_num() ) {
			const T* pSym = reinterpret_cast<const T*>(
				symbol_section->get_data() +
				index * symbol_section->get_entry_size() );

			const endianess_convertor& 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 ( 0 != 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;
	}

	//------------------------------------------------------------------------------
	template <class T>
	Elf_Word generic_add_symbol( Elf_Word      name,
								 Elf64_Addr    value,
								 Elf_Xword     size,
								 unsigned char info,
								 unsigned char other,
								 Elf_Half      shndx )
	{
		const endianess_convertor& convertor = elf_file.get_convertor();

		T entry;
		entry.st_name  = convertor( name );
		entry.st_value = value;
		entry.st_value = convertor( entry.st_value );
		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<char*>( &entry ),
									 sizeof( entry ) );

		Elf_Word nRet = symbol_section->get_size() / sizeof( entry ) - 1;

		return nRet;
	}

	//------------------------------------------------------------------------------
	template <class T>
	Elf_Xword generic_arrange_local_symbols(
		std::function<void( Elf_Xword first, Elf_Xword second )> func )
	{
		const endianess_convertor& convertor = elf_file.get_convertor();
		const Elf_Xword            size      = symbol_section->get_entry_size();

		Elf_Xword 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<T*>(
					generic_get_symbol_ptr<T>( 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<T*>( generic_get_symbol_ptr<T>( 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 );

				// Swap the symbols
				T tmp;
				std::copy( p1, p1 + 1, &tmp );
				std::copy( p2, p2 + 1, p1 );
				std::copy( &tmp, &tmp + 1, p2 );
			}
			else {
				// Update 'info' field of the section
				symbol_section->set_info( first_not_local );
				break;
			}
		}

		// Elf_Word nRet = symbol_section->get_size() / sizeof(entry) - 1;

		return first_not_local;
	}

	//------------------------------------------------------------------------------
  private:
	const elfio&   elf_file;
	S*             symbol_section;
	Elf_Half       hash_section_index;
	const section* hash_section;
};

using symbol_section_accessor = symbol_section_accessor_template<section>;
using const_symbol_section_accessor =
	symbol_section_accessor_template<const section>;

} // namespace ELFIO

#endif // ELFIO_SYMBOLS_HPP

/*** End of inlined file: elfio_symbols.hpp ***/


/*** Start of inlined file: elfio_note.hpp ***/
#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
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
template <class S> class note_section_accessor_template
{
  public:
	//------------------------------------------------------------------------------
	note_section_accessor_template( const elfio& elf_file_, S* section_ )
		: elf_file( elf_file_ ), note_section( section_ )
	{
		process_section();
	}

	//------------------------------------------------------------------------------
	Elf_Word get_notes_num() const
	{
		return (Elf_Word)note_start_positions.size();
	}

	//------------------------------------------------------------------------------
	bool get_note( Elf_Word     index,
				   Elf_Word&    type,
				   std::string& name,
				   void*&       desc,
				   Elf_Word&    descSize ) const
	{
		if ( index >= note_section->get_size() ) {
			return false;
		}

		const char* pData =
			note_section->get_data() + note_start_positions[index];
		int align = sizeof( Elf_Word );

		const endianess_convertor& convertor = elf_file.get_convertor();
		type            = convertor( *(const Elf_Word*)( pData + 2 * align ) );
		Elf_Word namesz = convertor( *(const Elf_Word*)( pData ) );
		descSize = convertor( *(const Elf_Word*)( pData + sizeof( namesz ) ) );

		Elf_Xword max_name_size =
			note_section->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 * align, namesz - 1 );
		if ( 0 == descSize ) {
			desc = 0;
		}
		else {
			desc =
				const_cast<char*>( pData + 3 * align +
								   ( ( namesz + align - 1 ) / align ) * align );
		}

		return true;
	}

	//------------------------------------------------------------------------------
	void add_note( Elf_Word           type,
				   const std::string& name,
				   const void*        desc,
				   Elf_Word           descSize )
	{
		const endianess_convertor& 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<char*>( &nameLenConv ), align );
		Elf_Word    descSizeConv = convertor( descSize );

		buffer.append( reinterpret_cast<char*>( &descSizeConv ), align );
		type = convertor( type );
		buffer.append( reinterpret_cast<char*>( &type ), align );
		buffer.append( name );
		buffer.append( 1, '\x00' );
		const char pad[] = { '\0', '\0', '\0', '\0' };
		if ( nameLen % align != 0 ) {
			buffer.append( pad, align - nameLen % align );
		}
		if ( desc != 0 && descSize != 0 ) {
			buffer.append( reinterpret_cast<const char*>( desc ), descSize );
			if ( descSize % align != 0 ) {
				buffer.append( pad, align - descSize % align );
			}
		}

		note_start_positions.push_back( note_section->get_size() );
		note_section->append_data( buffer );
	}

  private:
	//------------------------------------------------------------------------------
	void process_section()
	{
		const endianess_convertor& convertor = elf_file.get_convertor();
		const char*                data      = note_section->get_data();
		Elf_Xword                  size      = note_section->get_size();
		Elf_Xword                  current   = 0;

		note_start_positions.clear();

		// Is it empty?
		if ( 0 == data || 0 == size ) {
			return;
		}

		Elf_Word align = sizeof( Elf_Word );
		while ( current + (Elf_Xword)3 * align <= size ) {
			note_start_positions.push_back( current );
			Elf_Word namesz = convertor( *(const Elf_Word*)( data + current ) );
			Elf_Word descsz = convertor(
				*(const Elf_Word*)( data + current + sizeof( namesz ) ) );

			current += (Elf_Xword)3 * sizeof( Elf_Word ) +
					   ( ( namesz + align - 1 ) / align ) * (Elf_Xword)align +
					   ( ( descsz + align - 1 ) / align ) * (Elf_Xword)align;
		}
	}

	//------------------------------------------------------------------------------
  private:
	const elfio&           elf_file;
	S*                     note_section;
	std::vector<Elf_Xword> note_start_positions;
};

using note_section_accessor = note_section_accessor_template<section>;
using const_note_section_accessor =
	note_section_accessor_template<const section>;

} // namespace ELFIO

#endif // ELFIO_NOTE_HPP

/*** End of inlined file: elfio_note.hpp ***/


/*** Start of inlined file: elfio_relocation.hpp ***/
#ifndef ELFIO_RELOCATION_HPP
#define ELFIO_RELOCATION_HPP

namespace ELFIO {

template <typename T> struct get_sym_and_type;
template <> struct get_sym_and_type<Elf32_Rel>
{
	static int get_r_sym( Elf_Xword info )
	{
		return ELF32_R_SYM( (Elf_Word)info );
	}
	static int get_r_type( Elf_Xword info )
	{
		return ELF32_R_TYPE( (Elf_Word)info );
	}
};
template <> struct get_sym_and_type<Elf32_Rela>
{
	static int get_r_sym( Elf_Xword info )
	{
		return ELF32_R_SYM( (Elf_Word)info );
	}
	static int get_r_type( Elf_Xword info )
	{
		return ELF32_R_TYPE( (Elf_Word)info );
	}
};
template <> struct get_sym_and_type<Elf64_Rel>
{
	static int get_r_sym( Elf_Xword info ) { return ELF64_R_SYM( info ); }
	static int get_r_type( Elf_Xword info ) { return ELF64_R_TYPE( info ); }
};
template <> struct get_sym_and_type<Elf64_Rela>
{
	static int get_r_sym( Elf_Xword info ) { return ELF64_R_SYM( info ); }
	static int get_r_type( Elf_Xword info ) { return ELF64_R_TYPE( info ); }
};

//------------------------------------------------------------------------------
template <class S> class relocation_section_accessor_template
{
  public:
	//------------------------------------------------------------------------------
	relocation_section_accessor_template( const elfio& elf_file_, S* section_ )
		: elf_file( elf_file_ ), relocation_section( section_ )
	{
	}

	//------------------------------------------------------------------------------
	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;
	}

	//------------------------------------------------------------------------------
	bool get_entry( Elf_Xword   index,
					Elf64_Addr& offset,
					Elf_Word&   symbol,
					Elf_Word&   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() ) {
				generic_get_entry_rel<Elf32_Rel>( index, offset, symbol, type,
												  addend );
			}
			else if ( SHT_RELA == relocation_section->get_type() ) {
				generic_get_entry_rela<Elf32_Rela>( index, offset, symbol, type,
													addend );
			}
		}
		else {
			if ( SHT_REL == relocation_section->get_type() ) {
				generic_get_entry_rel<Elf64_Rel>( index, offset, symbol, type,
												  addend );
			}
			else if ( SHT_RELA == relocation_section->get_type() ) {
				generic_get_entry_rela<Elf64_Rela>( index, offset, symbol, type,
													addend );
			}
		}

		return true;
	}

	//------------------------------------------------------------------------------
	bool get_entry( Elf_Xword    index,
					Elf64_Addr&  offset,
					Elf64_Addr&  symbolValue,
					std::string& symbolName,
					Elf_Word&    type,
					Elf_Sxword&  addend,
					Elf_Sxword&  calcValue ) const
	{
		// Do regular job
		Elf_Word symbol;
		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;
	}

	//------------------------------------------------------------------------------
	bool set_entry( Elf_Xword  index,
					Elf64_Addr offset,
					Elf_Word   symbol,
					Elf_Word   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<Elf32_Rel>( index, offset, symbol, type,
												  addend );
			}
			else if ( SHT_RELA == relocation_section->get_type() ) {
				generic_set_entry_rela<Elf32_Rela>( index, offset, symbol, type,
													addend );
			}
		}
		else {
			if ( SHT_REL == relocation_section->get_type() ) {
				generic_set_entry_rel<Elf64_Rel>( index, offset, symbol, type,
												  addend );
			}
			else if ( SHT_RELA == relocation_section->get_type() ) {
				generic_set_entry_rela<Elf64_Rela>( index, offset, symbol, type,
													addend );
			}
		}

		return true;
	}

	//------------------------------------------------------------------------------
	void add_entry( Elf64_Addr offset, Elf_Xword info )
	{
		if ( elf_file.get_class() == ELFCLASS32 ) {
			generic_add_entry<Elf32_Rel>( offset, info );
		}
		else {
			generic_add_entry<Elf64_Rel>( offset, info );
		}
	}

	//------------------------------------------------------------------------------
	void add_entry( Elf64_Addr offset, Elf_Word symbol, unsigned char 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 );
	}

	//------------------------------------------------------------------------------
	void add_entry( Elf64_Addr offset, Elf_Xword info, Elf_Sxword addend )
	{
		if ( elf_file.get_class() == ELFCLASS32 ) {
			generic_add_entry<Elf32_Rela>( offset, info, addend );
		}
		else {
			generic_add_entry<Elf64_Rela>( offset, info, addend );
		}
	}

	//------------------------------------------------------------------------------
	void add_entry( Elf64_Addr    offset,
					Elf_Word      symbol,
					unsigned char 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 );
	}

	//------------------------------------------------------------------------------
	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 char           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 );
	}

	//------------------------------------------------------------------------------
	void swap_symbols( Elf_Xword first, Elf_Xword second )
	{
		Elf64_Addr offset;
		Elf_Word   symbol;
		Elf_Word   rtype;
		Elf_Sxword addend;
		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:
	//------------------------------------------------------------------------------
	Elf_Half get_symbol_table_index() const
	{
		return (Elf_Half)relocation_section->get_link();
	}

	//------------------------------------------------------------------------------
	template <class T>
	void generic_get_entry_rel( Elf_Xword   index,
								Elf64_Addr& offset,
								Elf_Word&   symbol,
								Elf_Word&   type,
								Elf_Sxword& addend ) const
	{
		const endianess_convertor& convertor = elf_file.get_convertor();

		const T* pEntry = reinterpret_cast<const T*>(
			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<T>::get_r_sym( tmp );
		type          = get_sym_and_type<T>::get_r_type( tmp );
		addend        = 0;
	}

	//------------------------------------------------------------------------------
	template <class T>
	void generic_get_entry_rela( Elf_Xword   index,
								 Elf64_Addr& offset,
								 Elf_Word&   symbol,
								 Elf_Word&   type,
								 Elf_Sxword& addend ) const
	{
		const endianess_convertor& convertor = elf_file.get_convertor();

		const T* pEntry = reinterpret_cast<const T*>(
			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<T>::get_r_sym( tmp );
		type          = get_sym_and_type<T>::get_r_type( tmp );
		addend        = convertor( pEntry->r_addend );
	}

	//------------------------------------------------------------------------------
	template <class T>
	void generic_set_entry_rel( Elf_Xword  index,
								Elf64_Addr offset,
								Elf_Word   symbol,
								Elf_Word   type,
								Elf_Sxword )
	{
		const endianess_convertor& convertor = elf_file.get_convertor();

		T* pEntry = const_cast<T*>( reinterpret_cast<const T*>(
			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 = offset;
		pEntry->r_offset = convertor( pEntry->r_offset );
		pEntry->r_info   = convertor( pEntry->r_info );
	}

	//------------------------------------------------------------------------------
	template <class T>
	void generic_set_entry_rela( Elf_Xword  index,
								 Elf64_Addr offset,
								 Elf_Word   symbol,
								 Elf_Word   type,
								 Elf_Sxword addend )
	{
		const endianess_convertor& convertor = elf_file.get_convertor();

		T* pEntry = const_cast<T*>( reinterpret_cast<const T*>(
			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 = offset;
		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 );
	}

	//------------------------------------------------------------------------------
	template <class T>
	void generic_add_entry( Elf64_Addr offset, Elf_Xword info )
	{
		const endianess_convertor& convertor = elf_file.get_convertor();

		T entry;
		entry.r_offset = offset;
		entry.r_info   = info;
		entry.r_offset = convertor( entry.r_offset );
		entry.r_info   = convertor( entry.r_info );

		relocation_section->append_data( reinterpret_cast<char*>( &entry ),
										 sizeof( entry ) );
	}

	//------------------------------------------------------------------------------
	template <class T>
	void
	generic_add_entry( Elf64_Addr offset, Elf_Xword info, Elf_Sxword addend )
	{
		const endianess_convertor& 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<char*>( &entry ),
										 sizeof( entry ) );
	}

	//------------------------------------------------------------------------------
  private:
	const elfio& elf_file;
	S*           relocation_section;
};

using relocation_section_accessor =
	relocation_section_accessor_template<section>;
using const_relocation_section_accessor =
	relocation_section_accessor_template<const section>;

} // namespace ELFIO

#endif // ELFIO_RELOCATION_HPP

/*** End of inlined file: elfio_relocation.hpp ***/


/*** Start of inlined file: elfio_dynamic.hpp ***/
#ifndef ELFIO_DYNAMIC_HPP
#define ELFIO_DYNAMIC_HPP

namespace ELFIO {

//------------------------------------------------------------------------------
template <class S> class dynamic_section_accessor_template
{
  public:
	//------------------------------------------------------------------------------
	dynamic_section_accessor_template( const elfio& elf_file_, S* section_ )
		: elf_file( elf_file_ ), dynamic_section( section_ )
	{
	}

	//------------------------------------------------------------------------------
	Elf_Xword get_entries_num() const
	{
		Elf_Xword nRet = 0;

		if ( 0 != dynamic_section->get_entry_size() ) {
			nRet =
				dynamic_section->get_size() / dynamic_section->get_entry_size();
		}

		return nRet;
	}

	//------------------------------------------------------------------------------
	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<Elf32_Dyn>( index, tag, value );
		}
		else {
			generic_get_entry_dyn<Elf64_Dyn>( index, tag, value );
		}

		// If the tag may have 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( value );
			if ( 0 == result ) {
				str.clear();
				return false;
			}
			str = result;
		}
		else {
			str.clear();
		}

		return true;
	}

	//------------------------------------------------------------------------------
	void add_entry( Elf_Xword tag, Elf_Xword value )
	{
		if ( elf_file.get_class() == ELFCLASS32 ) {
			generic_add_entry<Elf32_Dyn>( tag, value );
		}
		else {
			generic_add_entry<Elf64_Dyn>( tag, value );
		}
	}

	//------------------------------------------------------------------------------
	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:
	//------------------------------------------------------------------------------
	Elf_Half get_string_table_index() const
	{
		return (Elf_Half)dynamic_section->get_link();
	}

	//------------------------------------------------------------------------------
	template <class T>
	void generic_get_entry_dyn( Elf_Xword  index,
								Elf_Xword& tag,
								Elf_Xword& value ) const
	{
		const endianess_convertor& convertor = elf_file.get_convertor();

		// Check unusual case when dynamic section has no data
		if ( dynamic_section->get_data() == 0 ||
			 ( index + 1 ) * dynamic_section->get_entry_size() >
				 dynamic_section->get_size() ) {
			tag   = DT_NULL;
			value = 0;
			return;
		}

		const T* pEntry = reinterpret_cast<const T*>(
			dynamic_section->get_data() +
			index * dynamic_section->get_entry_size() );
		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;
		}
	}

	//------------------------------------------------------------------------------
	template <class T> void generic_add_entry( Elf_Xword tag, Elf_Xword value )
	{
		const endianess_convertor& convertor = elf_file.get_convertor();

		T entry;

		switch ( tag ) {
		case DT_NULL:
		case DT_SYMBOLIC:
		case DT_TEXTREL:
		case DT_BIND_NOW:
			value = 0;
		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( 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( value );
			break;
		}

		entry.d_tag = convertor( tag );

		dynamic_section->append_data( reinterpret_cast<char*>( &entry ),
									  sizeof( entry ) );
	}

	//------------------------------------------------------------------------------
  private:
	const elfio& elf_file;
	S*           dynamic_section;
};

using dynamic_section_accessor = dynamic_section_accessor_template<section>;
using const_dynamic_section_accessor =
	dynamic_section_accessor_template<const section>;

} // namespace ELFIO

#endif // ELFIO_DYNAMIC_HPP

/*** End of inlined file: elfio_dynamic.hpp ***/


/*** Start of inlined file: elfio_modinfo.hpp ***/
#ifndef ELFIO_MODINFO_HPP
#define ELFIO_MODINFO_HPP

#include <string>
#include <vector>

namespace ELFIO {

//------------------------------------------------------------------------------
template <class S> class modinfo_section_accessor_template
{
  public:
	//------------------------------------------------------------------------------
	modinfo_section_accessor_template( S* section_ )
		: modinfo_section( section_ )
	{
		process_section();
	}

	//------------------------------------------------------------------------------
	Elf_Word get_attribute_num() const { return (Elf_Word)content.size(); }

	//------------------------------------------------------------------------------
	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;
	}

	//------------------------------------------------------------------------------
	bool get_attribute( std::string field_name, std::string& value ) const
	{
		for ( auto i = content.begin(); i != content.end(); i++ ) {
			if ( field_name == i->first ) {
				value = i->second;
				return true;
			}
		}

		return false;
	}

	//------------------------------------------------------------------------------
	Elf_Word add_attribute( std::string field, 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.push_back(
				std::pair<std::string, std::string>( field, value ) );
		}

		return current_position;
	}

	//------------------------------------------------------------------------------
  private:
	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( '=' );
					std::pair<std::string, std::string> attribute(
						info.substr( 0, loc ), info.substr( loc + 1 ) );

					content.push_back( attribute );

					i += info.length();
				}
			}
		}
	}

	//------------------------------------------------------------------------------
  private:
	S*                                               modinfo_section;
	std::vector<std::pair<std::string, std::string>> content;
};

using modinfo_section_accessor = modinfo_section_accessor_template<section>;
using const_modinfo_section_accessor =
	modinfo_section_accessor_template<const section>;

} // namespace ELFIO

#endif // ELFIO_MODINFO_HPP

/*** End of inlined file: elfio_modinfo.hpp ***/

#ifdef _MSC_VER
#pragma warning( pop )
#endif

#endif // ELFIO_HPP

/*** End of inlined file: elfio.hpp ***/


namespace ELFIO {

static struct class_table_t
{
	const char  key;
	const char* str;
} class_table[] = {
	{ ELFCLASS32, "ELF32" },
	{ ELFCLASS64, "ELF64" },
};

static struct endian_table_t
{
	const char  key;
	const char* str;
} endian_table[] = {
	{ ELFDATANONE, "None" },
	{ ELFDATA2LSB, "Little endian" },
	{ ELFDATA2MSB, "Big endian" },
};

static struct version_table_t
{
	const Elf64_Word key;
	const char*      str;
} version_table[] = {
	{ EV_NONE, "None" },
	{ EV_CURRENT, "Current" },
};

static 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 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_res183, "Reserved by ARM" },
	{ 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 " },
};

static struct section_type_table_t
{
	const Elf64_Half 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 " },
};

static 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" },
};

static struct segment_flag_table_t
{
	const Elf_Word key;
	const char*    str;
} segment_flag_table[] = {
	{ 0, "" },  { 1, "X" },  { 2, "W" },  { 3, "WX" },
	{ 4, "R" }, { 5, "RX" }, { 6, "RW" }, { 7, "RWX" },
};

static 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 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 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" },
};

static const ELFIO::Elf_Xword MAX_DATA_ENTRIES = 64;

//------------------------------------------------------------------------------
class dump
{
#define DUMP_DEC_FORMAT( width ) \
	std::setw( width ) << std::setfill( ' ' ) << std::dec << 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:
	//------------------------------------------------------------------------------
	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
			<< "  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;
	}

	//------------------------------------------------------------------------------
	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            "
				   " ES   Flg"
				<< std::endl
				<< "        Lk   Inf  Al      Name" << std::endl;
		}

		for ( Elf_Half i = 0; i < n; ++i ) { // For all sections
			section* sec = reader.sections[i];
			section_header( out, i, sec, reader.get_class() );
		}

		out << "Key to Flags: W (write), A (alloc), X (execute)\n\n"
			<< std::endl;
	}

	//------------------------------------------------------------------------------
	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();

		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_HEX_FORMAT( 8 ) << sec->get_address() << " "
				<< DUMP_HEX_FORMAT( 8 ) << sec->get_size() << " "
				<< DUMP_HEX_FORMAT( 2 ) << sec->get_entry_size() << " "
				<< DUMP_STR_FORMAT( 3 ) << section_flags( sec->get_flags() )
				<< " " << DUMP_HEX_FORMAT( 2 ) << sec->get_link() << " "
				<< DUMP_HEX_FORMAT( 3 ) << sec->get_info() << " "
				<< DUMP_HEX_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_HEX_FORMAT( 16 ) << sec->get_address() << " "
				<< DUMP_HEX_FORMAT( 16 ) << sec->get_size() << " "
				<< DUMP_HEX_FORMAT( 4 ) << sec->get_entry_size() << " "
				<< DUMP_STR_FORMAT( 3 ) << section_flags( sec->get_flags() )
				<< " " << std::endl
				<< "        " << DUMP_HEX_FORMAT( 4 ) << sec->get_link() << " "
				<< DUMP_HEX_FORMAT( 4 ) << sec->get_info() << " "
				<< DUMP_HEX_FORMAT( 4 ) << sec->get_addr_align() << "    "
				<< DUMP_STR_FORMAT( 17 ) << sec->get_name() << " " << std::endl;
		}

		out.flags( original_flags );

		return;
	}

	//------------------------------------------------------------------------------
	static void segment_headers( std::ostream& out, const elfio& reader )
	{
		Elf_Half n = reader.segments.size();
		if ( n == 0 ) {
			return;
		}

		out << "Segment 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           VirtAddr         PhysAddr         "
				   "Flags"
				<< std::endl
				<< "                       FileSize         Mem.Size         "
				   "Align"
				<< std::endl;
		}

		for ( Elf_Half i = 0; i < n; ++i ) {
			segment* seg = reader.segments[i];
			segment_header( out, i, seg, reader.get_class() );
		}

		out << std::endl;
	}

	//------------------------------------------------------------------------------
	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();

		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_HEX_FORMAT( 8 ) << seg->get_virtual_address()
				<< " " << DUMP_HEX_FORMAT( 8 ) << seg->get_physical_address()
				<< " " << DUMP_HEX_FORMAT( 8 ) << seg->get_file_size() << " "
				<< DUMP_HEX_FORMAT( 8 ) << seg->get_memory_size() << " "
				<< DUMP_STR_FORMAT( 8 ) << str_segment_flag( seg->get_flags() )
				<< " " << DUMP_HEX_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_HEX_FORMAT( 16 ) << seg->get_virtual_address()
				<< " " << DUMP_HEX_FORMAT( 16 ) << seg->get_physical_address()
				<< " " << DUMP_STR_FORMAT( 16 )
				<< str_segment_flag( seg->get_flags() ) << " " << std::endl
				<< "                       " << DUMP_HEX_FORMAT( 16 )
				<< seg->get_file_size() << " " << DUMP_HEX_FORMAT( 16 )
				<< seg->get_memory_size() << " " << DUMP_HEX_FORMAT( 16 )
				<< seg->get_align() << " " << std::endl;
		}

		out.flags( original_flags );
	}

	//------------------------------------------------------------------------------
	static void symbol_tables( std::ostream& out, const elfio& reader )
	{
		Elf_Half n = reader.sections.size();
		for ( Elf_Half i = 0; i < n; ++i ) { // For all sections
			section* sec = reader.sections[i];
			if ( SHT_SYMTAB == sec->get_type() ||
				 SHT_DYNSYM == sec->get_type() ) {
				symbol_section_accessor symbols( reader, sec );

				Elf_Xword sym_no = symbols.get_symbols_num();
				if ( sym_no > 0 ) {
					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;
				}
			}
		}
	}

	//------------------------------------------------------------------------------
	static void symbol_table( std::ostream& out,
							  Elf_Xword     no,
							  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_HEX_FORMAT( 8 ) << value << " " << DUMP_HEX_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_HEX_FORMAT( 16 ) << value << " "
				<< DUMP_HEX_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 );
	}

	//------------------------------------------------------------------------------
	static void notes( std::ostream& out, const elfio& reader )
	{
		Elf_Half no = reader.sections.size();
		for ( Elf_Half i = 0; i < no; ++i ) { // For all sections
			section* sec = reader.sections[i];
			if ( SHT_NOTE == sec->get_type() ) { // Look at notes
				note_section_accessor notes( reader, sec );
				Elf_Word              no_notes = notes.get_notes_num();
				if ( no > 0 ) {
					out << "Note section (" << sec->get_name() << ")"
						<< std::endl
						<< "    No Type     Name" << std::endl;
					for ( Elf_Word j = 0; j < no_notes; ++j ) { // For all notes
						Elf_Word    type;
						std::string name;
						void*       desc;
						Elf_Word    descsz;

						if ( notes.get_note( j, type, name, desc, descsz ) ) {
							// 'name' usually contains \0 at the end. Try to fix it
							name = name.c_str();
							note( out, j, type, name );
						}
					}

					out << std::endl;
				}
			}
		}
	}

	//------------------------------------------------------------------------------
	static void modinfo( std::ostream& out, const elfio& reader )
	{
		Elf_Half no = reader.sections.size();
		for ( Elf_Half i = 0; i < no; ++i ) { // For all sections
			section* sec = reader.sections[i];
			if ( ".modinfo" == sec->get_name() ) { // Look for the section
				out << "Section .modinfo" << std::endl;

				const_modinfo_section_accessor modinfo( sec );
				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;
			}
		}
	}

	//------------------------------------------------------------------------------
	static void
	note( std::ostream& out, int no, Elf_Word type, const std::string& name )
	{
		out << "  [" << DUMP_DEC_FORMAT( 2 ) << no << "] "
			<< DUMP_HEX_FORMAT( 8 ) << type << " " << DUMP_STR_FORMAT( 1 )
			<< name << std::endl;
	}

	//------------------------------------------------------------------------------
	static void dynamic_tags( std::ostream& out, const elfio& reader )
	{
		Elf_Half n = reader.sections.size();
		for ( Elf_Half i = 0; i < n; ++i ) { // For all sections
			section* sec = reader.sections[i];
			if ( SHT_DYNAMIC == sec->get_type() ) {
				dynamic_section_accessor dynamic( reader, sec );

				Elf_Xword dyn_no = dynamic.get_entries_num();
				if ( dyn_no > 0 ) {
					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() );
						if ( DT_NULL == tag ) {
							break;
						}
					}

					out << std::endl;
				}
			}
		}
	}

	//------------------------------------------------------------------------------
	static void dynamic_tag( std::ostream& out,
							 Elf_Xword     no,
							 Elf_Xword     tag,
							 Elf_Xword     value,
							 std::string   str,
							 unsigned int /*elf_class*/ )
	{
		out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] "
			<< DUMP_STR_FORMAT( 16 ) << str_dynamic_tag( tag ) << " ";
		if ( str.empty() ) {
			out << DUMP_HEX_FORMAT( 16 ) << value << " ";
		}
		else {
			out << DUMP_STR_FORMAT( 32 ) << str << " ";
		}
		out << std::endl;
	}

	//------------------------------------------------------------------------------
	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_HEX_FORMAT( 8 ) << i << "]";
				}

				out << " " << DUMP_HEX_FORMAT( 2 ) << ( pdata[i] & 0x000000FF );

				if ( i % 16 == 15 ) {
					out << std::endl;
				}
			}
			if ( i % 16 != 0 ) {
				out << std::endl;
			}

			out.flags( original_flags );
		}

		return;
	}

	//------------------------------------------------------------------------------
	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
			section* sec = reader.sections[i];
			if ( sec->get_type() == SHT_NOBITS ) {
				continue;
			}
			section_data( out, sec );
		}

		out << std::endl;
	}

	//------------------------------------------------------------------------------
	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_HEX_FORMAT( 8 ) << i << "]";
				}

				out << " " << DUMP_HEX_FORMAT( 2 ) << ( pdata[i] & 0x000000FF );

				if ( i % 16 == 15 ) {
					out << std::endl;
				}
			}
			if ( i % 16 != 0 ) {
				out << std::endl;
			}

			out.flags( original_flags );
		}

		return;
	}

	//------------------------------------------------------------------------------
	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
			segment* seg = reader.segments[i];
			segment_data( out, i, seg );
		}

		out << std::endl;
	}

  private:
	//------------------------------------------------------------------------------
	template <typename T, typename K>
	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 <typename T, typename K>
	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 <typename T>
	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";
		}

		return ret;
	}

//------------------------------------------------------------------------------
#define STR_FUNC_TABLE( name )                                         \
	template <typename T> 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( 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
#undef DUMP_DEC_FORMAT
#undef DUMP_HEX_FORMAT
#undef DUMP_STR_FORMAT
}; // class dump

}; // namespace ELFIO

#endif // ELFIO_DUMP_HPP

/*** End of inlined file: elfio_dump.hpp ***/

