| //===-------- GetDylibInterface.cpp - Get interface for real dylib --------===// |
| // |
| // 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 "llvm/ExecutionEngine/Orc/GetDylibInterface.h" |
| |
| #include "llvm/BinaryFormat/Magic.h" |
| #include "llvm/Object/MachO.h" |
| #include "llvm/Object/MachOUniversal.h" |
| #include "llvm/Object/TapiUniversal.h" |
| |
| #define DEBUG_TYPE "orc" |
| |
| namespace llvm::orc { |
| |
| Expected<SymbolNameSet> getDylibInterfaceFromDylib(ExecutionSession &ES, |
| Twine Path) { |
| auto CPUType = MachO::getCPUType(ES.getTargetTriple()); |
| if (!CPUType) |
| return CPUType.takeError(); |
| |
| auto CPUSubType = MachO::getCPUSubType(ES.getTargetTriple()); |
| if (!CPUSubType) |
| return CPUSubType.takeError(); |
| |
| auto Buf = MemoryBuffer::getFile(Path); |
| if (!Buf) |
| return createFileError(Path, Buf.getError()); |
| |
| auto BinFile = object::createBinary((*Buf)->getMemBufferRef()); |
| if (!BinFile) |
| return BinFile.takeError(); |
| |
| std::unique_ptr<object::MachOObjectFile> MachOFile; |
| if (isa<object::MachOObjectFile>(**BinFile)) |
| MachOFile.reset(dyn_cast<object::MachOObjectFile>(BinFile->release())); |
| else if (auto *MachOUni = |
| dyn_cast<object::MachOUniversalBinary>(BinFile->get())) { |
| for (auto &O : MachOUni->objects()) { |
| if (O.getCPUType() == *CPUType && O.getCPUSubType() == *CPUSubType) { |
| if (auto Obj = O.getAsObjectFile()) |
| MachOFile = std::move(*Obj); |
| else |
| return Obj.takeError(); |
| break; |
| } |
| } |
| if (!MachOFile) |
| return make_error<StringError>("MachO universal binary at " + Path + |
| " does not contain a slice for " + |
| ES.getTargetTriple().str(), |
| inconvertibleErrorCode()); |
| } else |
| return make_error<StringError>("File at " + Path + " is not a MachO", |
| inconvertibleErrorCode()); |
| |
| if (MachOFile->getHeader().filetype != MachO::MH_DYLIB) |
| return make_error<StringError>("MachO at " + Path + " is not a dylib", |
| inconvertibleErrorCode()); |
| |
| SymbolNameSet Symbols; |
| for (auto &Sym : MachOFile->symbols()) { |
| if (auto Name = Sym.getName()) |
| Symbols.insert(ES.intern(*Name)); |
| else |
| return Name.takeError(); |
| } |
| |
| return std::move(Symbols); |
| } |
| |
| Expected<SymbolNameSet> getDylibInterfaceFromTapiFile(ExecutionSession &ES, |
| Twine Path) { |
| SymbolNameSet Symbols; |
| |
| auto TapiFileBuffer = MemoryBuffer::getFile(Path); |
| if (!TapiFileBuffer) |
| return createFileError(Path, TapiFileBuffer.getError()); |
| |
| auto Tapi = |
| object::TapiUniversal::create((*TapiFileBuffer)->getMemBufferRef()); |
| if (!Tapi) |
| return Tapi.takeError(); |
| |
| auto CPUType = MachO::getCPUType(ES.getTargetTriple()); |
| if (!CPUType) |
| return CPUType.takeError(); |
| |
| auto CPUSubType = MachO::getCPUSubType(ES.getTargetTriple()); |
| if (!CPUSubType) |
| return CPUSubType.takeError(); |
| |
| auto &IF = (*Tapi)->getInterfaceFile(); |
| auto Interface = |
| IF.extract(MachO::getArchitectureFromCpuType(*CPUType, *CPUSubType)); |
| if (!Interface) |
| return Interface.takeError(); |
| |
| for (auto *Sym : (*Interface)->exports()) |
| Symbols.insert(ES.intern(Sym->getName())); |
| |
| return Symbols; |
| } |
| |
| Expected<SymbolNameSet> getDylibInterface(ExecutionSession &ES, Twine Path) { |
| file_magic Magic; |
| if (auto EC = identify_magic(Path, Magic)) |
| return createFileError(Path, EC); |
| |
| switch (Magic) { |
| case file_magic::macho_universal_binary: |
| case file_magic::macho_dynamically_linked_shared_lib: |
| return getDylibInterfaceFromDylib(ES, Path); |
| case file_magic::tapi_file: |
| return getDylibInterfaceFromTapiFile(ES, Path); |
| default: |
| return make_error<StringError>("Cannot get interface for " + Path + |
| " unrecognized file type", |
| inconvertibleErrorCode()); |
| } |
| } |
| |
| } // namespace llvm::orc |