1 //===-------- GetDylibInterface.cpp - Get interface for real dylib --------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/ExecutionEngine/Orc/GetDylibInterface.h" 10 11 #include "llvm/BinaryFormat/Magic.h" 12 #include "llvm/Object/MachO.h" 13 #include "llvm/Object/MachOUniversal.h" 14 #include "llvm/Object/TapiUniversal.h" 15 16 #define DEBUG_TYPE "orc" 17 18 namespace llvm::orc { 19 20 Expected<SymbolNameSet> getDylibInterfaceFromDylib(ExecutionSession &ES, 21 Twine Path) { 22 auto CPUType = MachO::getCPUType(ES.getTargetTriple()); 23 if (!CPUType) 24 return CPUType.takeError(); 25 26 auto CPUSubType = MachO::getCPUSubType(ES.getTargetTriple()); 27 if (!CPUSubType) 28 return CPUSubType.takeError(); 29 30 auto Buf = MemoryBuffer::getFile(Path); 31 if (!Buf) 32 return createFileError(Path, Buf.getError()); 33 34 auto BinFile = object::createBinary((*Buf)->getMemBufferRef()); 35 if (!BinFile) 36 return BinFile.takeError(); 37 38 std::unique_ptr<object::MachOObjectFile> MachOFile; 39 if (isa<object::MachOObjectFile>(**BinFile)) 40 MachOFile.reset(dyn_cast<object::MachOObjectFile>(BinFile->release())); 41 else if (auto *MachOUni = 42 dyn_cast<object::MachOUniversalBinary>(BinFile->get())) { 43 for (auto &O : MachOUni->objects()) { 44 if (O.getCPUType() == *CPUType && 45 (O.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK) == *CPUSubType) { 46 if (auto Obj = O.getAsObjectFile()) 47 MachOFile = std::move(*Obj); 48 else 49 return Obj.takeError(); 50 break; 51 } 52 } 53 if (!MachOFile) 54 return make_error<StringError>("MachO universal binary at " + Path + 55 " does not contain a slice for " + 56 ES.getTargetTriple().str(), 57 inconvertibleErrorCode()); 58 } else 59 return make_error<StringError>("File at " + Path + " is not a MachO", 60 inconvertibleErrorCode()); 61 62 if (MachOFile->getHeader().filetype != MachO::MH_DYLIB) 63 return make_error<StringError>("MachO at " + Path + " is not a dylib", 64 inconvertibleErrorCode()); 65 66 SymbolNameSet Symbols; 67 for (auto &Sym : MachOFile->symbols()) { 68 if (auto Name = Sym.getName()) 69 Symbols.insert(ES.intern(*Name)); 70 else 71 return Name.takeError(); 72 } 73 74 return std::move(Symbols); 75 } 76 77 Expected<SymbolNameSet> getDylibInterfaceFromTapiFile(ExecutionSession &ES, 78 Twine Path) { 79 SymbolNameSet Symbols; 80 81 auto TapiFileBuffer = MemoryBuffer::getFile(Path); 82 if (!TapiFileBuffer) 83 return createFileError(Path, TapiFileBuffer.getError()); 84 85 auto Tapi = 86 object::TapiUniversal::create((*TapiFileBuffer)->getMemBufferRef()); 87 if (!Tapi) 88 return Tapi.takeError(); 89 90 auto CPUType = MachO::getCPUType(ES.getTargetTriple()); 91 if (!CPUType) 92 return CPUType.takeError(); 93 94 auto CPUSubType = MachO::getCPUSubType(ES.getTargetTriple()); 95 if (!CPUSubType) 96 return CPUSubType.takeError(); 97 98 auto &IF = (*Tapi)->getInterfaceFile(); 99 auto Interface = 100 IF.extract(MachO::getArchitectureFromCpuType(*CPUType, *CPUSubType)); 101 if (!Interface) 102 return Interface.takeError(); 103 104 for (auto *Sym : (*Interface)->exports()) 105 Symbols.insert(ES.intern(Sym->getName())); 106 107 return Symbols; 108 } 109 110 Expected<SymbolNameSet> getDylibInterface(ExecutionSession &ES, Twine Path) { 111 file_magic Magic; 112 if (auto EC = identify_magic(Path, Magic)) 113 return createFileError(Path, EC); 114 115 switch (Magic) { 116 case file_magic::macho_universal_binary: 117 case file_magic::macho_dynamically_linked_shared_lib: 118 return getDylibInterfaceFromDylib(ES, Path); 119 case file_magic::tapi_file: 120 return getDylibInterfaceFromTapiFile(ES, Path); 121 default: 122 return make_error<StringError>("Cannot get interface for " + Path + 123 " unrecognized file type", 124 inconvertibleErrorCode()); 125 } 126 } 127 128 } // namespace llvm::orc 129