| /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying | 
 |    file LICENSE.rst or https://cmake.org/licensing for details.  */ | 
 | #include "cmELF.h" | 
 |  | 
 | #include <cstddef> | 
 | #include <cstdint> | 
 | #include <map> | 
 | #include <memory> | 
 | #include <sstream> | 
 | #include <utility> | 
 | #include <vector> | 
 |  | 
 | #include <cm/memory> | 
 | #include <cmext/algorithm> | 
 |  | 
 | #include <cm3p/kwiml/abi.h> | 
 |  | 
 | #include "cmsys/FStream.hxx" | 
 |  | 
 | #include "cmelf/elf32.h" | 
 | #include "cmelf/elf64.h" | 
 | #include "cmelf/elf_common.h" | 
 |  | 
 | // Low-level byte swapping implementation. | 
 | template <size_t s> | 
 | struct cmELFByteSwapSize | 
 | { | 
 | }; | 
 | static void cmELFByteSwap(char* data, cmELFByteSwapSize<2> /*unused*/) | 
 | { | 
 |   char one_byte; | 
 |   one_byte = data[0]; | 
 |   data[0] = data[1]; | 
 |   data[1] = one_byte; | 
 | } | 
 | static void cmELFByteSwap(char* data, cmELFByteSwapSize<4> /*unused*/) | 
 | { | 
 |   char one_byte; | 
 |   one_byte = data[0]; | 
 |   data[0] = data[3]; | 
 |   data[3] = one_byte; | 
 |   one_byte = data[1]; | 
 |   data[1] = data[2]; | 
 |   data[2] = one_byte; | 
 | } | 
 | static void cmELFByteSwap(char* data, cmELFByteSwapSize<8> /*unused*/) | 
 | { | 
 |   char one_byte; | 
 |   one_byte = data[0]; | 
 |   data[0] = data[7]; | 
 |   data[7] = one_byte; | 
 |   one_byte = data[1]; | 
 |   data[1] = data[6]; | 
 |   data[6] = one_byte; | 
 |   one_byte = data[2]; | 
 |   data[2] = data[5]; | 
 |   data[5] = one_byte; | 
 |   one_byte = data[3]; | 
 |   data[3] = data[4]; | 
 |   data[4] = one_byte; | 
 | } | 
 |  | 
 | // Low-level byte swapping interface. | 
 | template <typename T> | 
 | void cmELFByteSwap(T& x) | 
 | { | 
 |   cmELFByteSwap(reinterpret_cast<char*>(&x), cmELFByteSwapSize<sizeof(T)>()); | 
 | } | 
 |  | 
 | class cmELFInternal | 
 | { | 
 | public: | 
 |   using StringEntry = cmELF::StringEntry; | 
 |   enum ByteOrderType | 
 |   { | 
 |     ByteOrderMSB, | 
 |     ByteOrderLSB | 
 |   }; | 
 |  | 
 |   // Construct and take ownership of the file stream object. | 
 |   cmELFInternal(cmELF* external, std::unique_ptr<std::istream> fin, | 
 |                 ByteOrderType order) | 
 |     : External(external) | 
 |     , Stream(std::move(fin)) | 
 |     , ByteOrder(order) | 
 |   { | 
 | // In most cases the processor-specific byte order will match that | 
 | // of the target execution environment.  If we choose wrong here | 
 | // it is fixed when the header is read. | 
 | #if KWIML_ABI_ENDIAN_ID == KWIML_ABI_ENDIAN_ID_LITTLE | 
 |     this->NeedSwap = (this->ByteOrder == ByteOrderMSB); | 
 | #elif KWIML_ABI_ENDIAN_ID == KWIML_ABI_ENDIAN_ID_BIG | 
 |     this->NeedSwap = (this->ByteOrder == ByteOrderLSB); | 
 | #else | 
 |     this->NeedSwap = false; // Final decision is at runtime anyway. | 
 | #endif | 
 |  | 
 |     // We have not yet loaded the section info. | 
 |     this->DynamicSectionIndex = -1; | 
 |   } | 
 |  | 
 |   // Destruct and delete the file stream object. | 
 |   virtual ~cmELFInternal() = default; | 
 |  | 
 |   // Forward to the per-class implementation. | 
 |   virtual unsigned int GetNumberOfSections() const = 0; | 
 |   virtual unsigned long GetDynamicEntryPosition(int j) = 0; | 
 |   virtual cmELF::DynamicEntryList GetDynamicEntries() = 0; | 
 |   virtual std::vector<char> EncodeDynamicEntries( | 
 |     cmELF::DynamicEntryList const&) = 0; | 
 |   virtual StringEntry const* GetDynamicSectionString(unsigned int tag) = 0; | 
 |   virtual bool IsMips() const = 0; | 
 |   virtual void PrintInfo(std::ostream& os) const = 0; | 
 |  | 
 |   /** Returns true if the ELF file has a dynamic section **/ | 
 |   bool HasDynamicSection() const { return this->DynamicSectionIndex >= 0; } | 
 |  | 
 |   // Lookup the SONAME in the DYNAMIC section. | 
 |   StringEntry const* GetSOName() | 
 |   { | 
 |     return this->GetDynamicSectionString(DT_SONAME); | 
 |   } | 
 |  | 
 |   // Lookup the RPATH in the DYNAMIC section. | 
 |   StringEntry const* GetRPath() | 
 |   { | 
 |     return this->GetDynamicSectionString(DT_RPATH); | 
 |   } | 
 |  | 
 |   // Lookup the RUNPATH in the DYNAMIC section. | 
 |   StringEntry const* GetRunPath() | 
 |   { | 
 |     return this->GetDynamicSectionString(DT_RUNPATH); | 
 |   } | 
 |  | 
 |   // Return the recorded ELF type. | 
 |   cmELF::FileType GetFileType() const { return this->ELFType; } | 
 |  | 
 |   // Return the recorded machine. | 
 |   std::uint16_t GetMachine() const { return this->Machine; } | 
 |  | 
 | protected: | 
 |   // Data common to all ELF class implementations. | 
 |  | 
 |   // The external cmELF object. | 
 |   cmELF* External; | 
 |  | 
 |   // The stream from which to read. | 
 |   std::unique_ptr<std::istream> Stream; | 
 |  | 
 |   // The byte order of the ELF file. | 
 |   ByteOrderType ByteOrder; | 
 |  | 
 |   // The ELF file type. | 
 |   cmELF::FileType ELFType = cmELF::FileTypeInvalid; | 
 |  | 
 |   // The ELF architecture. | 
 |   std::uint16_t Machine; | 
 |  | 
 |   // Whether we need to byte-swap structures read from the stream. | 
 |   bool NeedSwap; | 
 |  | 
 |   // The section header index of the DYNAMIC section (-1 if none). | 
 |   int DynamicSectionIndex; | 
 |  | 
 |   // Helper methods for subclasses. | 
 |   void SetErrorMessage(char const* msg) | 
 |   { | 
 |     this->External->ErrorMessage = msg; | 
 |     this->ELFType = cmELF::FileTypeInvalid; | 
 |   } | 
 |  | 
 |   // Store string table entry states. | 
 |   std::map<unsigned int, StringEntry> DynamicSectionStrings; | 
 | }; | 
 |  | 
 | // Configure the implementation template for 32-bit ELF files. | 
 | struct cmELFTypes32 | 
 | { | 
 |   using ELF_Ehdr = Elf32_Ehdr; | 
 |   using ELF_Shdr = Elf32_Shdr; | 
 |   using ELF_Dyn = Elf32_Dyn; | 
 |   using ELF_Half = Elf32_Half; | 
 |   using tagtype = ::uint32_t; | 
 |   static char const* GetName() { return "32-bit"; } | 
 | }; | 
 |  | 
 | // Configure the implementation template for 64-bit ELF files. | 
 | struct cmELFTypes64 | 
 | { | 
 |   using ELF_Ehdr = Elf64_Ehdr; | 
 |   using ELF_Shdr = Elf64_Shdr; | 
 |   using ELF_Dyn = Elf64_Dyn; | 
 |   using ELF_Half = Elf64_Half; | 
 |   using tagtype = ::uint64_t; | 
 |   static char const* GetName() { return "64-bit"; } | 
 | }; | 
 |  | 
 | // Parser implementation template. | 
 | template <class Types> | 
 | class cmELFInternalImpl : public cmELFInternal | 
 | { | 
 | public: | 
 |   // Copy the ELF file format types from our configuration parameter. | 
 |   using ELF_Ehdr = typename Types::ELF_Ehdr; | 
 |   using ELF_Shdr = typename Types::ELF_Shdr; | 
 |   using ELF_Dyn = typename Types::ELF_Dyn; | 
 |   using ELF_Half = typename Types::ELF_Half; | 
 |   using tagtype = typename Types::tagtype; | 
 |  | 
 |   // Construct with a stream and byte swap indicator. | 
 |   cmELFInternalImpl(cmELF* external, std::unique_ptr<std::istream> fin, | 
 |                     ByteOrderType order); | 
 |  | 
 |   // Return the number of sections as specified by the ELF header. | 
 |   unsigned int GetNumberOfSections() const override | 
 |   { | 
 |     return static_cast<unsigned int>(this->ELFHeader.e_shnum + | 
 |                                      this->SectionHeaders[0].sh_size); | 
 |   } | 
 |  | 
 |   // Get the file position of a dynamic section entry. | 
 |   unsigned long GetDynamicEntryPosition(int j) override; | 
 |  | 
 |   cmELF::DynamicEntryList GetDynamicEntries() override; | 
 |   std::vector<char> EncodeDynamicEntries( | 
 |     cmELF::DynamicEntryList const&) override; | 
 |  | 
 |   // Lookup a string from the dynamic section with the given tag. | 
 |   StringEntry const* GetDynamicSectionString(unsigned int tag) override; | 
 |  | 
 |   bool IsMips() const override { return this->ELFHeader.e_machine == EM_MIPS; } | 
 |  | 
 |   // Print information about the ELF file. | 
 |   void PrintInfo(std::ostream& os) const override | 
 |   { | 
 |     os << "ELF " << Types::GetName(); | 
 |     if (this->ByteOrder == ByteOrderMSB) { | 
 |       os << " MSB"; | 
 |     } else if (this->ByteOrder == ByteOrderLSB) { | 
 |       os << " LSB"; | 
 |     } | 
 |     switch (this->ELFType) { | 
 |       case cmELF::FileTypeInvalid: | 
 |         os << " invalid file"; | 
 |         break; | 
 |       case cmELF::FileTypeRelocatableObject: | 
 |         os << " relocatable object"; | 
 |         break; | 
 |       case cmELF::FileTypeExecutable: | 
 |         os << " executable"; | 
 |         break; | 
 |       case cmELF::FileTypeSharedLibrary: | 
 |         os << " shared library"; | 
 |         break; | 
 |       case cmELF::FileTypeCore: | 
 |         os << " core file"; | 
 |         break; | 
 |       case cmELF::FileTypeSpecificOS: | 
 |         os << " os-specific type"; | 
 |         break; | 
 |       case cmELF::FileTypeSpecificProc: | 
 |         os << " processor-specific type"; | 
 |         break; | 
 |     } | 
 |     os << "\n"; | 
 |   } | 
 |  | 
 | private: | 
 |   static_assert(sizeof(ELF_Dyn().d_un.d_val) == sizeof(ELF_Dyn().d_un.d_ptr), | 
 |                 "ByteSwap(ELF_Dyn) assumes d_val and d_ptr are the same size"); | 
 |  | 
 |   void ByteSwap(ELF_Ehdr& elf_header) | 
 |   { | 
 |     cmELFByteSwap(elf_header.e_type); | 
 |     cmELFByteSwap(elf_header.e_machine); | 
 |     cmELFByteSwap(elf_header.e_version); | 
 |     cmELFByteSwap(elf_header.e_entry); | 
 |     cmELFByteSwap(elf_header.e_phoff); | 
 |     cmELFByteSwap(elf_header.e_shoff); | 
 |     cmELFByteSwap(elf_header.e_flags); | 
 |     cmELFByteSwap(elf_header.e_ehsize); | 
 |     cmELFByteSwap(elf_header.e_phentsize); | 
 |     cmELFByteSwap(elf_header.e_phnum); | 
 |     cmELFByteSwap(elf_header.e_shentsize); | 
 |     cmELFByteSwap(elf_header.e_shnum); | 
 |     cmELFByteSwap(elf_header.e_shstrndx); | 
 |   } | 
 |  | 
 |   void ByteSwap(ELF_Shdr& sec_header) | 
 |   { | 
 |     cmELFByteSwap(sec_header.sh_name); | 
 |     cmELFByteSwap(sec_header.sh_type); | 
 |     cmELFByteSwap(sec_header.sh_flags); | 
 |     cmELFByteSwap(sec_header.sh_addr); | 
 |     cmELFByteSwap(sec_header.sh_offset); | 
 |     cmELFByteSwap(sec_header.sh_size); | 
 |     cmELFByteSwap(sec_header.sh_link); | 
 |     cmELFByteSwap(sec_header.sh_info); | 
 |     cmELFByteSwap(sec_header.sh_addralign); | 
 |     cmELFByteSwap(sec_header.sh_entsize); | 
 |   } | 
 |  | 
 |   void ByteSwap(ELF_Dyn& dyn) | 
 |   { | 
 |     cmELFByteSwap(dyn.d_tag); | 
 |     cmELFByteSwap(dyn.d_un.d_val); | 
 |   } | 
 |  | 
 |   bool FileTypeValid(ELF_Half et) | 
 |   { | 
 |     unsigned int eti = static_cast<unsigned int>(et); | 
 |     if (eti == ET_NONE || eti == ET_REL || eti == ET_EXEC || eti == ET_DYN || | 
 |         eti == ET_CORE) { | 
 |       return true; | 
 |     } | 
 |     if (eti >= ET_LOOS && eti <= ET_HIOS) { | 
 |       return true; | 
 |     } | 
 |     if (eti >= ET_LOPROC && eti <= ET_HIPROC) { | 
 |       return true; | 
 |     } | 
 |     return false; | 
 |   } | 
 |  | 
 |   bool Read(ELF_Ehdr& x) | 
 |   { | 
 |     // Read the header from the file. | 
 |     if (!this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x))) { | 
 |       return false; | 
 |     } | 
 |  | 
 |     // The byte order of ELF header fields may not match that of the | 
 |     // processor-specific data.  The header fields are ordered to | 
 |     // match the target execution environment, so we may need to | 
 |     // memorize the order of all platforms based on the e_machine | 
 |     // value.  As a heuristic, if the type is invalid but its | 
 |     // swapped value is okay then flip our swap mode. | 
 |     ELF_Half et = x.e_type; | 
 |     if (this->NeedSwap) { | 
 |       cmELFByteSwap(et); | 
 |     } | 
 |     if (!this->FileTypeValid(et)) { | 
 |       cmELFByteSwap(et); | 
 |       if (this->FileTypeValid(et)) { | 
 |         // The previous byte order guess was wrong.  Flip it. | 
 |         this->NeedSwap = !this->NeedSwap; | 
 |       } | 
 |     } | 
 |  | 
 |     // Fix the byte order of the header. | 
 |     if (this->NeedSwap) { | 
 |       this->ByteSwap(x); | 
 |     } | 
 |     return true; | 
 |   } | 
 |   bool Read(ELF_Shdr& x) | 
 |   { | 
 |     if (this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)) && | 
 |         this->NeedSwap) { | 
 |       this->ByteSwap(x); | 
 |     } | 
 |     return !this->Stream->fail(); | 
 |   } | 
 |   bool Read(ELF_Dyn& x) | 
 |   { | 
 |     if (this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)) && | 
 |         this->NeedSwap) { | 
 |       this->ByteSwap(x); | 
 |     } | 
 |     return !this->Stream->fail(); | 
 |   } | 
 |  | 
 |   bool LoadSectionHeader(unsigned int i) | 
 |   { | 
 |     // Read the section header from the file. | 
 |     this->Stream->seekg(this->ELFHeader.e_shoff + | 
 |                         this->ELFHeader.e_shentsize * i); | 
 |     if (!this->Read(this->SectionHeaders[i])) { | 
 |       return false; | 
 |     } | 
 |  | 
 |     // Identify some important sections. | 
 |     if (this->SectionHeaders[i].sh_type == SHT_DYNAMIC) { | 
 |       this->DynamicSectionIndex = static_cast<int>(i); | 
 |     } | 
 |     return true; | 
 |   } | 
 |  | 
 |   bool LoadDynamicSection(); | 
 |  | 
 |   // Store the main ELF header. | 
 |   ELF_Ehdr ELFHeader; | 
 |  | 
 |   // Store all the section headers. | 
 |   std::vector<ELF_Shdr> SectionHeaders; | 
 |  | 
 |   // Store all entries of the DYNAMIC section. | 
 |   std::vector<ELF_Dyn> DynamicSectionEntries; | 
 | }; | 
 |  | 
 | template <class Types> | 
 | cmELFInternalImpl<Types>::cmELFInternalImpl(cmELF* external, | 
 |                                             std::unique_ptr<std::istream> fin, | 
 |                                             ByteOrderType order) | 
 |   : cmELFInternal(external, std::move(fin), order) | 
 | { | 
 |   // Read the main header. | 
 |   if (!this->Read(this->ELFHeader)) { | 
 |     this->SetErrorMessage("Failed to read main ELF header."); | 
 |     return; | 
 |   } | 
 |  | 
 |   // Determine the ELF file type. | 
 |   switch (this->ELFHeader.e_type) { | 
 |     case ET_NONE: | 
 |       this->SetErrorMessage("ELF file type is NONE."); | 
 |       return; | 
 |     case ET_REL: | 
 |       this->ELFType = cmELF::FileTypeRelocatableObject; | 
 |       break; | 
 |     case ET_EXEC: | 
 |       this->ELFType = cmELF::FileTypeExecutable; | 
 |       break; | 
 |     case ET_DYN: | 
 |       this->ELFType = cmELF::FileTypeSharedLibrary; | 
 |       break; | 
 |     case ET_CORE: | 
 |       this->ELFType = cmELF::FileTypeCore; | 
 |       break; | 
 |     default: { | 
 |       unsigned int eti = static_cast<unsigned int>(this->ELFHeader.e_type); | 
 |       if (eti >= ET_LOOS && eti <= ET_HIOS) { | 
 |         this->ELFType = cmELF::FileTypeSpecificOS; | 
 |         break; | 
 |       } | 
 |       if (eti >= ET_LOPROC && eti <= ET_HIPROC) { | 
 |         this->ELFType = cmELF::FileTypeSpecificProc; | 
 |         break; | 
 |       } | 
 |       std::ostringstream e; | 
 |       e << "Unknown ELF file type " << eti; | 
 |       this->SetErrorMessage(e.str().c_str()); | 
 |       return; | 
 |     } | 
 |   } | 
 |  | 
 |   this->Machine = this->ELFHeader.e_machine; | 
 |  | 
 |   // Load the section headers. | 
 |   this->SectionHeaders.resize( | 
 |     this->ELFHeader.e_shnum == 0 ? 1 : this->ELFHeader.e_shnum); | 
 |   this->LoadSectionHeader(0); | 
 |   this->SectionHeaders.resize(this->GetNumberOfSections()); | 
 |   for (unsigned int i = 1; i < this->GetNumberOfSections(); ++i) { | 
 |     if (!this->LoadSectionHeader(i)) { | 
 |       this->SetErrorMessage("Failed to load section headers."); | 
 |       return; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | template <class Types> | 
 | bool cmELFInternalImpl<Types>::LoadDynamicSection() | 
 | { | 
 |   // If there is no dynamic section we are done. | 
 |   if (!this->HasDynamicSection()) { | 
 |     return false; | 
 |   } | 
 |  | 
 |   // If the section was already loaded we are done. | 
 |   if (!this->DynamicSectionEntries.empty()) { | 
 |     return true; | 
 |   } | 
 |  | 
 |   // If there are no entries we are done. | 
 |   ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex]; | 
 |   if (sec.sh_entsize == 0) { | 
 |     return false; | 
 |   } | 
 |  | 
 |   // Allocate the dynamic section entries. | 
 |   int n = static_cast<int>(sec.sh_size / sec.sh_entsize); | 
 |   this->DynamicSectionEntries.resize(n); | 
 |  | 
 |   // Read each entry. | 
 |   for (int j = 0; j < n; ++j) { | 
 |     // Seek to the beginning of the section entry. | 
 |     this->Stream->seekg(sec.sh_offset + sec.sh_entsize * j); | 
 |     ELF_Dyn& dyn = this->DynamicSectionEntries[j]; | 
 |  | 
 |     // Try reading the entry. | 
 |     if (!this->Read(dyn)) { | 
 |       this->SetErrorMessage("Error reading entry from DYNAMIC section."); | 
 |       this->DynamicSectionIndex = -1; | 
 |       return false; | 
 |     } | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | template <class Types> | 
 | unsigned long cmELFInternalImpl<Types>::GetDynamicEntryPosition(int j) | 
 | { | 
 |   if (!this->LoadDynamicSection()) { | 
 |     return 0; | 
 |   } | 
 |   if (j < 0 || j >= static_cast<int>(this->DynamicSectionEntries.size())) { | 
 |     return 0; | 
 |   } | 
 |   ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex]; | 
 |   return sec.sh_offset + sec.sh_entsize * static_cast<unsigned long>(j); | 
 | } | 
 |  | 
 | template <class Types> | 
 | cmELF::DynamicEntryList cmELFInternalImpl<Types>::GetDynamicEntries() | 
 | { | 
 |   cmELF::DynamicEntryList result; | 
 |  | 
 |   // Ensure entries have been read from file | 
 |   if (!this->LoadDynamicSection()) { | 
 |     return result; | 
 |   } | 
 |  | 
 |   // Copy into public array | 
 |   result.reserve(this->DynamicSectionEntries.size()); | 
 |   for (ELF_Dyn& dyn : this->DynamicSectionEntries) { | 
 |     result.emplace_back(dyn.d_tag, dyn.d_un.d_val); | 
 |   } | 
 |  | 
 |   return result; | 
 | } | 
 |  | 
 | template <class Types> | 
 | std::vector<char> cmELFInternalImpl<Types>::EncodeDynamicEntries( | 
 |   cmELF::DynamicEntryList const& entries) | 
 | { | 
 |   std::vector<char> result; | 
 |   result.reserve(sizeof(ELF_Dyn) * entries.size()); | 
 |  | 
 |   for (auto const& entry : entries) { | 
 |     // Store the entry in an ELF_Dyn, byteswap it, then serialize to chars | 
 |     ELF_Dyn dyn; | 
 |     dyn.d_tag = static_cast<tagtype>(entry.first); | 
 |     dyn.d_un.d_val = static_cast<tagtype>(entry.second); | 
 |  | 
 |     if (this->NeedSwap) { | 
 |       this->ByteSwap(dyn); | 
 |     } | 
 |  | 
 |     char* pdyn = reinterpret_cast<char*>(&dyn); | 
 |     cm::append(result, pdyn, pdyn + sizeof(ELF_Dyn)); | 
 |   } | 
 |  | 
 |   return result; | 
 | } | 
 |  | 
 | template <class Types> | 
 | cmELF::StringEntry const* cmELFInternalImpl<Types>::GetDynamicSectionString( | 
 |   unsigned int tag) | 
 | { | 
 |   // Short-circuit if already checked. | 
 |   auto dssi = this->DynamicSectionStrings.find(tag); | 
 |   if (dssi != this->DynamicSectionStrings.end()) { | 
 |     if (dssi->second.Position > 0) { | 
 |       return &dssi->second; | 
 |     } | 
 |     return nullptr; | 
 |   } | 
 |  | 
 |   // Create an entry for this tag.  Assume it is missing until found. | 
 |   StringEntry& se = this->DynamicSectionStrings[tag]; | 
 |   se.Position = 0; | 
 |   se.Size = 0; | 
 |   se.IndexInSection = -1; | 
 |  | 
 |   // Try reading the dynamic section. | 
 |   if (!this->LoadDynamicSection()) { | 
 |     return nullptr; | 
 |   } | 
 |  | 
 |   // Get the string table referenced by the DYNAMIC section. | 
 |   ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex]; | 
 |   if (sec.sh_link >= this->SectionHeaders.size()) { | 
 |     this->SetErrorMessage("Section DYNAMIC has invalid string table index."); | 
 |     return nullptr; | 
 |   } | 
 |   ELF_Shdr const& strtab = this->SectionHeaders[sec.sh_link]; | 
 |  | 
 |   // Look for the requested entry. | 
 |   for (auto di = this->DynamicSectionEntries.begin(); | 
 |        di != this->DynamicSectionEntries.end(); ++di) { | 
 |     ELF_Dyn& dyn = *di; | 
 |     if (static_cast<tagtype>(dyn.d_tag) == static_cast<tagtype>(tag)) { | 
 |       // We found the tag requested. | 
 |       // Make sure the position given is within the string section. | 
 |       if (dyn.d_un.d_val >= strtab.sh_size) { | 
 |         this->SetErrorMessage("Section DYNAMIC references string beyond " | 
 |                               "the end of its string section."); | 
 |         return nullptr; | 
 |       } | 
 |  | 
 |       // Seek to the position reported by the entry. | 
 |       unsigned long first = static_cast<unsigned long>(dyn.d_un.d_val); | 
 |       unsigned long last = first; | 
 |       unsigned long end = static_cast<unsigned long>(strtab.sh_size); | 
 |       this->Stream->seekg(strtab.sh_offset + first); | 
 |  | 
 |       // Read the string.  It may be followed by more than one NULL | 
 |       // terminator.  Count the total size of the region allocated to | 
 |       // the string.  This assumes that the next string in the table | 
 |       // is non-empty, but the "chrpath" tool makes the same | 
 |       // assumption. | 
 |       bool terminated = false; | 
 |       char c; | 
 |       while (last != end && this->Stream->get(c) && !(terminated && c)) { | 
 |         ++last; | 
 |         if (c) { | 
 |           se.Value += c; | 
 |         } else { | 
 |           terminated = true; | 
 |         } | 
 |       } | 
 |  | 
 |       // Make sure the whole value was read. | 
 |       if (!(*this->Stream)) { | 
 |         if (tag == cmELF::TagRPath) { | 
 |           this->SetErrorMessage( | 
 |             "Dynamic section specifies unreadable DT_RPATH"); | 
 |         } else if (tag == cmELF::TagRunPath) { | 
 |           this->SetErrorMessage( | 
 |             "Dynamic section specifies unreadable DT_RUNPATH"); | 
 |         } else if (tag == cmELF::TagMipsRldMapRel) { | 
 |           this->SetErrorMessage( | 
 |             "Dynamic section specifies unreadable DT_MIPS_RLD_MAP_REL"); | 
 |         } else { | 
 |           this->SetErrorMessage("Dynamic section specifies unreadable value" | 
 |                                 " for unexpected attribute"); | 
 |         } | 
 |         se.Value = ""; | 
 |         return nullptr; | 
 |       } | 
 |  | 
 |       // The value has been read successfully.  Report it. | 
 |       se.Position = static_cast<unsigned long>(strtab.sh_offset + first); | 
 |       se.Size = last - first; | 
 |       se.IndexInSection = | 
 |         static_cast<int>(di - this->DynamicSectionEntries.begin()); | 
 |       return &se; | 
 |     } | 
 |   } | 
 |   return nullptr; | 
 | } | 
 |  | 
 | //============================================================================ | 
 | // External class implementation. | 
 |  | 
 | long const cmELF::TagRPath = DT_RPATH; | 
 | long const cmELF::TagRunPath = DT_RUNPATH; | 
 | long const cmELF::TagMipsRldMapRel = DT_MIPS_RLD_MAP_REL; | 
 |  | 
 | cmELF::cmELF(char const* fname) | 
 | { | 
 |   // Try to open the file. | 
 |   auto fin = cm::make_unique<cmsys::ifstream>(fname, std::ios::binary); | 
 |  | 
 |   // Quit now if the file could not be opened. | 
 |   if (!fin || !*fin) { | 
 |     this->ErrorMessage = "Error opening input file."; | 
 |     return; | 
 |   } | 
 |  | 
 |   // Read the ELF identification block. | 
 |   char ident[EI_NIDENT]; | 
 |   if (!fin->read(ident, EI_NIDENT)) { | 
 |     this->ErrorMessage = "Error reading ELF identification."; | 
 |     return; | 
 |   } | 
 |   if (!fin->seekg(0)) { | 
 |     this->ErrorMessage = "Error seeking to beginning of file."; | 
 |     return; | 
 |   } | 
 |  | 
 |   // Verify the ELF identification. | 
 |   if (!(ident[EI_MAG0] == ELFMAG0 && ident[EI_MAG1] == ELFMAG1 && | 
 |         ident[EI_MAG2] == ELFMAG2 && ident[EI_MAG3] == ELFMAG3)) { | 
 |     this->ErrorMessage = "File does not have a valid ELF identification."; | 
 |     return; | 
 |   } | 
 |  | 
 |   // Check the byte order in which the rest of the file is encoded. | 
 |   cmELFInternal::ByteOrderType order; | 
 |   if (ident[EI_DATA] == ELFDATA2LSB) { | 
 |     // File is LSB. | 
 |     order = cmELFInternal::ByteOrderLSB; | 
 |   } else if (ident[EI_DATA] == ELFDATA2MSB) { | 
 |     // File is MSB. | 
 |     order = cmELFInternal::ByteOrderMSB; | 
 |   } else { | 
 |     this->ErrorMessage = "ELF file is not LSB or MSB encoded."; | 
 |     return; | 
 |   } | 
 |  | 
 |   // Check the class of the file and construct the corresponding | 
 |   // parser implementation. | 
 |   if (ident[EI_CLASS] == ELFCLASS32) { | 
 |     // 32-bit ELF | 
 |     this->Internal = cm::make_unique<cmELFInternalImpl<cmELFTypes32>>( | 
 |       this, std::move(fin), order); | 
 |   } else if (ident[EI_CLASS] == ELFCLASS64) { | 
 |     // 64-bit ELF | 
 |     this->Internal = cm::make_unique<cmELFInternalImpl<cmELFTypes64>>( | 
 |       this, std::move(fin), order); | 
 |   } else { | 
 |     this->ErrorMessage = "ELF file class is not 32-bit or 64-bit."; | 
 |     return; | 
 |   } | 
 | } | 
 |  | 
 | cmELF::~cmELF() = default; | 
 |  | 
 | bool cmELF::Valid() const | 
 | { | 
 |   return this->Internal && this->Internal->GetFileType() != FileTypeInvalid; | 
 | } | 
 |  | 
 | cmELF::FileType cmELF::GetFileType() const | 
 | { | 
 |   if (this->Valid()) { | 
 |     return this->Internal->GetFileType(); | 
 |   } | 
 |   return FileTypeInvalid; | 
 | } | 
 |  | 
 | std::uint16_t cmELF::GetMachine() const | 
 | { | 
 |   if (this->Valid()) { | 
 |     return this->Internal->GetMachine(); | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | unsigned int cmELF::GetNumberOfSections() const | 
 | { | 
 |   if (this->Valid()) { | 
 |     return this->Internal->GetNumberOfSections(); | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | unsigned long cmELF::GetDynamicEntryPosition(int index) const | 
 | { | 
 |   if (this->Valid()) { | 
 |     return this->Internal->GetDynamicEntryPosition(index); | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | cmELF::DynamicEntryList cmELF::GetDynamicEntries() const | 
 | { | 
 |   if (this->Valid()) { | 
 |     return this->Internal->GetDynamicEntries(); | 
 |   } | 
 |  | 
 |   return cmELF::DynamicEntryList(); | 
 | } | 
 |  | 
 | std::vector<char> cmELF::EncodeDynamicEntries( | 
 |   cmELF::DynamicEntryList const& dentries) const | 
 | { | 
 |   if (this->Valid()) { | 
 |     return this->Internal->EncodeDynamicEntries(dentries); | 
 |   } | 
 |  | 
 |   return std::vector<char>(); | 
 | } | 
 |  | 
 | bool cmELF::HasDynamicSection() const | 
 | { | 
 |   return this->Valid() && this->Internal->HasDynamicSection(); | 
 | } | 
 |  | 
 | bool cmELF::GetSOName(std::string& soname) | 
 | { | 
 |   if (StringEntry const* se = this->GetSOName()) { | 
 |     soname = se->Value; | 
 |     return true; | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | cmELF::StringEntry const* cmELF::GetSOName() | 
 | { | 
 |   if (this->Valid() && | 
 |       this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary) { | 
 |     return this->Internal->GetSOName(); | 
 |   } | 
 |   return nullptr; | 
 | } | 
 |  | 
 | cmELF::StringEntry const* cmELF::GetRPath() | 
 | { | 
 |   if (this->Valid() && | 
 |       (this->Internal->GetFileType() == cmELF::FileTypeExecutable || | 
 |        this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary)) { | 
 |     return this->Internal->GetRPath(); | 
 |   } | 
 |   return nullptr; | 
 | } | 
 |  | 
 | cmELF::StringEntry const* cmELF::GetRunPath() | 
 | { | 
 |   if (this->Valid() && | 
 |       (this->Internal->GetFileType() == cmELF::FileTypeExecutable || | 
 |        this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary)) { | 
 |     return this->Internal->GetRunPath(); | 
 |   } | 
 |   return nullptr; | 
 | } | 
 |  | 
 | bool cmELF::IsMIPS() const | 
 | { | 
 |   if (this->Valid()) { | 
 |     return this->Internal->IsMips(); | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | void cmELF::PrintInfo(std::ostream& os) const | 
 | { | 
 |   if (this->Valid()) { | 
 |     this->Internal->PrintInfo(os); | 
 |   } else { | 
 |     os << "Not a valid ELF file.\n"; | 
 |   } | 
 | } |