Index: clang/tools/clang-offload-wrapper/ClangOffloadWrapper.cpp =================================================================== --- clang/tools/clang-offload-wrapper/ClangOffloadWrapper.cpp +++ clang/tools/clang-offload-wrapper/ClangOffloadWrapper.cpp @@ -17,26 +17,35 @@ #include "clang/Basic/Version.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Triple.h" +#include "llvm/BinaryFormat/ELF.h" #include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/IR/Constants.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Object/ObjectFile.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/EndianStream.h" #include "llvm/Support/Errc.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Program.h" #include "llvm/Support/Signals.h" #include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/VCSRevision.h" #include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Utils/ModuleUtils.h" #include #include +#define OPENMP_OFFLOAD_IMAGE_VERSION "1.0" + using namespace llvm; +using namespace llvm::object; static cl::opt Help("h", cl::desc("Alias for -help"), cl::Hidden); @@ -59,6 +68,11 @@ cl::desc("Target triple for the output module"), cl::value_desc("triple"), cl::cat(ClangOffloadWrapperCategory)); +static cl::opt SaveTemps("save-temps", + cl::desc("Save temporary files that may be produced by the tool. " + "This option forces print-out of the temporary files' names."), + cl::Hidden); + namespace { class BinaryWrapper { @@ -69,6 +83,15 @@ StructType *ImageTy = nullptr; StructType *DescTy = nullptr; + std::string ToolName; + std::string ObjcopyPath; + // Temporary file names that may be created during adding notes + // to ELF offload images. Use -save-temps to keep them and also + // see their names. A temporary file's name includes the name + // of the original input ELF image, so you can easily match + // them, if you have multiple inputs. + std::vector TempFiles; + private: IntegerType *getSizeTTy() { switch (M.getDataLayout().getPointerTypeSize(Type::getInt8PtrTy(C))) { @@ -293,8 +316,48 @@ } public: - BinaryWrapper(StringRef Target) : M("offload.wrapper.object", C) { + BinaryWrapper(StringRef Target, StringRef ToolName) + : M("offload.wrapper.object", C), ToolName(ToolName) { M.setTargetTriple(Target); + ErrorOr ObjcopyPathOrErr = + sys::findProgramByName("llvm-objcopy"); + if (!ObjcopyPathOrErr) { +#ifdef _WIN32 + // Look for llvm-objcopy.exe as well. + ObjcopyPathOrErr = sys::findProgramByName("llvm-objcopy.exe"); + if (!ObjcopyPathOrErr) { +#endif // _WIN32 + WithColor::warning(errs(), ToolName) << + "cannot find llvm-objcopy[.exe] in PATH; ELF notes cannot be added.\n"; +#ifdef _WIN32 + } +#endif // _WIN32 + } + + if (ObjcopyPathOrErr) + ObjcopyPath = *ObjcopyPathOrErr; + } + + ~BinaryWrapper() { + if (TempFiles.empty()) + return; + + StringRef ToolNameRef(ToolName); + auto warningOS = [ToolNameRef]() -> raw_ostream & { + return WithColor::warning(errs(), ToolNameRef); + }; + + for (auto &F : TempFiles) { + if (SaveTemps) { + warningOS() << "keeping temporary file " << F << "\n"; + continue; + } + + auto EC = sys::fs::remove(F, false); + if (EC) + warningOS() << "cannot remove temporary file " << F << + ": " << EC.message().c_str() << "\n"; + } } const Module &wrapBinaries(ArrayRef> Binaries) { @@ -304,6 +367,204 @@ createUnregisterFunction(Desc); return M; } + + std::unique_ptr addELFNotes( + std::unique_ptr Buf, + StringRef OriginalFileName) { + // Cannot add notes, if llvm-objcopy is not available. + // + // I did not find a clean way to add a new notes section into an existing + // ELF file. llvm-objcopy seems to recreate a new ELF from scratch, + // and we just try to use llvm-objcopy here. + if (ObjcopyPath.empty()) + return std::move(Buf); + + StringRef ToolNameRef(ToolName); + + // Helpers to emit warnings. + auto warningOS = [ToolNameRef]() -> raw_ostream & { + return WithColor::warning(errs(), ToolNameRef); + }; + auto handleErrorAsWarning = [ToolNameRef, &warningOS](Error E) { + logAllUnhandledErrors(std::move(E), warningOS()); + }; + + Expected> BinOrErr = + ObjectFile::createELFObjectFile(Buf->getMemBufferRef(), + /*InitContent=*/false); + if (Error E = BinOrErr.takeError()) { + consumeError(std::move(E)); + // This warning is questionable, but let it be here, + // assuming that most OpenMP offload models use ELF offload images. + warningOS() << OriginalFileName << + " is not an ELF image, so notes cannot be added to it.\n"; + return std::move(Buf); + } + + // If we fail to add the note section, we just pass through the original + // ELF image for wrapping. At some point we should enforce the note section + // and start emitting errors vs warnings. + support::endianness Endianness; + if (isa(BinOrErr->get()) || + isa(BinOrErr->get())) { + Endianness = support::little; + } else if (isa(BinOrErr->get()) || + isa(BinOrErr->get())) { + Endianness = support::big; + } else { + warningOS() << OriginalFileName << + " is an ELF image of unrecognized format.\n"; + return std::move(Buf); + } + + // Create temporary file for the data of a new SHT_NOTE section. + // We fill it in with data and then pass to llvm-objcopy invocation + // for reading. + Twine NotesFileModel = OriginalFileName + Twine(".elfnotes.%%%%%%%.tmp"); + Expected NotesTemp = + sys::fs::TempFile::create(NotesFileModel); + if (Error E = NotesTemp.takeError()) { + handleErrorAsWarning(createFileError(NotesFileModel, std::move(E))); + return std::move(Buf); + } + TempFiles.push_back(NotesTemp->TmpName); + + // Create temporary file for the updated ELF image. + // This is an empty file that we pass to llvm-objcopy invocation + // for writing. + Twine ELFFileModel = OriginalFileName + Twine(".elfwithnotes.%%%%%%%.tmp"); + Expected ELFTemp = + sys::fs::TempFile::create(ELFFileModel); + if (Error E = ELFTemp.takeError()) { + handleErrorAsWarning(createFileError(ELFFileModel, std::move(E))); + return std::move(Buf); + } + TempFiles.push_back(ELFTemp->TmpName); + + // Keep the new ELF image file to reserve the name for the future + // llvm-objcopy invocation. + std::string ELFTmpFileName = ELFTemp->TmpName; + if (Error E = ELFTemp->keep(ELFTmpFileName)) { + handleErrorAsWarning(createFileError(ELFTmpFileName, std::move(E))); + return std::move(Buf); + } + + // Write notes to the *elfnotes*.tmp file. + raw_fd_ostream NotesOS(NotesTemp->FD, false); + + struct NoteTy { + // Note name is a null-terminated "LLVMOMPOFFLOAD". + std::string Name; + // Note type defined in llvm/include/llvm/BinaryFormat/ELF.h. + uint32_t Type = 0; + // Each note has type-specific associated data. + std::string Desc; + + NoteTy(std::string &&Name, uint32_t Type, std::string &&Desc) + : Name(std::move(Name)), Type(Type), Desc(std::move(Desc)) {} + }; + + // So far we emit just three notes. + SmallVector Notes; + // Version of the offload image identifying the structure of the ELF image. + // Version 1.0 does not have any specific requirements. + // We may come up with some structure that has to be honored by all + // offload implementations in future (e.g. to let libomptarget + // get some information from the offload image). + Notes.emplace_back("LLVMOMPOFFLOAD", ELF::NT_LLVM_OPENMP_OFFLOAD_VERSION, + OPENMP_OFFLOAD_IMAGE_VERSION); + // This is a producer identification string. We are LLVM! + Notes.emplace_back("LLVMOMPOFFLOAD", ELF::NT_LLVM_OPENMP_OFFLOAD_PRODUCER, + "LLVM"); + // This is a producer version. Use the same format that is used + // by clang to report the LLVM version. + Notes.emplace_back("LLVMOMPOFFLOAD", + ELF::NT_LLVM_OPENMP_OFFLOAD_PRODUCER_VERSION, LLVM_VERSION_STRING +#ifdef LLVM_REVISION + " " LLVM_REVISION +#endif + ); + + // Return the amount of padding required for a blob of N bytes + // to be aligned to Alignment bytes. + auto getPadAmount = [](uint32_t N, uint32_t Alignment) -> uint32_t { + uint32_t Mod = (N % Alignment); + if (Mod == 0) + return 0; + return Alignment - Mod; + }; + auto emitPadding = [&getPadAmount](raw_ostream &OS, uint32_t Size) { + for (uint32_t I = 0; I < getPadAmount(Size, 4); ++I) + OS << '\0'; + }; + + // Put notes into the file. + for (auto &N : Notes) { + assert(!N.Name.empty() && "We should not create notes with empty names."); + // Name must be null-terminated. + if (N.Name.back() != '\0') + N.Name += '\0'; + uint32_t NameSz = N.Name.size(); + uint32_t DescSz = N.Desc.size(); + // A note starts with three 4-byte values: + // NameSz + // DescSz + // Type + // These three fields are endian-sensitive. + support::endian::write(NotesOS, NameSz, Endianness); + support::endian::write(NotesOS, DescSz, Endianness); + support::endian::write(NotesOS, N.Type, Endianness); + // Next, we have a null-terminated Name padded to a 4-byte boundary. + NotesOS << N.Name; + emitPadding(NotesOS, NameSz); + if (DescSz == 0) + continue; + // Finally, we have a descriptor, which is an arbitrary flow of bytes. + NotesOS << N.Desc; + emitPadding(NotesOS, DescSz); + } + NotesOS.flush(); + + // Keep the notes file. + std::string NotesTmpFileName = NotesTemp->TmpName; + if (Error E = NotesTemp->keep(NotesTmpFileName)) { + handleErrorAsWarning(createFileError(NotesTmpFileName, std::move(E))); + return std::move(Buf); + } + + // Run llvm-objcopy like this: + // llvm-objcopy --add-section=.note.openmp= \ + // + // + // This will add a SHT_NOTE section on top of the original ELF. + std::vector Args; + Args.push_back(ObjcopyPath); + std::string Option("--add-section=.note.openmp=" + NotesTmpFileName); + Args.push_back(Option); + Args.push_back(OriginalFileName); + Args.push_back(ELFTmpFileName); + bool ExecutionFailed = false; + std::string ErrMsg; + (void)sys::ExecuteAndWait(ObjcopyPath, Args, + /*Env=*/llvm::None, /*Redirects=*/{}, /*SecondsToWait=*/0, + /*MemoryLimit=*/0, &ErrMsg, &ExecutionFailed); + + if (ExecutionFailed) { + warningOS() << ErrMsg << "\n"; + return std::move(Buf); + } + + // Substitute the original ELF with new one. + ErrorOr> BufOrErr = + MemoryBuffer::getFile(ELFTmpFileName); + if (!BufOrErr) { + handleErrorAsWarning(createFileError(ELFTmpFileName, + BufOrErr.getError())); + return std::move(Buf); + } + + return std::move(*BufOrErr); + } }; } // anonymous namespace @@ -337,6 +598,8 @@ return 1; } + BinaryWrapper Wrapper(Target, argv[0]); + // Read device binaries. SmallVector, 4u> Buffers; SmallVector, 4u> Images; @@ -349,8 +612,13 @@ reportError(createFileError(File, BufOrErr.getError())); return 1; } + std::unique_ptr Buffer(std::move(*BufOrErr)); + if (File != "-") { + // Adding ELF notes for STDIN is not supported yet. + Buffer = Wrapper.addELFNotes(std::move(Buffer), File); + } const std::unique_ptr &Buf = - Buffers.emplace_back(std::move(*BufOrErr)); + Buffers.emplace_back(std::move(Buffer)); Images.emplace_back(Buf->getBufferStart(), Buf->getBufferSize()); } @@ -363,7 +631,7 @@ } // Create a wrapper for device binaries and write its bitcode to the file. - WriteBitcodeToFile(BinaryWrapper(Target).wrapBinaries( + WriteBitcodeToFile(Wrapper.wrapBinaries( makeArrayRef(Images.data(), Images.size())), Out.os()); if (Out.os().has_error()) { Index: llvm/include/llvm/BinaryFormat/ELF.h =================================================================== --- llvm/include/llvm/BinaryFormat/ELF.h +++ llvm/include/llvm/BinaryFormat/ELF.h @@ -1606,6 +1606,13 @@ NT_AMDGPU_METADATA = 32 }; +// LLVMOMPOFFLOAD specific notes. +enum : unsigned { + NT_LLVM_OPENMP_OFFLOAD_VERSION = 1, + NT_LLVM_OPENMP_OFFLOAD_PRODUCER = 2, + NT_LLVM_OPENMP_OFFLOAD_PRODUCER_VERSION = 3 +}; + enum { GNU_ABI_TAG_LINUX = 0, GNU_ABI_TAG_HURD = 1, Index: llvm/tools/llvm-readobj/ELFDumper.cpp =================================================================== --- llvm/tools/llvm-readobj/ELFDumper.cpp +++ llvm/tools/llvm-readobj/ELFDumper.cpp @@ -4906,7 +4906,7 @@ return OS.str(); } -static StringRef getGNUGoldVersion(ArrayRef Desc) { +static StringRef getDescAsStringRef(ArrayRef Desc) { return StringRef(reinterpret_cast(Desc.data()), Desc.size()); } @@ -4930,7 +4930,7 @@ break; } case ELF::NT_GNU_GOLD_VERSION: - OS << " Version: " << getGNUGoldVersion(Desc); + OS << " Version: " << getDescAsStringRef(Desc); break; case ELF::NT_GNU_PROPERTY_TYPE_0: OS << " Properties:"; @@ -4942,6 +4942,26 @@ return true; } +template +static bool printLLVMOMPOFFLOADNote(raw_ostream &OS, uint32_t NoteType, + ArrayRef Desc) { + switch (NoteType) { + default: + return false; + case ELF::NT_LLVM_OPENMP_OFFLOAD_VERSION: + OS << " Version: " << getDescAsStringRef(Desc); + break; + case ELF::NT_LLVM_OPENMP_OFFLOAD_PRODUCER: + OS << " Producer: " << getDescAsStringRef(Desc); + break; + case ELF::NT_LLVM_OPENMP_OFFLOAD_PRODUCER_VERSION: + OS << " Producer version: " << getDescAsStringRef(Desc); + break; + } + OS << '\n'; + return true; +} + static const EnumEntry FreeBSDFeatureCtlFlags[] = { {"ASLR_DISABLE", NT_FREEBSD_FCTL_ASLR_DISABLE}, {"PROTMAX_DISABLE", NT_FREEBSD_FCTL_PROTMAX_DISABLE}, @@ -5254,6 +5274,15 @@ {ELF::NT_AMDGPU_METADATA, "NT_AMDGPU_METADATA (AMDGPU Metadata)"}, }; +static const NoteType LLVMOMPOFFLOADNoteTypes[] = { + {ELF::NT_LLVM_OPENMP_OFFLOAD_VERSION, + "NT_LLVM_OPENMP_OFFLOAD_VERSION (image format version)"}, + {ELF::NT_LLVM_OPENMP_OFFLOAD_PRODUCER, + "NT_LLVM_OPENMP_OFFLOAD_PRODUCER (producing toolchain)"}, + {ELF::NT_LLVM_OPENMP_OFFLOAD_PRODUCER_VERSION, + "NT_LLVM_OPENMP_OFFLOAD_PRODUCER_VERSION (producing toolchain version)"}, +}; + static const NoteType CoreNoteTypes[] = { {ELF::NT_PRSTATUS, "NT_PRSTATUS (prstatus structure)"}, {ELF::NT_FPREGSET, "NT_FPREGSET (floating point registers)"}, @@ -5347,6 +5376,8 @@ return FindNote(AMDNoteTypes); if (Name == "AMDGPU") return FindNote(AMDGPUNoteTypes); + if (Name == "LLVMOMPOFFLOAD") + return FindNote(LLVMOMPOFFLOADNoteTypes); if (ELFType == ELF::ET_CORE) return FindNote(CoreNoteTypes); @@ -5482,6 +5513,9 @@ OS << " " << N.Type << ":\n " << N.Value << '\n'; return Error::success(); } + } else if (Name == "LLVMOMPOFFLOAD") { + if (printLLVMOMPOFFLOADNote(OS, Type, Descriptor)) + return Error::success(); } else if (Name == "CORE") { if (Type == ELF::NT_FILE) { DataExtractor DescExtractor(Descriptor, @@ -6728,7 +6762,7 @@ break; } case ELF::NT_GNU_GOLD_VERSION: - W.printString("Version", getGNUGoldVersion(Desc)); + W.printString("Version", getDescAsStringRef(Desc)); break; case ELF::NT_GNU_PROPERTY_TYPE_0: ListScope D(W, "Property"); @@ -6739,6 +6773,26 @@ return true; } +template +static bool printLLVMOMPOFFLOADNoteLLVMStyle(uint32_t NoteType, + ArrayRef Desc, + ScopedPrinter &W) { + switch (NoteType) { + default: + return false; + case ELF::NT_LLVM_OPENMP_OFFLOAD_VERSION: + W.printString("Version", getDescAsStringRef(Desc)); + break; + case ELF::NT_LLVM_OPENMP_OFFLOAD_PRODUCER: + W.printString("Producer", getDescAsStringRef(Desc)); + break; + case ELF::NT_LLVM_OPENMP_OFFLOAD_PRODUCER_VERSION: + W.printString("Producer version", getDescAsStringRef(Desc)); + break; + } + return true; +} + static void printCoreNoteLLVMStyle(const CoreNote &Note, ScopedPrinter &W) { W.printNumber("Page Size", Note.PageSize); for (const CoreFileMapping &Mapping : Note.Mappings) { @@ -6806,6 +6860,9 @@ W.printString(N.Type, N.Value); return Error::success(); } + } else if (Name == "LLVMOMPOFFLOAD") { + if (printLLVMOMPOFFLOADNoteLLVMStyle(Type, Descriptor, W)) + return Error::success(); } else if (Name == "CORE") { if (Type == ELF::NT_FILE) { DataExtractor DescExtractor(Descriptor, 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,31 @@ # ##===----------------------------------------------------------------------===## -add_library(elf_common INTERFACE) +# Use libelf, is possible. +# Otherwise, use LLVM ELF (unless OPENMP_STANDALONE_BUILD). +set(MAY_USE_LIBELF LIBOMPTARGET_DEP_LIBELF_FOUND) +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(MAY_USE_LIBELF 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) + target_link_libraries(elf_common INTERFACE + LLVMBinaryFormat LLVMObject LLVMSupport) +else(MAY_USE_LIBELF AND NOT LIBOMPTARGET_FORCE_LLVM_ELF) + libomptarget_say("Not building elf_common offload plugin library: libelf dependency not found.") +endif(MAY_USE_LIBELF 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,23 @@ //===----------------------------------------------------------------------===// // // 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 LIBOMPTARGET_PLUGINS_ELF_COMMON_H +#define LIBOMPTARGET_PLUGINS_ELF_COMMON_H -#include -#include +#include +#include "elf_constants.h" +#include "omptargetplugin.h" -// 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 // LIBOMPTARGET_PLUGINS_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,92 @@ +//===-- 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 "Debug.h" +#include "elf_common.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; + + std::string NameStr(Note.getName(), Note.getNameSize()); + // Check if this is a null-terminated "LLVMOMPOFFLOAD" string. + std::string LlvmName("LLVMOMPOFFLOAD"); + LlvmName += '\0'; + if (NameStr != LlvmName) + 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,28 @@ +//===-- 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. +// +//===----------------------------------------------------------------------===// + +// 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", +}; Index: openmp/libomptarget/plugins/common/elf_common/elf_light.h =================================================================== --- /dev/null +++ openmp/libomptarget/plugins/common/elf_common/elf_light.h @@ -0,0 +1,122 @@ +//===-- 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 LIBOMPTARGET_PLUGINS_ELF_LIGHT_H +#define LIBOMPTARGET_PLUGINS_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(); + uint64_t getNameSize() const; + const char *getName() const; + uint64_t getDescSize() const; + 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 // LIBOMPTARGET_PLUGINS_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,1281 @@ +//===-- 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 +#include "Debug.h" +#include "elf_light.h" + +#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. +typedef struct { + 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) +} Elf_Note; + +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."); + + 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("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."); + + 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 *create_section_note_iterator_impl(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 *create_segment_note_iterator_impl(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("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("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->create_section_note_iterator_impl(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->create_segment_note_iterator_impl(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); + return Note->n_namesz; +} + +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 { + 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 { + 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 { + 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 *create_section_note_iterator_impl(bool IsEnd) const = 0; + virtual ElfLNoteIteratorImplBase *create_segment_note_iterator_impl(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("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 *create_section_note_iterator_impl( + bool IsEnd) const override { + return new ElfLSectionNoteIteratorImpl(File->getELFFile(), *Err, IsEnd); + } + + ElfLNoteIteratorImplBase *create_segment_note_iterator_impl( + 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) + 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 { + 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->create_section_note_iterator_impl(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->create_segment_note_iterator_impl(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")