LLVM 23.0.0git
MachO.cpp
Go to the documentation of this file.
1//===----------------- MachO.cpp - MachO format utilities -----------------===//
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
10
11#include "llvm/ADT/ScopeExit.h"
19
20#define DEBUG_TYPE "orc"
21
22namespace llvm {
23namespace orc {
24
25static std::string objDesc(const MemoryBufferRef &Obj, const Triple &TT,
26 bool ObjIsSlice) {
27 std::string Desc;
28 if (ObjIsSlice)
29 Desc += (TT.getArchName() + " slice of universal binary ").str();
30 Desc += Obj.getBufferIdentifier();
31 return Desc;
32}
33
34template <typename HeaderType>
36 bool SwapEndianness, const Triple &TT,
37 bool ObjIsSlice) {
38 StringRef Data = Obj.getBuffer();
39
40 HeaderType Hdr;
41 memcpy(&Hdr, Data.data(), sizeof(HeaderType));
42
43 if (SwapEndianness)
44 swapStruct(Hdr);
45
46 if (Hdr.filetype != MachO::MH_OBJECT)
47 return make_error<StringError>(objDesc(Obj, TT, ObjIsSlice) +
48 " is not a MachO relocatable object",
50
51 auto ObjArchTT =
52 object::MachOObjectFile::getArchTriple(Hdr.cputype, Hdr.cpusubtype);
53 if (ObjArchTT.getArch() != TT.getArch())
55 objDesc(Obj, TT, ObjIsSlice) + " (" + ObjArchTT.getArchName() +
56 "), cannot be loaded into " + TT.str() + " process",
58
59 return Error::success();
60}
61
63 bool ObjIsSlice) {
64 StringRef Data = Obj.getBuffer();
65
66 if (Data.size() < 4)
68 objDesc(Obj, TT, ObjIsSlice) +
69 " is not a valid MachO relocatable object file (truncated header)",
71
72 uint32_t Magic;
73 memcpy(&Magic, Data.data(), sizeof(uint32_t));
74
75 switch (Magic) {
76 case MachO::MH_MAGIC:
77 case MachO::MH_CIGAM:
79 std::move(Obj), Magic == MachO::MH_CIGAM, TT, ObjIsSlice);
83 std::move(Obj), Magic == MachO::MH_CIGAM_64, TT, ObjIsSlice);
84 default:
86 objDesc(Obj, TT, ObjIsSlice) +
87 " is not a valid MachO relocatable object (bad magic value)",
89 }
90}
91
93checkMachORelocatableObject(std::unique_ptr<MemoryBuffer> Obj, const Triple &TT,
94 bool ObjIsSlice) {
95 if (auto Err =
96 checkMachORelocatableObject(Obj->getMemBufferRef(), TT, ObjIsSlice))
97 return std::move(Err);
98 return std::move(Obj);
99}
100
103 std::optional<StringRef> IdentifierOverride) {
104 assert((TT.getObjectFormat() == Triple::UnknownObjectFormat ||
105 TT.getObjectFormat() == Triple::MachO) &&
106 "TT must specify MachO or Unknown object format");
107
108 if (!IdentifierOverride)
109 IdentifierOverride = Path;
110
113 if (!FDOrErr)
114 return createFileError(Path, FDOrErr.takeError());
115 sys::fs::file_t FD = *FDOrErr;
116 llvm::scope_exit CloseFile([&]() { sys::fs::closeFile(FD); });
117
118 auto Buf =
119 MemoryBuffer::getOpenFile(FD, *IdentifierOverride, /*FileSize=*/-1);
120 if (!Buf)
122 StringRef("Could not load MachO object at path ") + Path,
123 Buf.getError());
124
125 switch (identify_magic((*Buf)->getBuffer())) {
127 auto CheckedObj = checkMachORelocatableObject(std::move(*Buf), TT, false);
128 if (!CheckedObj)
129 return CheckedObj.takeError();
130 return std::make_pair(std::move(*CheckedObj),
132 }
134 return loadLinkableSliceFromMachOUniversalBinary(FD, std::move(*Buf), TT,
136 *IdentifierOverride);
137 default:
139 Path + " does not contain a relocatable object file compatible with " +
140 TT.str(),
142 }
143}
144
147 std::unique_ptr<MemoryBuffer> UBBuf,
148 const Triple &TT, LoadArchives LA,
149 StringRef UBPath,
150 StringRef Identifier) {
151
152 auto UniversalBin =
153 object::MachOUniversalBinary::create(UBBuf->getMemBufferRef());
154 if (!UniversalBin)
155 return UniversalBin.takeError();
156
157 auto SliceRange = getMachOSliceRangeForTriple(**UniversalBin, TT);
158 if (!SliceRange)
159 return SliceRange.takeError();
160
161 auto Buf = MemoryBuffer::getOpenFileSlice(FD, Identifier, SliceRange->second,
162 SliceRange->first);
163 if (!Buf)
165 "Could not load " + TT.getArchName() +
166 " slice of MachO universal binary at path " + UBPath,
167 Buf.getError());
168
169 switch (identify_magic((*Buf)->getBuffer())) {
171 if (LA != LoadArchives::Never)
172 return std::make_pair(std::move(*Buf), LinkableFileKind::Archive);
173 break;
175 if (LA != LoadArchives::Required) {
176 auto CheckedObj = checkMachORelocatableObject(std::move(*Buf), TT, true);
177 if (!CheckedObj)
178 return CheckedObj.takeError();
179 return std::make_pair(std::move(*CheckedObj),
181 }
182 break;
183 }
184 default:
185 break;
186 }
187
188 auto FT = [&] {
189 switch (LA) {
191 return "a mach-o relocatable object file";
193 return "a mach-o relocatable object file or archive";
195 return "an archive";
196 }
197 llvm_unreachable("Unknown LoadArchives enum");
198 };
199
200 return make_error<StringError>(TT.getArchName() + " slice of " + UBPath +
201 " does not contain " + FT(),
203}
204
207 const Triple &TT) {
208
209 for (const auto &Obj : UB.objects()) {
210 auto ObjTT = Obj.getTriple();
211 if (ObjTT.getArch() == TT.getArch() &&
212 ObjTT.getSubArch() == TT.getSubArch() &&
213 (TT.getVendor() == Triple::UnknownVendor ||
214 ObjTT.getVendor() == TT.getVendor())) {
215 // We found a match. Return the range for the slice.
216 return std::make_pair(Obj.getOffset(), Obj.getSize());
217 }
218 }
219
220 return make_error<StringError>(Twine("Universal binary ") + UB.getFileName() +
221 " does not contain a slice for " +
222 TT.str(),
224}
225
228
230 if (!UB)
231 return UB.takeError();
232
233 return getMachOSliceRangeForTriple(**UB, TT);
234}
235
237 object::Archive &A, MemoryBufferRef MemberBuf, size_t Index) {
238
239 auto LoadMember = [&]() {
241 Index);
242 };
243
244 if (!ObjCOnly) {
245 // If we're loading all files then just load the buffer immediately. Return
246 // false to indicate that there's no further loading to do here.
247 if (auto Err = L.add(JD, LoadMember()))
248 return Err;
249 return false;
250 }
251
252 // We need to check whether this archive member contains any Objective-C
253 // or Swift metadata.
254 auto Obj = object::ObjectFile::createObjectFile(MemberBuf);
255 if (!Obj) {
256 // Invalid files are not loadable, but don't invalidate the archive.
257 consumeError(Obj.takeError());
258 return false;
259 }
260
261 if (auto *MachOObj = dyn_cast<object::MachOObjectFile>(&**Obj)) {
262 // Load the object if any recognized special section is present.
263 for (auto Sec : MachOObj->sections()) {
264 auto SegName =
265 MachOObj->getSectionFinalSegmentName(Sec.getRawDataRefImpl());
266 if (auto SecName = Sec.getName()) {
267 if (*SecName == "__objc_classlist" || *SecName == "__objc_protolist" ||
268 *SecName == "__objc_clsrolist" || *SecName == "__objc_catlist" ||
269 *SecName == "__objc_catlist2" || *SecName == "__objc_nlcatlist" ||
270 (SegName == "__TEXT" && (*SecName).starts_with("__swift") &&
271 *SecName != "__swift_modhash")) {
272 if (auto Err = L.add(JD, LoadMember()))
273 return Err;
274 return false;
275 }
276 } else
277 return SecName.takeError();
278 }
279 }
280
281 // This is an object file but we didn't load it, so return true to indicate
282 // that it's still loadable.
283 return true;
284}
285
287noFallbackArchs(uint32_t CPUType, uint32_t CPUSubType) {
289 Result.push_back({CPUType, CPUSubType});
290 return Result;
291}
292
296
297 // Match given CPU type/subtype first.
298 Archs.push_back({CPUType, CPUSubType});
299
300 switch (CPUType) {
302 // Handle arm64 variants.
303 switch (CPUSubType) {
305 Archs.push_back({CPUType, MachO::CPU_SUBTYPE_ARM64E});
306 break;
307 default:
308 break;
309 }
310 break;
311 default:
312 break;
313 }
314
315 return Archs;
316}
317
320 GetFallbackArchsFn GetFallbackArchs) {
321 auto InitCPUType = MachO::getCPUType(ES.getTargetTriple());
322 if (!InitCPUType)
323 return InitCPUType.takeError();
324
325 auto InitCPUSubType = MachO::getCPUSubType(ES.getTargetTriple());
326 if (!InitCPUSubType)
327 return InitCPUSubType.takeError();
328
329 auto Buf = MemoryBuffer::getFile(Path);
330 if (!Buf)
331 return createFileError(Path, Buf.getError());
332
333 auto BinFile = object::createBinary((*Buf)->getMemBufferRef());
334 if (!BinFile)
335 return BinFile.takeError();
336
337 std::unique_ptr<object::MachOObjectFile> MachOFile;
338 if (isa<object::MachOObjectFile>(**BinFile)) {
339 MachOFile.reset(dyn_cast<object::MachOObjectFile>(BinFile->release()));
340
341 // TODO: Check that dylib arch is compatible.
342 } else if (auto *MachOUni =
345 if (GetFallbackArchs)
346 ArchsToTry = GetFallbackArchs(*InitCPUType, *InitCPUSubType);
347 else
348 ArchsToTry.push_back({*InitCPUType, *InitCPUSubType});
349
350 for (auto &[CPUType, CPUSubType] : ArchsToTry) {
351 for (auto &O : MachOUni->objects()) {
352 if (O.getCPUType() == CPUType &&
353 (O.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK) == CPUSubType) {
354 if (auto Obj = O.getAsObjectFile())
355 MachOFile = std::move(*Obj);
356 else
357 return Obj.takeError();
358 break;
359 }
360 }
361 if (MachOFile) // If found, break out.
362 break;
363 }
364 if (!MachOFile)
366 "MachO universal binary at " + Path +
367 " does not contain a compatible slice for " +
368 ES.getTargetTriple().str(),
370 } else
371 return make_error<StringError>("File at " + Path + " is not a MachO",
373
374 if (MachOFile->getHeader().filetype != MachO::MH_DYLIB)
375 return make_error<StringError>("MachO at " + Path + " is not a dylib",
377
378 SymbolNameSet Symbols;
379 for (auto &Sym : MachOFile->symbols()) {
380 if (auto Name = Sym.getName())
381 Symbols.insert(ES.intern(*Name));
382 else
383 return Name.takeError();
384 }
385
386 return std::move(Symbols);
387}
388
391 GetFallbackArchsFn GetFallbackArchs) {
392 SymbolNameSet Symbols;
393
394 auto TapiFileBuffer = MemoryBuffer::getFile(Path);
395 if (!TapiFileBuffer)
396 return createFileError(Path, TapiFileBuffer.getError());
397
398 auto Tapi =
399 object::TapiUniversal::create((*TapiFileBuffer)->getMemBufferRef());
400 if (!Tapi)
401 return Tapi.takeError();
402
403 auto InitCPUType = MachO::getCPUType(ES.getTargetTriple());
404 if (!InitCPUType)
405 return InitCPUType.takeError();
406
407 auto InitCPUSubType = MachO::getCPUSubType(ES.getTargetTriple());
408 if (!InitCPUSubType)
409 return InitCPUSubType.takeError();
410
412 if (GetFallbackArchs)
413 ArchsToTry = GetFallbackArchs(*InitCPUType, *InitCPUSubType);
414 else
415 ArchsToTry.push_back({*InitCPUType, *InitCPUSubType});
416
417 auto &IF = (*Tapi)->getInterfaceFile();
418
419 auto ArchSet = IF.getArchitectures();
420 for (auto [CPUType, CPUSubType] : ArchsToTry) {
421 auto A = MachO::getArchitectureFromCpuType(CPUType, CPUSubType);
422 if (ArchSet.has(A)) {
423 if (auto Interface = IF.extract(A)) {
424 for (auto *Sym : (*Interface)->exports())
425 Symbols.insert(ES.intern(Sym->getName()));
426 return Symbols;
427 } else
428 return Interface.takeError();
429 }
430 }
431
433 "MachO interface file at " + Path +
434 " does not contain a compatible slice for " +
435 ES.getTargetTriple().str(),
437}
438
440 GetFallbackArchsFn GetFallbackArchs) {
441 file_magic Magic;
442 if (auto EC = identify_magic(Path, Magic))
443 return createFileError(Path, EC);
444
445 switch (Magic) {
448 return getDylibInterfaceFromDylib(ES, Path, std::move(GetFallbackArchs));
450 return getDylibInterfaceFromTapiFile(ES, Path, std::move(GetFallbackArchs));
451 default:
452 return make_error<StringError>("Cannot get interface for " + Path +
453 " unrecognized file type",
455 }
456}
457
458} // End namespace orc.
459} // End namespace llvm.
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
This file defines the make_scope_exit function, which executes user-defined cleanup logic at scope ex...
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Tagged union holding either a T or a Error.
Definition Error.h:485
Error takeError()
Take ownership of the stored error.
Definition Error.h:612
static ErrorOr< std::unique_ptr< MemoryBuffer > > getOpenFile(sys::fs::file_t FD, const Twine &Filename, uint64_t FileSize, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)
Given an already-open file descriptor, read the file and return a MemoryBuffer.
static ErrorOr< std::unique_ptr< MemoryBuffer > > getOpenFileSlice(sys::fs::file_t FD, const Twine &Filename, uint64_t MapSize, int64_t Offset, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)
Given an already-open file descriptor, map some slice of it into a MemoryBuffer.
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
Triple - Helper class for working with autoconf configuration names.
Definition Triple.h:47
const std::string & str() const
Definition Triple.h:485
@ UnknownObjectFormat
Definition Triple.h:325
@ UnknownVendor
Definition Triple.h:189
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
StringRef getFileName() const
Definition Binary.cpp:41
Triple getArchTriple(const char **McpuDefault=nullptr) const
static Expected< std::unique_ptr< MachOUniversalBinary > > create(MemoryBufferRef Source)
iterator_range< object_iterator > objects() const
static Expected< OwningBinary< ObjectFile > > createObjectFile(StringRef ObjectPath)
static Expected< std::unique_ptr< TapiUniversal > > create(MemoryBufferRef Source)
An ExecutionSession represents a running JIT program.
Definition Core.h:1355
const Triple & getTargetTriple() const
Return the triple for the executor.
Definition Core.h:1398
SymbolStringPtr intern(StringRef SymName)
Add a symbol name to the SymbolStringPool and return a pointer to it.
Definition Core.h:1409
LLVM_ABI Expected< bool > operator()(object::Archive &A, MemoryBufferRef MemberBuf, size_t Index)
Definition MachO.cpp:236
static std::unique_ptr< MemoryBuffer > createMemberBuffer(object::Archive &A, MemoryBufferRef BufRef, size_t Index)
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
LLVM_ABI Expected< uint32_t > getCPUSubType(const Triple &T)
Definition MachO.cpp:101
@ MH_OBJECT
Definition MachO.h:43
@ MH_DYLIB
Definition MachO.h:48
@ MH_MAGIC
Definition MachO.h:30
@ MH_CIGAM_64
Definition MachO.h:33
@ MH_CIGAM
Definition MachO.h:31
@ MH_MAGIC_64
Definition MachO.h:32
@ CPU_SUBTYPE_ARM64E
Definition MachO.h:1645
@ CPU_SUBTYPE_ARM64_ALL
Definition MachO.h:1643
LLVM_ABI Architecture getArchitectureFromCpuType(uint32_t CPUType, uint32_t CPUSubType)
Convert a CPU Type and Subtype pair to an architecture slice.
LLVM_ABI Expected< uint32_t > getCPUType(const Triple &T)
Definition MachO.cpp:81
@ CPU_SUBTYPE_MASK
Definition MachO.h:1581
@ CPU_TYPE_ARM64
Definition MachO.h:1570
LLVM_ABI Expected< std::unique_ptr< Binary > > createBinary(MemoryBufferRef Source, LLVMContext *Context=nullptr, bool InitContent=true)
Create a Binary from Source, autodetecting the file type.
Definition Binary.cpp:45
LLVM_ABI SmallVector< std::pair< uint32_t, uint32_t > > noFallbackArchs(uint32_t CPUType, uint32_t CPUSubType)
Match the exact CPU type/subtype only.
Definition MachO.cpp:287
LLVM_ABI Expected< SymbolNameSet > getDylibInterfaceFromTapiFile(ExecutionSession &ES, Twine Path, GetFallbackArchsFn GetFallbackArchs=standardMachOFallbackArchs)
Returns a SymbolNameSet containing the exported symbols defined in the relevant slice of the TapiUniv...
Definition MachO.cpp:390
LLVM_ABI Expected< std::pair< std::unique_ptr< MemoryBuffer >, LinkableFileKind > > loadLinkableSliceFromMachOUniversalBinary(sys::fs::file_t FD, std::unique_ptr< MemoryBuffer > UBBuf, const Triple &TT, LoadArchives LA, StringRef UBPath, StringRef Identifier)
Load a compatible relocatable object (if available) from a MachO universal binary.
Definition MachO.cpp:146
unique_function< SmallVector< std::pair< uint32_t, uint32_t > >( uint32_t CPUType, uint32_t CPUSubType)> GetFallbackArchsFn
Definition MachO.h:98
LLVM_ABI SmallVector< std::pair< uint32_t, uint32_t > > standardMachOFallbackArchs(uint32_t CPUType, uint32_t CPUSubType)
Match standard dynamic loader fallback rules.
Definition MachO.cpp:294
LLVM_ABI Expected< SymbolNameSet > getDylibInterface(ExecutionSession &ES, Twine Path, GetFallbackArchsFn GetFallbackArchs=standardMachOFallbackArchs)
Returns a SymbolNameSet containing the exported symbols defined in the relevant slice of the given fi...
Definition MachO.cpp:439
LLVM_ABI Error checkMachORelocatableObject(MemoryBufferRef Obj, const Triple &TT, bool ObjIsSlice)
Check that the given buffer contains a MachO object file compatible with the given triple.
Definition MachO.cpp:62
LLVM_ABI Expected< std::pair< size_t, size_t > > getMachOSliceRangeForTriple(object::MachOUniversalBinary &UB, const Triple &TT)
Utility for identifying the file-slice compatible with TT in a universal binary.
Definition MachO.cpp:206
LLVM_ABI Expected< SymbolNameSet > getDylibInterfaceFromDylib(ExecutionSession &ES, Twine Path, GetFallbackArchsFn GetFallbackArchs=standardMachOFallbackArchs)
Returns a SymbolNameSet containing the exported symbols defined in the given dylib.
Definition MachO.cpp:319
DenseSet< SymbolStringPtr > SymbolNameSet
A set of symbol names (represented by SymbolStringPtrs for.
static std::string objDesc(const MemoryBufferRef &Obj, const Triple &TT, bool ObjIsSlice)
Definition MachO.cpp:25
Expected< std::pair< std::unique_ptr< MemoryBuffer >, LinkableFileKind > > loadMachORelocatableObject(StringRef Path, const Triple &TT, LoadArchives LA, std::optional< StringRef > IdentifierOverride)
Definition MachO.cpp:102
LLVM_ABI std::error_code closeFile(file_t &F)
Close the file object.
LLVM_ABI Expected< file_t > openNativeFileForRead(const Twine &Name, OpenFlags Flags=OF_None, SmallVectorImpl< char > *RealPath=nullptr)
Opens the file with the given name in a read-only mode, returning its open file descriptor.
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
LLVM_ABI file_magic identify_magic(StringRef magic)
Identify the type of a binary file based on how magical it is.
Definition Magic.cpp:33
Error createFileError(const Twine &F, Error E)
Concatenate a source file path and/or name with an Error.
Definition Error.h:1399
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
LLVM_ABI std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition Error.cpp:94
Op::Description Desc
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
Definition Error.h:340
FunctionAddr VTableAddr uintptr_t uintptr_t Data
Definition InstrProf.h:189
void consumeError(Error Err)
Consume a Error without doing anything.
Definition Error.h:1083
file_magic - An "enum class" enumeration of file types based on magic (the first N bytes of the file)...
Definition Magic.h:21
@ archive
ar style archive file
Definition Magic.h:26
@ macho_dynamically_linked_shared_lib
Mach-O dynlinked shared lib.
Definition Magic.h:38
@ macho_universal_binary
Mach-O universal binary.
Definition Magic.h:44
@ macho_object
Mach-O Object file.
Definition Magic.h:33
@ tapi_file
Text-based Dynamic Library Stub file.
Definition Magic.h:56