xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/GetDylibInterface.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
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