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