Index: openmp/libomptarget/plugins/amdgpu/CMakeLists.txt =================================================================== --- openmp/libomptarget/plugins/amdgpu/CMakeLists.txt +++ openmp/libomptarget/plugins/amdgpu/CMakeLists.txt @@ -75,7 +75,9 @@ PRIVATE elf_common hsa-runtime64::hsa-runtime64 - pthread dl elf + dl + ${LIBOMPTARGET_DEP_LIBELF_LIBRARIES} + ${OPENMP_PTHREAD_LIB} "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/../exports" "-Wl,-z,defs" ) Index: openmp/libomptarget/plugins/common/elf_common/CMakeLists.txt =================================================================== --- openmp/libomptarget/plugins/common/elf_common/CMakeLists.txt +++ openmp/libomptarget/plugins/common/elf_common/CMakeLists.txt @@ -10,6 +10,30 @@ # ##===----------------------------------------------------------------------===## -add_library(elf_common INTERFACE) +# Use libelf, is possible. +# Otherwise, use LLVM ELF (unless OPENMP_STANDALONE_BUILD). +option(LIBOMPTARGET_FORCE_LLVM_ELF + "Use LLVM ELFObjectFile implementation for elf_common.\ + This requires in-tree build." OFF) +add_library(elf_common OBJECT elf_common.cpp elf_light.cpp) +if(LIBOMPTARGET_DEP_LIBELF_FOUND AND NOT LIBOMPTARGET_FORCE_LLVM_ELF) + target_compile_definitions(elf_common PRIVATE -DMAY_USE_LIBELF) + target_include_directories(elf_common PRIVATE + ${LIBOMPTARGET_DEP_LIBELF_INCLUDE_DIR}) + target_link_libraries(elf_common INTERFACE + ${LIBOMPTARGET_DEP_LIBELF_LIBRARIES}) +elseif(NOT OPENMP_STANDALONE_BUILD) + llvm_update_compile_flags(elf_common) + set(LINK_LLVM_LIBS LLVMBinaryFormat LLVMObject LLVMSupport) + target_link_libraries(elf_common INTERFACE ${LINK_LLVM_LIBS}) + add_dependencies(elf_common ${LINK_LLVM_LIBS}) +else(LIBOMPTARGET_DEP_LIBELF_FOUND AND NOT LIBOMPTARGET_FORCE_LLVM_ELF) + libomptarget_say("Not building elf_common offload plugin library: libelf dependency not found.") +endif(LIBOMPTARGET_DEP_LIBELF_FOUND AND NOT LIBOMPTARGET_FORCE_LLVM_ELF) + +# The code uses Debug.h, which requires threads support. +target_link_libraries(elf_common INTERFACE ${OPENMP_PTHREAD_LIB}) + +# Expose elf_common.h directory to the users of this library. target_include_directories(elf_common INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) Index: openmp/libomptarget/plugins/common/elf_common/elf_common.h =================================================================== --- openmp/libomptarget/plugins/common/elf_common/elf_common.h +++ openmp/libomptarget/plugins/common/elf_common/elf_common.h @@ -1,4 +1,4 @@ -//===-- elf_common.h - Common ELF functionality -------------------*- C -*-===// +//===-- elf_common.h - Common ELF functionality -----------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -7,105 +7,22 @@ //===----------------------------------------------------------------------===// // // Common ELF functionality for target plugins. -// Must be included in the plugin source file AFTER omptarget.h has been -// included and macro DP(...) has been defined. -// . // //===----------------------------------------------------------------------===// -#if !(defined(_OMPTARGET_DEBUG_H)) -#error Include elf_common.h in the plugin source AFTER Debug.h has\ - been included. -#endif +#ifndef LLVM_OPENMP_LIBOMPTARGET_PLUGINS_COMMON_ELF_COMMON_ELF_COMMON_H +#define LLVM_OPENMP_LIBOMPTARGET_PLUGINS_COMMON_ELF_COMMON_ELF_COMMON_H -#include -#include +#include "elf_constants.h" +#include "omptargetplugin.h" +#include -// Check whether an image is valid for execution on target_id -static inline int32_t elf_check_machine(__tgt_device_image *image, - uint16_t target_id) { +/// Return non-zero, if the given \p image is an ELF object, which +/// e_machine matches \p target_id; return zero otherwise. +EXTERN int32_t elf_check_machine(__tgt_device_image *image, uint16_t target_id); - // Is the library version incompatible with the header file? - if (elf_version(EV_CURRENT) == EV_NONE) { - DP("Incompatible ELF library!\n"); - return 0; - } +/// Return non-zero, if the given \p image is an ET_DYN ELF object; +/// return zero otherwise. +EXTERN int32_t elf_is_dynamic(__tgt_device_image *image); - char *img_begin = (char *)image->ImageStart; - char *img_end = (char *)image->ImageEnd; - size_t img_size = img_end - img_begin; - - // Obtain elf handler - Elf *e = elf_memory(img_begin, img_size); - if (!e) { - DP("Unable to get ELF handle: %s!\n", elf_errmsg(-1)); - return 0; - } - - // Check if ELF is the right kind. - if (elf_kind(e) != ELF_K_ELF) { - DP("Unexpected ELF type!\n"); - elf_end(e); - return 0; - } - Elf64_Ehdr *eh64 = elf64_getehdr(e); - Elf32_Ehdr *eh32 = elf32_getehdr(e); - - if (!eh64 && !eh32) { - DP("Unable to get machine ID from ELF file!\n"); - elf_end(e); - return 0; - } - - uint16_t MachineID; - if (eh64 && !eh32) - MachineID = eh64->e_machine; - else if (eh32 && !eh64) - MachineID = eh32->e_machine; - else { - DP("Ambiguous ELF header!\n"); - elf_end(e); - return 0; - } - - elf_end(e); - return MachineID == target_id; -} - -static inline int32_t elf_is_dynamic(__tgt_device_image *image) { - - char *img_begin = (char *)image->ImageStart; - char *img_end = (char *)image->ImageEnd; - size_t img_size = img_end - img_begin; - - // Obtain elf handler - Elf *e = elf_memory(img_begin, img_size); - if (!e) { - DP("Unable to get ELF handle: %s!\n", elf_errmsg(-1)); - return 0; - } - - Elf64_Ehdr *eh64 = elf64_getehdr(e); - Elf32_Ehdr *eh32 = elf32_getehdr(e); - - if (!eh64 && !eh32) { - DP("Unable to get machine ID from ELF file!\n"); - elf_end(e); - return 0; - } - - uint16_t Type; - if (eh64 && !eh32) - Type = eh64->e_type; - else if (eh32 && !eh64) - Type = eh32->e_type; - else { - DP("Ambiguous ELF header!\n"); - elf_end(e); - return 0; - } - - elf_end(e); - DP("ELF Type: %d\n", Type); - return Type == ET_DYN; -} +#endif // LLVM_OPENMP_LIBOMPTARGET_PLUGINS_COMMON_ELF_COMMON_ELF_COMMON_H Index: openmp/libomptarget/plugins/common/elf_common/elf_common.cpp =================================================================== --- /dev/null +++ openmp/libomptarget/plugins/common/elf_common/elf_common.cpp @@ -0,0 +1,91 @@ +//===-- elf_common.cpp - Common ELF functionality -------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Common ELF functionality for target plugins. +// +//===----------------------------------------------------------------------===// +#include "elf_common.h" +#include "Debug.h" +#include "elf_light.h" + +#ifndef TARGET_NAME +#define TARGET_NAME Common ELF +#endif +#define DEBUG_PREFIX "TARGET " GETNAME(TARGET_NAME) + +#ifdef ELFMAG +// Subtle verification that libelf APIs are not used explicitly here. +// Code here must use libelf independent APIs from elf_light.h. +#error "LIBELF.H cannot be used explicitly here." +#endif // ELFMAG + +EXTERN int32_t elf_check_machine(__tgt_device_image *image, + uint16_t target_id) { + char *img_begin = reinterpret_cast(image->ImageStart); + char *img_end = reinterpret_cast(image->ImageEnd); + size_t img_size = img_end - img_begin; + ElfL E(img_begin, img_size); + if (!E.isValidElf()) { + DP("Unable to get ELF handle: %s!\n", E.getErrmsg(-1)); + return 0; + } + + if (getDebugLevel() > 0) { + auto PrintOutNote = [](const ElfLNote &Note) { + if (Note.getNameSize() == 0) + return; + + // Note that the NameStr below does not include the null + // terminator. + std::string NameStr(Note.getName(), Note.getNameSize()); + if (NameStr != "LLVMOMPOFFLOAD") + return; + + uint64_t Type = Note.getType(); + switch (Type) { + default: + DP("LLVMOMPOFFLOAD ELF note with unknown type %" PRIu64 ".\n", Type); + break; + case NT_LLVM_OPENMP_OFFLOAD_VERSION: + case NT_LLVM_OPENMP_OFFLOAD_PRODUCER: + case NT_LLVM_OPENMP_OFFLOAD_PRODUCER_VERSION: { + std::string DescStr(reinterpret_cast(Note.getDesc()), + Note.getDescSize()); + DP("LLVMOMPOFFLOAD ELF note %s with value: '%s'\n", + OMPNoteTypeNames[Type], DescStr.c_str()); + break; + } + } + }; + + for (auto I = E.section_notes_begin(), IE = E.section_notes_end(); I != IE; + ++I) + PrintOutNote(*I); + + for (auto I = E.segment_notes_begin(), IE = E.segment_notes_end(); I != IE; + ++I) + PrintOutNote(*I); + } + uint16_t MachineID = E.getEMachine(); + return MachineID == target_id; +} + +EXTERN int32_t elf_is_dynamic(__tgt_device_image *image) { + char *img_begin = reinterpret_cast(image->ImageStart); + char *img_end = reinterpret_cast(image->ImageEnd); + size_t img_size = img_end - img_begin; + ElfL E(img_begin, img_size); + if (!E.isValidElf()) { + DP("Unable to get ELF handle: %s!\n", E.getErrmsg(-1)); + return 0; + } + + uint16_t Type = E.getEType(); + DP("ELF Type: %" PRIu16 "\n", Type); + return ElfL::isDynType(Type); +} Index: openmp/libomptarget/plugins/common/elf_common/elf_constants.h =================================================================== --- /dev/null +++ openmp/libomptarget/plugins/common/elf_common/elf_constants.h @@ -0,0 +1,33 @@ +//===-- elf_constants.h - ELF constants -------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Here we duplicate some ELF constants that may not be yet available +// in elf.h or llvm/BinaryFormat/ELF.h (e.g. in an out-of-tree build). +// Note that we use the same constant names as in llvm/BinaryFormat/ELF.h. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OPENMP_LIBOMPTARGET_PLUGINS_COMMON_ELF_COMMON_ELF_CONSTANTS_H +#define LLVM_OPENMP_LIBOMPTARGET_PLUGINS_COMMON_ELF_COMMON_ELF_CONSTANTS_H + +// ELF notes with "LLVMOMPOFFLOAD" name may be of either of these types. +enum : unsigned { + NT_LLVM_OPENMP_OFFLOAD_VERSION = 1, + NT_LLVM_OPENMP_OFFLOAD_PRODUCER = 2, + NT_LLVM_OPENMP_OFFLOAD_PRODUCER_VERSION = 3, + NT_LLVM_OPENMP_OFFLOAD_LAST = NT_LLVM_OPENMP_OFFLOAD_PRODUCER_VERSION +}; + +constexpr const char *OMPNoteTypeNames[NT_LLVM_OPENMP_OFFLOAD_LAST + 1] = { + "NT_LLVM_OPENMP_OFFLOAD_UNKNOWN", + "NT_LLVM_OPENMP_OFFLOAD_VERSION", + "NT_LLVM_OPENMP_OFFLOAD_PRODUCER", + "NT_LLVM_OPENMP_OFFLOAD_PRODUCER_VERSION", +}; + +#endif // LLVM_OPENMP_LIBOMPTARGET_PLUGINS_COMMON_ELF_COMMON_ELF_CONSTANTS_H Index: openmp/libomptarget/plugins/common/elf_common/elf_light.h =================================================================== --- /dev/null +++ openmp/libomptarget/plugins/common/elf_common/elf_light.h @@ -0,0 +1,133 @@ +//===-- elf_light.h - Basic ELF functionality -------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Light ELF implementation provides basic ELF reading functionality. +// It may be used in systems without libelf support, if the corresponding +// LLVM ELF implementation is available. +// The interface declared here must be independent of libelf.h/elf.h. +// +// NOTE: we can try to rely on https://github.com/WolfgangSt/libelf +// on Windows, if this implementation gets more complex. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OPENMP_LIBOMPTARGET_PLUGINS_COMMON_ELF_COMMON_ELF_LIGHT_H +#define LLVM_OPENMP_LIBOMPTARGET_PLUGINS_COMMON_ELF_COMMON_ELF_LIGHT_H + +#include +#include +#include + +class ElfL; +class ElfLSegmentNoteIterator; +class ElfLSectionNoteIterator; +class ElfNote; + +// Class representing NOTEs from PT_NOTE segments and SHT_NOTE sections. +class ElfLNote { + const void *Impl = nullptr; + + friend class ElfLSegmentNoteIterator; + friend class ElfLSectionNoteIterator; + + // Only ElfLSectionNoteIterator is allowed to create notes via its + // operator*(). + explicit ElfLNote(const void *I); + ElfLNote &operator=(const ElfLNote &) = delete; + +public: + // FIXME: add move copy constructor and assignment operator. + ElfLNote(const ElfLNote &); + ~ElfLNote(); + // Returns the note's name size not including the null terminator. + // Note that it may be illegal to access the getName() pointer + // beyond the returned size, i.e. the implementation may + // not guarantee that there is '\0' after getNameSize() + // characters of the name. + uint64_t getNameSize() const; + // Returns a pointer to the beginning of the note's name. + const char *getName() const; + // Returns the number of bytes in the descriptor. + uint64_t getDescSize() const; + // Returns a pointer to the beginning of the note's descriptor. + // It is illegal to access more that getDescSize() bytes + // via this pointer. + const uint8_t *getDesc() const; + uint64_t getType() const; +}; + +// Iterator over NOTEs in PT_NOTE segments. +class ElfLSegmentNoteIterator + : std::iterator { + + void *Impl = nullptr; + + friend class ElfL; + + // Only ElfL is allowed to create iterators to itself. + ElfLSegmentNoteIterator(const void *I, bool IsEnd = false); + ElfLSectionNoteIterator &operator=(const ElfLSegmentNoteIterator &) = delete; + +public: + // FIXME: add move copy constructor and assignment operator. + ElfLSegmentNoteIterator(const ElfLSegmentNoteIterator &Other); + ~ElfLSegmentNoteIterator(); + ElfLSegmentNoteIterator &operator++(); + bool operator==(const ElfLSegmentNoteIterator Other) const; + bool operator!=(const ElfLSegmentNoteIterator Other) const; + ElfLNote operator*() const; +}; + +// Iterator over NOTEs in SHT_NOTE sections. +class ElfLSectionNoteIterator + : std::iterator { + + void *Impl = nullptr; + + friend class ElfL; + + // Only ElfL is allowed to create iterators to itself. + ElfLSectionNoteIterator(const void *I, bool IsEnd = false); + ElfLSectionNoteIterator &operator=(const ElfLSectionNoteIterator &) = delete; + +public: + // FIXME: add move copy constructor and assignment operator. + ElfLSectionNoteIterator(const ElfLSectionNoteIterator &Other); + ~ElfLSectionNoteIterator(); + ElfLSectionNoteIterator &operator++(); + bool operator==(const ElfLSectionNoteIterator Other) const; + bool operator!=(const ElfLSectionNoteIterator Other) const; + ElfLNote operator*() const; +}; + +// Wrapper around the given ELF image. +class ElfL { + // Opaque pointer to the actual implementation. + void *Impl = nullptr; + + // FIXME: implement if needed. + ElfL(const ElfL &) = delete; + ElfL &operator=(const ElfL &) = delete; + +public: + ElfL(char *Begin, size_t Size); + ~ElfL(); + bool isValidElf() const; + const char *getErrmsg(int N) const; + uint16_t getEMachine() const; + uint16_t getEType() const; + + static bool isDynType(uint16_t Ty); + + ElfLSectionNoteIterator section_notes_begin() const; + ElfLSectionNoteIterator section_notes_end() const; + ElfLSegmentNoteIterator segment_notes_begin() const; + ElfLSegmentNoteIterator segment_notes_end() const; +}; + +#endif // LLVM_OPENMP_LIBOMPTARGET_PLUGINS_COMMON_ELF_COMMON_ELF_LIGHT_H Index: openmp/libomptarget/plugins/common/elf_common/elf_light.cpp =================================================================== --- /dev/null +++ openmp/libomptarget/plugins/common/elf_common/elf_light.cpp @@ -0,0 +1,1266 @@ +//===-- elf_light.cpp - Basic ELF functionality -----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "elf_light.h" +#include "Debug.h" +#include + +#ifndef TARGET_NAME +#define TARGET_NAME ELF light +#endif +#define DEBUG_PREFIX "TARGET " GETNAME(TARGET_NAME) + +#if MAY_USE_LIBELF + +// Implementation based on libelf. +#include +#include + +// Helper methods to align addresses. +template inline T alignDown(T value, size_t alignment) { + return (T)(value & ~(alignment - 1)); +} + +template inline T *alignDown(T *value, size_t alignment) { + return reinterpret_cast(alignDown((intptr_t)value, alignment)); +} + +template inline T alignUp(T value, size_t alignment) { + return alignDown((T)(value + alignment - 1), alignment); +} + +template inline T *alignUp(T *value, size_t alignment) { + return reinterpret_cast( + alignDown((intptr_t)(value + alignment - 1), alignment)); +} + +// FIXME: this is taken from openmp/libomptarget/plugins/amdgpu/impl/system.cpp, +// but it may be incorrect for 64-bit ELF. Elf64_Nhdr and Elf32_Nhdr +// have different representation. The alignment used for the name and +// the descriptor is still 4 bytes. At the same time, it seems to work +// for 64-bit ELFs produced by LLVM. +struct Elf_Note { + uint32_t n_namesz; // Length of note's name. + uint32_t n_descsz; // Length of note's value. + uint32_t n_type; // Type of note. + // then name + // then padding, optional + // then desc, at 4 byte alignment (not 8, despite being elf64) +}; + +static const uint32_t NoteAlignment = 4; + +// Implementation of the iterator for SHT_NOTE sections. +// The iterator allows processing all NOTEs in all SHT_NOTE sections +// in the ELF image provided during the iterator object construction. +class ElfLSectionNoteIteratorImpl { + // A pointer to Elf object created by elf_memory() for + // the ELF image we are going to iterate. + Elf *EF; + + // A pointer to the current SHT_NOTE section. + // In the initial state of the iterator object this will actually + // point to the very first section in the ELF image, but it will be + // adjusted right away either to point to the first SHT_NOTE section + // or set to nullptr (if there are no SHT_NOTE sections). + Elf_Scn *CurrentSection = nullptr; + + // A pointer to the current NOTE inside a SHT_NOTE section + // pointed by CurrentSection. If it is nullptr, then this means + // that the iterator object is an end() iterator. + Elf_Note *NPtr = nullptr; + + uint64_t getNotesBeginAddr(const GElf_Shdr &Shdr) const { + return reinterpret_cast(elf_rawfile(EF, nullptr)) + + Shdr.sh_offset; + } + + uint64_t getNotesEndAddr(const GElf_Shdr &Shdr) const { + return getNotesBeginAddr(Shdr) + Shdr.sh_size; + } + + uint64_t getNoteSize(const Elf_Note &Note) const { + return sizeof(Note) + alignUp(Note.n_namesz, NoteAlignment) + + alignUp(Note.n_descsz, NoteAlignment); + } + + // Given the current state of the iterator object, advances + // the iterator forward to point to the next NOTE in the next + // SHT_NOTE section. + // If there is no such a NOTE, then it sets the iterator + // object to the end() state. + // + // Note that this method does not change the iterator, if + // NPtr is pointing to a valid note within CurrentSection. + // The iterator advancement in this case is done via operator++. + void autoAdvance(bool IsFirst = false) { + // Cannot advance, if CurrentSection is NULL. + if (!CurrentSection) + return; + + // NPtr points to a valid NOTE in CurrentSection, thus, + // no auto advancement. + if (NPtr) + return; + + GElf_Shdr Shdr; + gelf_getshdr(CurrentSection, &Shdr); + + // CurrentSection is a valid section, and NPtr is an end() iterator. + // + // If IsFirst is true, then we just in the initial state, and + // we need to set CurrentSection to the first SHT_NOTE section (if any), + // and, then, NPtr to the first note in this section. + // + // If IsFirst is false, then we've reached the end of the current + // SHT_NOTE section, and should find the next section with notes. + if (!IsFirst || gelf_getshdr(CurrentSection, &Shdr)->sh_type != SHT_NOTE) + CurrentSection = elf_nextscn(EF, CurrentSection); + + while (CurrentSection && + gelf_getshdr(CurrentSection, &Shdr)->sh_type != SHT_NOTE) + CurrentSection = elf_nextscn(EF, CurrentSection); + + if (!CurrentSection) { + // No more sections. + // Note that NPtr is already nullptr indicating the end() iterator. + return; + } + + gelf_getshdr(CurrentSection, &Shdr); + uint64_t NotesBegin = getNotesBeginAddr(Shdr); + uint64_t NotesEnd = getNotesEndAddr(Shdr); + if (NotesBegin >= NotesEnd) { + // Something went wrong. Assume that we've reached + // the end of all notes. + CurrentSection = nullptr; + NPtr = nullptr; + return; + } + + NPtr = reinterpret_cast(NotesBegin); + assert(NPtr && "Invalid SHT_NOTE section."); + } + + bool operator!=(const ElfLSectionNoteIteratorImpl Other) const { + return !(*this == Other); + } + +public: + ElfLSectionNoteIteratorImpl(Elf *RawElf, bool IsEnd = false) : EF(RawElf) { + assert(EF && "Trying to iterate invalid ELF."); + + if (IsEnd) { + // NPtr equal to nullptr means end() iterator. + return; + } + + // Set CurrentSection to the very first section, + // and let autoAdvance() find the first valid note (if any). + CurrentSection = elf_getscn(EF, 0); + autoAdvance(true); + } + + bool operator==(const ElfLSectionNoteIteratorImpl Other) const { + // They should be pointing to the same NOTE to be equal. + return NPtr == Other.NPtr; + } + + const Elf_Note *operator*() const { + assert(*this != ElfLSectionNoteIteratorImpl(EF, true) && + "Dereferencing the end iterator."); + return NPtr; + } + + // Advance to the next NOTE in the CurrentSection. + // If there is no next NOTE, then autoAdvance() to the next + // SHT_NOTE section and its first NOTE. + ElfLSectionNoteIteratorImpl &operator++() { + assert(*this != ElfLSectionNoteIteratorImpl(EF, true) && + "Incrementing the end iterator."); + + GElf_Shdr Shdr; + gelf_getshdr(CurrentSection, &Shdr); + uint64_t NotesBegin = getNotesBeginAddr(Shdr); + uint64_t NotesEnd = getNotesEndAddr(Shdr); + assert(reinterpret_cast(NPtr) >= NotesBegin && + reinterpret_cast(NPtr) < NotesEnd && + "Invalid pointer to a note computed somewhere else."); + (void)NotesBegin; + + uint64_t NoteSize = getNoteSize(*NPtr); + NPtr = + reinterpret_cast(reinterpret_cast(NPtr) + NoteSize); + if (reinterpret_cast(NPtr) >= NotesEnd || + reinterpret_cast(NPtr) + sizeof(*NPtr) >= NotesEnd) { + // We've reached the end of the current NOTE section. + NPtr = nullptr; + } + + // Auto advance to the next section, if needed. + autoAdvance(); + return *this; + } +}; + +// Implementation of the iterator for PT_NOTE segments. +// The iterator allows processing all NOTEs in all PT_NOTE segments +// in the ELF image provided during the iterator object construction. +class ElfLSegmentNoteIteratorImpl { + // A pointer to Elf object created by elf_memory() for + // the ELF image we are going to iterate. + Elf *EF; + + // A pointer to the current PT_NOTE segment. + // In the initial state of the iterator object this will actually + // point to the very first segment in the ELF image, but it will be + // adjusted right away either to point to the first PT_NOTE segment + // or set to nullptr (if there are no PT_NOTE segments). + size_t NumberOfPhdrs = (std::numeric_limits::max)(); + size_t CurrentSegment = (std::numeric_limits::max)(); + + // A pointer to the current NOTE inside a PT_NOTE segment + // pointed by CurrentSegment. If it is nullptr, then this means + // that the iterator object is an end() iterator. + Elf_Note *NPtr = nullptr; + + uint64_t getNotesBeginAddr(const GElf_Phdr &Phdr) const { + return reinterpret_cast(elf_rawfile(EF, nullptr)) + Phdr.p_offset; + } + + uint64_t getNotesEndAddr(const GElf_Phdr &Phdr) const { + return getNotesBeginAddr(Phdr) + Phdr.p_filesz; + } + + uint64_t getNoteSize(const Elf_Note &Note) const { + return sizeof(Note) + alignUp(Note.n_namesz, NoteAlignment) + + alignUp(Note.n_descsz, NoteAlignment); + } + + // Given the current state of the iterator object, advances + // the iterator forward to point to the next NOTE in the next + // PT_NOTE segment. + // If there is no such a NOTE, then it sets the iterator + // object to the end() state. + // + // Note that this method does not change the iterator, if + // NPtr is pointing to a valid note within CurrentSegment. + // The iterator advancement in this case is done via operator++. + void autoAdvance(bool IsFirst = false) { + // Cannot advance, if CurrentSegment is invalid. + if (CurrentSegment >= NumberOfPhdrs) + return; + + // NPtr points to a valid NOTE in CurrentSegment, thus, + // no auto advancement. + if (NPtr) + return; + + GElf_Phdr Phdr; + gelf_getphdr(EF, CurrentSegment, &Phdr); + + // CurrentSegment is a valid segment, and NPtr is an end() iterator. + // + // If IsFirst is true, then we just in the initial state, and + // we need to set CurrentSegment to the first PT_NOTE segment (if any), + // and, then, NPtr to the first note in this segment. + // + // If IsFirst is false, then we've reached the end of the current + // PT_NOTE segment, and should find the next segment with notes. + if (!IsFirst || Phdr.p_type != PT_NOTE) + ++CurrentSegment; + + while (CurrentSegment < NumberOfPhdrs) { + if (gelf_getphdr(EF, CurrentSegment, &Phdr) != &Phdr) + continue; + + if (Phdr.p_type == PT_NOTE) + break; + + ++CurrentSegment; + } + + if (CurrentSegment >= NumberOfPhdrs) { + // No more segments. + // Note that NPtr is already nullptr indicating the end() iterator. + return; + } + + if (gelf_getphdr(EF, CurrentSegment, &Phdr) != &Phdr) + assert(false && "Invalid program header selected above."); + + uint64_t NotesBegin = getNotesBeginAddr(Phdr); + uint64_t NotesEnd = getNotesEndAddr(Phdr); + if (NotesBegin >= NotesEnd) { + // Something went wrong. Assume that we've reached + // the end of all notes. + CurrentSegment = NumberOfPhdrs; + NPtr = nullptr; + return; + } + + NPtr = reinterpret_cast(NotesBegin); + assert(NPtr && "Invalid PT_NOTE segment."); + } + + bool operator!=(const ElfLSegmentNoteIteratorImpl Other) const { + return !(*this == Other); + } + +public: + ElfLSegmentNoteIteratorImpl(Elf *RawElf, bool IsEnd = false) : EF(RawElf) { + assert(EF && "Trying to iterate invalid ELF."); + + if (IsEnd) { + // NPtr equal to nullptr means end() iterator. + return; + } + + // Set CurrentSegment to the very first segment, + // and let autoAdvance() find the first valid note (if any). + CurrentSegment = 0; + + // Set NumberOfPhdrs to 0, if we cannot query it. + if (elf_getphdrnum(EF, &NumberOfPhdrs) != 0) + NumberOfPhdrs = 0; + autoAdvance(true); + } + + bool operator==(const ElfLSegmentNoteIteratorImpl Other) const { + // They should be pointing to the same NOTE to be equal. + return NPtr == Other.NPtr; + } + + const Elf_Note *operator*() const { + assert(*this != ElfLSegmentNoteIteratorImpl(EF, true) && + "Dereferencing the end iterator."); + return NPtr; + } + + // Advance to the next NOTE in the CurrentSegment. + // If there is no next NOTE, then autoAdvance() to the next + // PT_NOTE segment and its first NOTE. + ElfLSegmentNoteIteratorImpl &operator++() { + assert(*this != ElfLSegmentNoteIteratorImpl(EF, true) && + "Incrementing the end iterator."); + + GElf_Phdr Phdr; + gelf_getphdr(EF, CurrentSegment, &Phdr); + uint64_t NotesBegin = getNotesBeginAddr(Phdr); + uint64_t NotesEnd = getNotesEndAddr(Phdr); + assert(reinterpret_cast(NPtr) >= NotesBegin && + reinterpret_cast(NPtr) < NotesEnd && + "Invalid pointer to a note computed somewhere else."); + (void)NotesBegin; + + uint64_t NoteSize = getNoteSize(*NPtr); + NPtr = + reinterpret_cast(reinterpret_cast(NPtr) + NoteSize); + if (reinterpret_cast(NPtr) >= NotesEnd || + reinterpret_cast(NPtr) + sizeof(*NPtr) >= NotesEnd) { + // We've reached the end of the current NOTE section. + NPtr = nullptr; + } + + // Auto advance to the next section, if needed. + autoAdvance(); + return *this; + } +}; + +// Actual implementation of ElfL via libelf. +// It is constructed from an ELF image defined by its +// starting pointer in memory and a length in bytes. +class ElfLImpl { + // A pointer to Elf object created by elf_memory() for + // the ELF image. + Elf *EF = nullptr; + + // Class of the ELF image. + unsigned ElfClass = ELFCLASSNONE; + + // A pointer to the ELF image's header. + // Depending on the class it may be either 'Elf32_Ehdr *' + // or 'Elf64_Ehdr '. + const void *Header = nullptr; + + // Let the owning object access this. + friend class ElfL; + +public: + ElfLImpl(Elf *RawElf, unsigned ElfClass, const void *Header) + : EF(RawElf), ElfClass(ElfClass), Header(Header) {} + + // Allocates and constructs a new iterator for NOTEs in + // SHT_NOTE sections of the ELF image. + ElfLSectionNoteIteratorImpl * + createSectionNoteIteratorImpl(bool IsEnd) const { + return new ElfLSectionNoteIteratorImpl(EF, IsEnd); + } + + // Allocates and constructs a new iterator for NOTEs in + // PT_NOTE segments of the ELF image. + ElfLSegmentNoteIteratorImpl * + createSegmentNoteIteratorImpl(bool IsEnd) const { + return new ElfLSegmentNoteIteratorImpl(EF, IsEnd); + } +}; + +ElfL::ElfL(char *Begin, size_t Size) { + Elf *ElfHandle = elf_memory(Begin, Size); + if (!ElfHandle) { + elf_end(ElfHandle); + return; + } + + const Elf32_Ehdr *Header32 = elf32_getehdr(ElfHandle); + const Elf64_Ehdr *Header64 = elf64_getehdr(ElfHandle); + + if (!Header32 == !Header64) { + // Ambiguous ELF header or unrecognized ELF image. + elf_end(ElfHandle); + return; + } + + const void *Header = nullptr; + unsigned ElfClass = ELFCLASSNONE; + + if (Header32) { + ElfClass = ELFCLASS32; + Header = reinterpret_cast(Header32); + } else { + ElfClass = ELFCLASS64; + Header = reinterpret_cast(Header64); + } + + Impl = reinterpret_cast(new ElfLImpl(ElfHandle, ElfClass, Header)); +} + +ElfL::~ElfL() { + if (Impl) { + ElfLImpl *EImpl = reinterpret_cast(Impl); + elf_end(EImpl->EF); + delete EImpl; + } +} + +bool ElfL::isValidElf() const { + ElfLImpl *EImpl = reinterpret_cast(Impl); + return Impl && EImpl->Header && EImpl->ElfClass != ELFCLASSNONE; +} + +const char *ElfL::getErrmsg(int N) const { return elf_errmsg(-1); } + +uint16_t ElfL::getEMachine() const { + assert(isValidElf() && "Invalid ELF."); + ElfLImpl *EImpl = reinterpret_cast(Impl); + if (EImpl->ElfClass == ELFCLASS32) + return reinterpret_cast(EImpl->Header)->e_machine; + else if (EImpl->ElfClass == ELFCLASS64) + return reinterpret_cast(EImpl->Header)->e_machine; + else + assert(false && "Unsupported ELF class."); + + return EM_NONE; +} + +uint16_t ElfL::getEType() const { + assert(isValidElf() && "Invalid ELF."); + ElfLImpl *EImpl = reinterpret_cast(Impl); + if (EImpl->ElfClass == ELFCLASS32) + return reinterpret_cast(EImpl->Header)->e_type; + else if (EImpl->ElfClass == ELFCLASS64) + return reinterpret_cast(EImpl->Header)->e_type; + else + assert(false && "Unsupported ELF class."); + + return ET_NONE; +} + +bool ElfL::isDynType(uint16_t Ty) { return Ty == ET_DYN; } + +ElfLSectionNoteIterator ElfL::section_notes_begin() const { + return ElfLSectionNoteIterator(reinterpret_cast(Impl)); +} + +ElfLSectionNoteIterator ElfL::section_notes_end() const { + return ElfLSectionNoteIterator(reinterpret_cast(Impl), + true); +} + +ElfLSectionNoteIterator::ElfLSectionNoteIterator(const void *I, bool IsEnd) { + const ElfLImpl *EImpl = reinterpret_cast(I); + Impl = EImpl->createSectionNoteIteratorImpl(IsEnd); +} + +ElfLSectionNoteIterator::ElfLSectionNoteIterator( + const ElfLSectionNoteIterator &Other) { + ElfLSectionNoteIteratorImpl *IImpl = + reinterpret_cast(Other.Impl); + Impl = new ElfLSectionNoteIteratorImpl(*IImpl); +} + +ElfLSectionNoteIterator::~ElfLSectionNoteIterator() { + assert(Impl && "Invalid ElfLSectionNoteIterator object."); + ElfLSectionNoteIteratorImpl *IImpl = + reinterpret_cast(Impl); + delete IImpl; +} + +bool ElfLSectionNoteIterator::operator==( + const ElfLSectionNoteIterator Other) const { + const ElfLSectionNoteIteratorImpl *Lhs = + reinterpret_cast(Impl); + const ElfLSectionNoteIteratorImpl *Rhs = + reinterpret_cast(Other.Impl); + return (*Lhs == *Rhs); +} + +bool ElfLSectionNoteIterator::operator!=( + const ElfLSectionNoteIterator Other) const { + return !(*this == Other); +} + +ElfLSectionNoteIterator &ElfLSectionNoteIterator::operator++() { + ElfLSectionNoteIteratorImpl *IImpl = + reinterpret_cast(Impl); + ++(*IImpl); + return *this; +} + +ElfLNote ElfLSectionNoteIterator::operator*() const { + ElfLSectionNoteIteratorImpl *IImpl = + reinterpret_cast(Impl); + return ElfLNote(**IImpl); +} + +ElfLSegmentNoteIterator ElfL::segment_notes_begin() const { + return ElfLSegmentNoteIterator(reinterpret_cast(Impl)); +} + +ElfLSegmentNoteIterator ElfL::segment_notes_end() const { + return ElfLSegmentNoteIterator(reinterpret_cast(Impl), + true); +} + +ElfLSegmentNoteIterator::ElfLSegmentNoteIterator(const void *I, bool IsEnd) { + const ElfLImpl *EImpl = reinterpret_cast(I); + Impl = EImpl->createSegmentNoteIteratorImpl(IsEnd); +} + +ElfLSegmentNoteIterator::ElfLSegmentNoteIterator( + const ElfLSegmentNoteIterator &Other) { + ElfLSegmentNoteIteratorImpl *IImpl = + reinterpret_cast(Other.Impl); + Impl = new ElfLSegmentNoteIteratorImpl(*IImpl); +} + +ElfLSegmentNoteIterator::~ElfLSegmentNoteIterator() { + assert(Impl && "Invalid ElfLSegmentNoteIterator object."); + ElfLSegmentNoteIteratorImpl *IImpl = + reinterpret_cast(Impl); + delete IImpl; +} + +bool ElfLSegmentNoteIterator::operator==( + const ElfLSegmentNoteIterator Other) const { + const ElfLSegmentNoteIteratorImpl *Lhs = + reinterpret_cast(Impl); + const ElfLSegmentNoteIteratorImpl *Rhs = + reinterpret_cast(Other.Impl); + return (*Lhs == *Rhs); +} + +bool ElfLSegmentNoteIterator::operator!=( + const ElfLSegmentNoteIterator Other) const { + return !(*this == Other); +} + +ElfLSegmentNoteIterator &ElfLSegmentNoteIterator::operator++() { + ElfLSegmentNoteIteratorImpl *IImpl = + reinterpret_cast(Impl); + ++(*IImpl); + return *this; +} + +ElfLNote ElfLSegmentNoteIterator::operator*() const { + ElfLSegmentNoteIteratorImpl *IImpl = + reinterpret_cast(Impl); + return ElfLNote(**IImpl); +} + +ElfLNote::ElfLNote(const void *I) { + // ElfLNote::Impl is a pointer to Elf_Note in this implementation. + // A pointer to Elf_Note is returned by + // ElfLSectionNoteIteratorImpl::operator*(). + Impl = I; +} + +ElfLNote::ElfLNote(const ElfLNote &Other) { Impl = Other.Impl; } + +ElfLNote::~ElfLNote() {} + +uint64_t ElfLNote::getNameSize() const { + const Elf_Note *Note = reinterpret_cast(Impl); + if (Note->n_namesz == 0) + return 0; + // libelf returns name size that accounts for the null terminator. + // ELF light interface returns the size ignoring it. + return Note->n_namesz - 1; +} + +const char *ElfLNote::getName() const { + const Elf_Note *Note = reinterpret_cast(Impl); + return reinterpret_cast(Note) + sizeof(*Note); +} + +uint64_t ElfLNote::getDescSize() const { + const Elf_Note *Note = reinterpret_cast(Impl); + return Note->n_descsz; +} + +const uint8_t *ElfLNote::getDesc() const { + const Elf_Note *Note = reinterpret_cast(Impl); + return reinterpret_cast(Note) + sizeof(*Note) + + alignUp(getNameSize(), NoteAlignment); +} + +uint64_t ElfLNote::getType() const { + const Elf_Note *Note = reinterpret_cast(Impl); + return Note->n_type; +} + +#else // !MAY_USE_LIBELF + +// Implementation based on LLVM ELF binary format. +#include "llvm/Object/Binary.h" +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Object/ELFTypes.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/MemoryBuffer.h" + +using namespace llvm; +using namespace llvm::ELF; +using namespace llvm::object; + +class ElfLNoteImplBase { +public: + virtual ~ElfLNoteImplBase() = default; + virtual ElfLNoteImplBase *clone() const = 0; + virtual size_t getNameSize() const = 0; + virtual const char *getName() const = 0; + virtual size_t getDescSize() const = 0; + virtual const uint8_t *getDesc() const = 0; + virtual uint32_t getType() const = 0; +}; + +template class ElfLNoteImpl : public ElfLNoteImplBase { + using Elf_Note = typename ELFT::Note; + const Elf_Note Note; + +public: + ElfLNoteImpl(const Elf_Note Note) : Note(Note) {} + ElfLNoteImpl(const ElfLNoteImpl &) = default; + ElfLNoteImplBase *clone() const override { return new ElfLNoteImpl(*this); } + ~ElfLNoteImpl() = default; + size_t getNameSize() const override { return Note.getName().size(); } + const char *getName() const override { return Note.getName().data(); } + size_t getDescSize() const override { return Note.getDesc().size(); } + const uint8_t *getDesc() const override { return Note.getDesc().data(); } + uint32_t getType() const override { return Note.getType(); } +}; + +class ElfLNoteIteratorImplBase { +protected: + const endianness TargetEndianness; + const bool Is64Bits; + const bool IsSectionIterator; + + ElfLNoteIteratorImplBase(endianness TargetEndianness, bool Is64Bits, + bool IsSectionIterator) + : TargetEndianness(TargetEndianness), Is64Bits(Is64Bits), + IsSectionIterator(IsSectionIterator) {} + +public: + ElfLNoteIteratorImplBase(const ElfLNoteIteratorImplBase &) = default; + virtual ~ElfLNoteIteratorImplBase() = default; + virtual ElfLNoteIteratorImplBase *clone() const = 0; + virtual ElfLNoteIteratorImplBase &operator++() = 0; + virtual bool operator==(const ElfLNoteIteratorImplBase &) const = 0; + virtual ElfLNoteImplBase *operator*() const = 0; + + endianness getEndianness() const { return TargetEndianness; } + + bool is64Bits() const { return Is64Bits; } + + bool isSectionIterator() const { return IsSectionIterator; } +}; + +template +class ElfLNoteIteratorImpl : public ElfLNoteIteratorImplBase { +protected: + using NoteIterator = typename ELFT::NoteIterator; + + const ELFFile &EF; + NoteIterator NotesIt; + Error &Err; + + explicit ElfLNoteIteratorImpl(const ELFFile &EF, Error &Err, + bool IsSectionIterator) + : ElfLNoteIteratorImplBase(ELFT::TargetEndianness, ELFT::Is64Bits, + IsSectionIterator), + EF(EF), NotesIt(EF.notes_end()), Err(Err) {} + +public: + ElfLNoteIteratorImpl(const ElfLNoteIteratorImpl &) = default; + virtual ~ElfLNoteIteratorImpl() = default; + + static bool classof(const ElfLNoteIteratorImplBase *B) { + return (B->getEndianness() == ELFT::TargetEndianness && + B->is64Bits() == ELFT::Is64Bits); + } +}; + +template +class ElfLSectionNoteIteratorImpl : public ElfLNoteIteratorImpl { + using Elf_Shdr = typename ELFT::Shdr; + using Elf_Shdr_Range = typename ELFT::ShdrRange; + using NoteIterator = typename ElfLNoteIteratorImpl::NoteIterator; + using SectionsIteratorTy = typename Elf_Shdr_Range::iterator; + + SectionsIteratorTy SectionsIt; + + const ELFFile &getEF() const { return this->EF; } + const NoteIterator &getNotesIt() const { return this->NotesIt; } + Error &getErr() const { return this->Err; } + NoteIterator &getNotesIt() { return this->NotesIt; } + SectionsIteratorTy section_begin() const { + Expected Sections = getEF().sections(); + if (!Sections) + return SectionsIteratorTy(); + + return Sections->begin(); + } + + SectionsIteratorTy section_end() const { + Expected Sections = getEF().sections(); + if (!Sections) + return SectionsIteratorTy(); + + return Sections->end(); + } + + bool isEqual(const ElfLSectionNoteIteratorImpl &Lhs, + const ElfLSectionNoteIteratorImpl &Rhs) const { + // Check for end() iterators, first. + if (Lhs.SectionsIt == section_end() && Rhs.SectionsIt == section_end()) + return true; + + if (Lhs.SectionsIt != Rhs.SectionsIt) + return false; + + return Lhs.getNotesIt() == Rhs.getNotesIt(); + } + + void autoAdvance(bool IsFirst = false) { + if (SectionsIt == section_end()) + return; + + if (getNotesIt() != getEF().notes_end()) + return; + + // SectionsIt is not an end iterator, and NotesIt is an end() + // iterator. + // + // If IsFirst is true, then we just in the initial state, and + // we need to set SectionsIt to the first SHT_NOTE section (if any), + // and, then, NotesIt to the first note in this section. + // + // If IsFirst is false, then we've reached the end of the current + // SHT_NOTE section, and should find the next section with notes. + if (!IsFirst || SectionsIt->sh_type != ELF::SHT_NOTE) + ++SectionsIt; + + while (SectionsIt != section_end() && + SectionsIt->sh_type != ELF::SHT_NOTE) { + ++SectionsIt; + } + + if (SectionsIt == section_end()) { + // No more sections. + return; + } + + const Elf_Shdr &Section = *SectionsIt; + getNotesIt() = getEF().notes_begin(Section, getErr()); + + // Auto advance the iterator, if the NOTE section + // does not contain any notes (e.g. some error happened + // during the note parsing). + autoAdvance(); + } + + bool operator!=(const ElfLSectionNoteIteratorImpl &Other) const { + return !(*this == Other); + } + +public: + ElfLSectionNoteIteratorImpl(const ELFFile &EF, Error &Err, + bool IsEnd = false) + : ElfLNoteIteratorImpl(EF, Err, true) { + if (IsEnd) { + SectionsIt = section_end(); + // It is an end() iterator, if SectionsIt is an end() iterator. + return; + } + + SectionsIt = section_begin(); + autoAdvance(true); + } + + ElfLSectionNoteIteratorImpl(const ElfLSectionNoteIteratorImpl &Copy) = + default; + + ElfLNoteIteratorImplBase *clone() const override { + return new ElfLSectionNoteIteratorImpl(*this); + } + + bool operator==(const ElfLNoteIteratorImplBase &Other) const override { + if (const ElfLSectionNoteIteratorImpl *OPtr = + dyn_cast(&Other)) { + return isEqual(*this, *OPtr); + } + return false; + } + + ElfLSectionNoteIteratorImpl &operator++() override { + assert(*this != ElfLSectionNoteIteratorImpl(getEF(), getErr(), true) && + "Incrementing the end iterator."); + // Move the notes iterator within the current section. + ++getNotesIt(); + autoAdvance(); + + return *this; + } + + ElfLNoteImplBase *operator*() const override { + assert(*this != ElfLSectionNoteIteratorImpl(getEF(), getErr(), true) && + "Dereferencing the end iterator."); + return new ElfLNoteImpl(*getNotesIt()); + } + + static bool classof(const ElfLNoteIteratorImplBase *B) { + return (ElfLNoteIteratorImpl::classof(B) && + B->isSectionIterator() == true); + } +}; + +template +class ElfLSegmentNoteIteratorImpl : public ElfLNoteIteratorImpl { + using Elf_Phdr = typename ELFT::Phdr; + using Elf_Phdr_Range = typename ELFT::PhdrRange; + using NoteIterator = typename ElfLNoteIteratorImpl::NoteIterator; + using SegmentIteratorTy = typename Elf_Phdr_Range::iterator; + + SegmentIteratorTy SegmentsIt; + + const ELFFile &getEF() const { return this->EF; } + const NoteIterator &getNotesIt() const { return this->NotesIt; } + Error &getErr() const { return this->Err; } + NoteIterator &getNotesIt() { return this->NotesIt; } + SegmentIteratorTy segment_begin() const { + Expected Segments = getEF().program_headers(); + if (!Segments) + return SegmentIteratorTy(); + + return Segments->begin(); + } + + SegmentIteratorTy segment_end() const { + Expected Segments = getEF().program_headers(); + if (!Segments) + return SegmentIteratorTy(); + + return Segments->end(); + } + + bool isEqual(const ElfLSegmentNoteIteratorImpl &Lhs, + const ElfLSegmentNoteIteratorImpl &Rhs) const { + // Check for end() iterators, first. + if (Lhs.SegmentsIt == segment_end() && Rhs.SegmentsIt == segment_end()) + return true; + + if (Lhs.SegmentsIt != Rhs.SegmentsIt) + return false; + + return Lhs.getNotesIt() == Rhs.getNotesIt(); + } + + void autoAdvance(bool IsFirst = false) { + if (SegmentsIt == segment_end()) + return; + + if (getNotesIt() != getEF().notes_end()) + return; + + // SegmentsIt is not an end iterator, and NotesIt is an end() + // iterator. + // + // If IsFirst is true, then we just in the initial state, and + // we need to set SegmentsIt to the first PT_NOTE segment (if any), + // and, then, NotesIt to the first note in this segment. + // + // If IsFirst is false, then we've reached the end of the current + // PT_NOTE segment, and should find the next segment with notes. + if (!IsFirst || SegmentsIt->p_type != ELF::SHT_NOTE) + ++SegmentsIt; + + while (SegmentsIt != segment_end() && SegmentsIt->p_type != ELF::PT_NOTE) { + ++SegmentsIt; + } + + if (SegmentsIt == segment_end()) { + // No more segments. + return; + } + + const Elf_Phdr &Segment = *SegmentsIt; + getNotesIt() = getEF().notes_begin(Segment, getErr()); + + // Auto advance the iterator, if the NOTE segment + // does not contain any notes (e.g. some error happened + // during the note parsing). + autoAdvance(); + } + + bool operator!=(const ElfLSegmentNoteIteratorImpl &Other) const { + return !(*this == Other); + } + +public: + ElfLSegmentNoteIteratorImpl(const ELFFile &EF, Error &Err, + bool IsEnd = false) + : ElfLNoteIteratorImpl(EF, Err, false) { + if (IsEnd) { + SegmentsIt = segment_end(); + // It is an end() iterator, if SegmentsIt is an end() iterator. + return; + } + + SegmentsIt = segment_begin(); + autoAdvance(true); + } + + ElfLSegmentNoteIteratorImpl(const ElfLSegmentNoteIteratorImpl &Copy) = + default; + + ElfLNoteIteratorImplBase *clone() const override { + return new ElfLSegmentNoteIteratorImpl(*this); + } + + bool operator==(const ElfLNoteIteratorImplBase &Other) const override { + if (const ElfLSegmentNoteIteratorImpl *OPtr = + dyn_cast(&Other)) { + return isEqual(*this, *OPtr); + } + return false; + } + + ElfLSegmentNoteIteratorImpl &operator++() override { + assert(*this != ElfLSegmentNoteIteratorImpl(getEF(), getErr(), true) && + "Incrementing the end iterator."); + // Move the notes iterator within the current segment. + ++getNotesIt(); + autoAdvance(); + + return *this; + } + + ElfLNoteImplBase *operator*() const override { + assert(*this != ElfLSegmentNoteIteratorImpl(getEF(), getErr(), true) && + "Dereferencing the end iterator."); + return new ElfLNoteImpl(*getNotesIt()); + } + + static bool classof(const ElfLNoteIteratorImplBase *B) { + return (ElfLNoteIteratorImpl::classof(B) && + B->isSectionIterator() == false); + } +}; + +class ElfLImplBase { +public: + ElfLImplBase() = default; + ElfLImplBase(const ElfLImplBase &) = delete; + ElfLImplBase &operator=(const ElfLImplBase &) = delete; + virtual ~ElfLImplBase() = default; + virtual uint16_t getEMachine() const = 0; + virtual uint16_t getEType() const = 0; + + virtual ElfLNoteIteratorImplBase * + createSectionNoteIteratorImpl(bool IsEnd) const = 0; + virtual ElfLNoteIteratorImplBase * + createSegmentNoteIteratorImpl(bool IsEnd) const = 0; +}; + +template class ElfLImpl : public ElfLImplBase { + std::unique_ptr> File; + Error *Err = nullptr; + + friend class ElfL; + +public: + ElfLImpl(std::unique_ptr F) { + ObjectFile *FPtr = F.release(); + if (auto *Obj = dyn_cast>(FPtr)) + File = std::unique_ptr>(Obj); + else + assert(false && "Not an ELF object file, or ELF class is wrong."); + + Err = new Error(std::move(Error::success())); + } + ElfLImpl(const ElfLImpl &) = delete; + ElfLImpl &operator=(const ElfLImpl &) = delete; + virtual ~ElfLImpl() { + if (!Err) + return; + + if (*Err) { + auto ErrorString = toString(std::move(*Err)); + DP("Destroying ELF object parsed with errors: %s\n", ErrorString.c_str()); + } else { + delete Err; + } + Err = nullptr; + } + uint16_t getEMachine() const override { + return cast(File.get())->getEMachine(); + } + uint16_t getEType() const override { + return cast(File.get())->getEType(); + } + + ElfLNoteIteratorImplBase * + createSectionNoteIteratorImpl(bool IsEnd) const override { + return new ElfLSectionNoteIteratorImpl(File->getELFFile(), *Err, + IsEnd); + } + + ElfLNoteIteratorImplBase * + createSegmentNoteIteratorImpl(bool IsEnd) const override { + return new ElfLSegmentNoteIteratorImpl(File->getELFFile(), *Err, + IsEnd); + } +}; + +ElfL::ElfL(char *Begin, size_t Size) { + StringRef StrBuf(Begin, Size); + std::unique_ptr MemBuf = + MemoryBuffer::getMemBuffer(StrBuf, "", false); + Expected> BinOrErr = + ObjectFile::createELFObjectFile(MemBuf->getMemBufferRef(), + /*InitContent=*/false); + if (!BinOrErr) { + consumeError(BinOrErr.takeError()); + return; + } + + if (isa(BinOrErr->get())) { + Impl = + reinterpret_cast(new ElfLImpl(std::move(*BinOrErr))); + } else if (isa(BinOrErr->get())) + Impl = + reinterpret_cast(new ElfLImpl(std::move(*BinOrErr))); + else if (isa(BinOrErr->get())) + Impl = + reinterpret_cast(new ElfLImpl(std::move(*BinOrErr))); + else if (isa(BinOrErr->get())) + Impl = + reinterpret_cast(new ElfLImpl(std::move(*BinOrErr))); +} + +ElfL::~ElfL() { + ElfLImplBase *EImpl = reinterpret_cast(Impl); + delete EImpl; +} + +bool ElfL::isValidElf() const { return Impl; } + +const char *ElfL::getErrmsg(int N) const { + // TODO: return text representation for the latest Error. + return "LLVM ELF error"; +} + +uint16_t ElfL::getEMachine() const { + assert(isValidElf() && "Invalid ELF."); + ElfLImplBase *EImpl = reinterpret_cast(Impl); + return EImpl->getEMachine(); +} + +uint16_t ElfL::getEType() const { + assert(isValidElf() && "Invalid ELF."); + ElfLImplBase *EImpl = reinterpret_cast(Impl); + return EImpl->getEType(); +} + +bool ElfL::isDynType(uint16_t Ty) { return Ty == ET_DYN; } + +ElfLSectionNoteIterator::ElfLSectionNoteIterator(const void *I, bool IsEnd) { + const ElfLImplBase *EImpl = reinterpret_cast(I); + // Create new ElfLSectionNoteIteratorImpl object. + Impl = EImpl->createSectionNoteIteratorImpl(IsEnd); +} + +ElfLSectionNoteIterator::~ElfLSectionNoteIterator() { + const ElfLNoteIteratorImplBase *IImpl = + reinterpret_cast(Impl); + delete IImpl; +} + +ElfLSectionNoteIterator::ElfLSectionNoteIterator( + const ElfLSectionNoteIterator &Other) { + const ElfLNoteIteratorImplBase *IImpl = + reinterpret_cast(Other.Impl); + Impl = IImpl->clone(); +} + +bool ElfLSectionNoteIterator::operator==( + const ElfLSectionNoteIterator Other) const { + const ElfLNoteIteratorImplBase *Lhs = + reinterpret_cast(Impl); + const ElfLNoteIteratorImplBase *Rhs = + reinterpret_cast(Other.Impl); + return (*Lhs == *Rhs); +} + +bool ElfLSectionNoteIterator::operator!=( + const ElfLSectionNoteIterator Other) const { + return !(*this == Other); +} + +ElfLSectionNoteIterator &ElfLSectionNoteIterator::operator++() { + ElfLNoteIteratorImplBase *EImpl = + reinterpret_cast(Impl); + ++(*EImpl); + return *this; +} + +ElfLNote ElfLSectionNoteIterator::operator*() const { return ElfLNote(Impl); } + +ElfLSectionNoteIterator ElfL::section_notes_begin() const { + assert(isValidElf() && "Invalid ELF."); + return ElfLSectionNoteIterator(reinterpret_cast(Impl)); +} + +ElfLSectionNoteIterator ElfL::section_notes_end() const { + assert(isValidElf() && "Invalid ELF."); + return ElfLSectionNoteIterator(reinterpret_cast(Impl), + true); +} + +ElfLSegmentNoteIterator::ElfLSegmentNoteIterator(const void *I, bool IsEnd) { + const ElfLImplBase *EImpl = reinterpret_cast(I); + // Create new ElfLSegmentNoteIteratorImpl object. + Impl = EImpl->createSegmentNoteIteratorImpl(IsEnd); +} + +ElfLSegmentNoteIterator::~ElfLSegmentNoteIterator() { + const ElfLNoteIteratorImplBase *IImpl = + reinterpret_cast(Impl); + delete IImpl; +} + +ElfLSegmentNoteIterator::ElfLSegmentNoteIterator( + const ElfLSegmentNoteIterator &Other) { + const ElfLNoteIteratorImplBase *IImpl = + reinterpret_cast(Other.Impl); + Impl = IImpl->clone(); +} + +bool ElfLSegmentNoteIterator::operator==( + const ElfLSegmentNoteIterator Other) const { + const ElfLNoteIteratorImplBase *Lhs = + reinterpret_cast(Impl); + const ElfLNoteIteratorImplBase *Rhs = + reinterpret_cast(Other.Impl); + return (*Lhs == *Rhs); +} + +bool ElfLSegmentNoteIterator::operator!=( + const ElfLSegmentNoteIterator Other) const { + return !(*this == Other); +} + +ElfLSegmentNoteIterator &ElfLSegmentNoteIterator::operator++() { + ElfLNoteIteratorImplBase *EImpl = + reinterpret_cast(Impl); + ++(*EImpl); + return *this; +} + +ElfLNote ElfLSegmentNoteIterator::operator*() const { return ElfLNote(Impl); } + +ElfLSegmentNoteIterator ElfL::segment_notes_begin() const { + assert(isValidElf() && "Invalid ELF."); + return ElfLSegmentNoteIterator(reinterpret_cast(Impl)); +} + +ElfLSegmentNoteIterator ElfL::segment_notes_end() const { + assert(isValidElf() && "Invalid ELF."); + return ElfLSegmentNoteIterator(reinterpret_cast(Impl), + true); +} + +ElfLNote::ElfLNote(const void *IteratorImpl) { + const ElfLNoteIteratorImplBase *IImpl = + reinterpret_cast(IteratorImpl); + Impl = **IImpl; +} + +ElfLNote::ElfLNote(const ElfLNote &Other) { + const ElfLNoteImplBase *NImpl = + reinterpret_cast(Impl); + Impl = NImpl->clone(); +} + +ElfLNote::~ElfLNote() { + const ElfLNoteImplBase *NImpl = + reinterpret_cast(Impl); + delete NImpl; +} + +uint64_t ElfLNote::getNameSize() const { + const ElfLNoteImplBase *NImpl = + reinterpret_cast(Impl); + return NImpl->getNameSize(); +} + +const char *ElfLNote::getName() const { + const ElfLNoteImplBase *NImpl = + reinterpret_cast(Impl); + return NImpl->getName(); +} + +uint64_t ElfLNote::getDescSize() const { + const ElfLNoteImplBase *NImpl = + reinterpret_cast(Impl); + return NImpl->getDescSize(); +} + +const uint8_t *ElfLNote::getDesc() const { + const ElfLNoteImplBase *NImpl = + reinterpret_cast(Impl); + return NImpl->getDesc(); +} + +uint64_t ElfLNote::getType() const { + const ElfLNoteImplBase *NImpl = + reinterpret_cast(Impl); + return NImpl->getType(); +} +#endif // !MAY_USE_LIBELF Index: openmp/libomptarget/plugins/remote/server/CMakeLists.txt =================================================================== --- openmp/libomptarget/plugins/remote/server/CMakeLists.txt +++ openmp/libomptarget/plugins/remote/server/CMakeLists.txt @@ -10,7 +10,6 @@ # ##===----------------------------------------------------------------------===## -include_directories(${LIBOMPTARGET_DEP_LIBELF_INCLUDE_DIRS}) include_directories(${LIBOMPTARGET_SRC_DIR}) include_directories(${LIBOMPTARGET_INCLUDE_DIR}) include_directories(${GRPC_INCLUDE_DIR}) @@ -28,4 +27,4 @@ grpc++ protobuf ${OPENMP_PTHREAD_LIB} - "-ldl" "-lomp" "-fopenmp" "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/../../exports" ${LIBOMPTARGET_DEP_LIBELF_LIBRARIES}) + "-ldl" "-lomp" "-fopenmp" "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/../../exports") Index: openmp/libomptarget/test/offloading/llvmompoffload_notes.c =================================================================== --- /dev/null +++ openmp/libomptarget/test/offloading/llvmompoffload_notes.c @@ -0,0 +1,12 @@ +// RUN: %libomptarget-compile-x86_64-pc-linux-gnu && env LIBOMPTARGET_DEBUG=1 %libomptarget-run-x86_64-pc-linux-gnu 2>&1 | %fcheck-x86_64-pc-linux-gnu + +// CHECK: TARGET Common ELF --> LLVMOMPOFFLOAD ELF note NT_LLVM_OPENMP_OFFLOAD_VERSION with value: '1.0' +// CHECK: TARGET Common ELF --> LLVMOMPOFFLOAD ELF note NT_LLVM_OPENMP_OFFLOAD_PRODUCER with value: 'LLVM' +// CHECK: TARGET Common ELF --> LLVMOMPOFFLOAD ELF note NT_LLVM_OPENMP_OFFLOAD_PRODUCER_VERSION with value: + +int main() { +#pragma omp target + ; + + return 0; +}