LLVM 22.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 ObjArch = object::MachOObjectFile::getArch(Hdr.cputype, Hdr.cpusubtype);
52 if (ObjArch != TT.getArch())
54 objDesc(Obj, TT, ObjIsSlice) + Triple::getArchTypeName(ObjArch) +
55 ", cannot be loaded into " + TT.str() + " process",
57
58 return Error::success();
59}
60
62 bool ObjIsSlice) {
63 StringRef Data = Obj.getBuffer();
64
65 if (Data.size() < 4)
67 objDesc(Obj, TT, ObjIsSlice) +
68 " is not a valid MachO relocatable object file (truncated header)",
70
71 uint32_t Magic;
72 memcpy(&Magic, Data.data(), sizeof(uint32_t));
73
74 switch (Magic) {
75 case MachO::MH_MAGIC:
76 case MachO::MH_CIGAM:
78 std::move(Obj), Magic == MachO::MH_CIGAM, TT, ObjIsSlice);
82 std::move(Obj), Magic == MachO::MH_CIGAM_64, TT, ObjIsSlice);
83 default:
85 objDesc(Obj, TT, ObjIsSlice) +
86 " is not a valid MachO relocatable object (bad magic value)",
88 }
89}
90
92checkMachORelocatableObject(std::unique_ptr<MemoryBuffer> Obj, const Triple &TT,
93 bool ObjIsSlice) {
94 if (auto Err =
95 checkMachORelocatableObject(Obj->getMemBufferRef(), TT, ObjIsSlice))
96 return std::move(Err);
97 return std::move(Obj);
98}
99
102 std::optional<StringRef> IdentifierOverride) {
103 assert((TT.getObjectFormat() == Triple::UnknownObjectFormat ||
104 TT.getObjectFormat() == Triple::MachO) &&
105 "TT must specify MachO or Unknown object format");
106
107 if (!IdentifierOverride)
108 IdentifierOverride = Path;
109
112 if (!FDOrErr)
113 return createFileError(Path, FDOrErr.takeError());
114 sys::fs::file_t FD = *FDOrErr;
115 auto CloseFile = make_scope_exit([&]() { sys::fs::closeFile(FD); });
116
117 auto Buf =
118 MemoryBuffer::getOpenFile(FD, *IdentifierOverride, /*FileSize=*/-1);
119 if (!Buf)
121 StringRef("Could not load MachO object at path ") + Path,
122 Buf.getError());
123
124 switch (identify_magic((*Buf)->getBuffer())) {
126 auto CheckedObj = checkMachORelocatableObject(std::move(*Buf), TT, false);
127 if (!CheckedObj)
128 return CheckedObj.takeError();
129 return std::make_pair(std::move(*CheckedObj),
131 }
133 return loadLinkableSliceFromMachOUniversalBinary(FD, std::move(*Buf), TT,
135 *IdentifierOverride);
136 default:
138 Path + " does not contain a relocatable object file compatible with " +
139 TT.str(),
141 }
142}
143
146 std::unique_ptr<MemoryBuffer> UBBuf,
147 const Triple &TT, LoadArchives LA,
148 StringRef UBPath,
149 StringRef Identifier) {
150
151 auto UniversalBin =
152 object::MachOUniversalBinary::create(UBBuf->getMemBufferRef());
153 if (!UniversalBin)
154 return UniversalBin.takeError();
155
156 auto SliceRange = getMachOSliceRangeForTriple(**UniversalBin, TT);
157 if (!SliceRange)
158 return SliceRange.takeError();
159
160 auto Buf = MemoryBuffer::getOpenFileSlice(FD, Identifier, SliceRange->second,
161 SliceRange->first);
162 if (!Buf)
164 "Could not load " + TT.getArchName() +
165 " slice of MachO universal binary at path " + UBPath,
166 Buf.getError());
167
168 switch (identify_magic((*Buf)->getBuffer())) {
170 if (LA != LoadArchives::Never)
171 return std::make_pair(std::move(*Buf), LinkableFileKind::Archive);
172 break;
174 if (LA != LoadArchives::Required) {
175 auto CheckedObj = checkMachORelocatableObject(std::move(*Buf), TT, true);
176 if (!CheckedObj)
177 return CheckedObj.takeError();
178 return std::make_pair(std::move(*CheckedObj),
180 }
181 break;
182 }
183 default:
184 break;
185 }
186
187 auto FT = [&] {
188 switch (LA) {
190 return "a mach-o relocatable object file";
192 return "a mach-o relocatable object file or archive";
194 return "an archive";
195 }
196 llvm_unreachable("Unknown LoadArchives enum");
197 };
198
199 return make_error<StringError>(TT.getArchName() + " slice of " + UBPath +
200 " does not contain " + FT(),
202}
203
206 const Triple &TT) {
207
208 for (const auto &Obj : UB.objects()) {
209 auto ObjTT = Obj.getTriple();
210 if (ObjTT.getArch() == TT.getArch() &&
211 ObjTT.getSubArch() == TT.getSubArch() &&
212 (TT.getVendor() == Triple::UnknownVendor ||
213 ObjTT.getVendor() == TT.getVendor())) {
214 // We found a match. Return the range for the slice.
215 return std::make_pair(Obj.getOffset(), Obj.getSize());
216 }
217 }
218
219 return make_error<StringError>(Twine("Universal binary ") + UB.getFileName() +
220 " does not contain a slice for " +
221 TT.str(),
223}
224
227
229 if (!UB)
230 return UB.takeError();
231
232 return getMachOSliceRangeForTriple(**UB, TT);
233}
234
236 object::Archive &A, MemoryBufferRef MemberBuf, size_t Index) {
237
238 auto LoadMember = [&]() {
240 Index);
241 };
242
243 if (!ObjCOnly) {
244 // If we're loading all files then just load the buffer immediately. Return
245 // false to indicate that there's no further loading to do here.
246 if (auto Err = L.add(JD, LoadMember()))
247 return Err;
248 return false;
249 }
250
251 // We need to check whether this archive member contains any Objective-C
252 // or Swift metadata.
253 auto Obj = object::ObjectFile::createObjectFile(MemberBuf);
254 if (!Obj) {
255 // Invalid files are not loadable, but don't invalidate the archive.
256 consumeError(Obj.takeError());
257 return false;
258 }
259
260 if (auto *MachOObj = dyn_cast<object::MachOObjectFile>(&**Obj)) {
261 // Load the object if any recognized special section is present.
262 for (auto Sec : MachOObj->sections()) {
263 auto SegName =
264 MachOObj->getSectionFinalSegmentName(Sec.getRawDataRefImpl());
265 if (auto SecName = Sec.getName()) {
266 if (*SecName == "__objc_classlist" || *SecName == "__objc_protolist" ||
267 *SecName == "__objc_clsrolist" || *SecName == "__objc_catlist" ||
268 *SecName == "__objc_catlist2" || *SecName == "__objc_nlcatlist" ||
269 (SegName == "__TEXT" && (*SecName).starts_with("__swift") &&
270 *SecName != "__swift_modhash")) {
271 if (auto Err = L.add(JD, LoadMember()))
272 return Err;
273 return false;
274 }
275 } else
276 return SecName.takeError();
277 }
278 }
279
280 // This is an object file but we didn't load it, so return true to indicate
281 // that it's still loadable.
282 return true;
283}
284
286noFallbackArchs(uint32_t CPUType, uint32_t CPUSubType) {
288 Result.push_back({CPUType, CPUSubType});
289 return Result;
290}
291
295
296 // Match given CPU type/subtype first.
297 Archs.push_back({CPUType, CPUSubType});
298
299 switch (CPUType) {
301 // Handle arm64 variants.
302 switch (CPUSubType) {
304 Archs.push_back({CPUType, MachO::CPU_SUBTYPE_ARM64E});
305 break;
306 default:
307 break;
308 }
309 break;
310 default:
311 break;
312 }
313
314 return Archs;
315}
316
319 GetFallbackArchsFn GetFallbackArchs) {
320 auto InitCPUType = MachO::getCPUType(ES.getTargetTriple());
321 if (!InitCPUType)
322 return InitCPUType.takeError();
323
324 auto InitCPUSubType = MachO::getCPUSubType(ES.getTargetTriple());
325 if (!InitCPUSubType)
326 return InitCPUSubType.takeError();
327
328 auto Buf = MemoryBuffer::getFile(Path);
329 if (!Buf)
330 return createFileError(Path, Buf.getError());
331
332 auto BinFile = object::createBinary((*Buf)->getMemBufferRef());
333 if (!BinFile)
334 return BinFile.takeError();
335
336 std::unique_ptr<object::MachOObjectFile> MachOFile;
337 if (isa<object::MachOObjectFile>(**BinFile)) {
338 MachOFile.reset(dyn_cast<object::MachOObjectFile>(BinFile->release()));
339
340 // TODO: Check that dylib arch is compatible.
341 } else if (auto *MachOUni =
344 if (GetFallbackArchs)
345 ArchsToTry = GetFallbackArchs(*InitCPUType, *InitCPUSubType);
346 else
347 ArchsToTry.push_back({*InitCPUType, *InitCPUSubType});
348
349 for (auto &[CPUType, CPUSubType] : ArchsToTry) {
350 for (auto &O : MachOUni->objects()) {
351 if (O.getCPUType() == CPUType &&
352 (O.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK) == CPUSubType) {
353 if (auto Obj = O.getAsObjectFile())
354 MachOFile = std::move(*Obj);
355 else
356 return Obj.takeError();
357 break;
358 }
359 }
360 if (MachOFile) // If found, break out.
361 break;
362 }
363 if (!MachOFile)
365 "MachO universal binary at " + Path +
366 " does not contain a compatible slice for " +
367 ES.getTargetTriple().str(),
369 } else
370 return make_error<StringError>("File at " + Path + " is not a MachO",
372
373 if (MachOFile->getHeader().filetype != MachO::MH_DYLIB)
374 return make_error<StringError>("MachO at " + Path + " is not a dylib",
376
377 SymbolNameSet Symbols;
378 for (auto &Sym : MachOFile->symbols()) {
379 if (auto Name = Sym.getName())
380 Symbols.insert(ES.intern(*Name));
381 else
382 return Name.takeError();
383 }
384
385 return std::move(Symbols);
386}
387
390 GetFallbackArchsFn GetFallbackArchs) {
391 SymbolNameSet Symbols;
392
393 auto TapiFileBuffer = MemoryBuffer::getFile(Path);
394 if (!TapiFileBuffer)
395 return createFileError(Path, TapiFileBuffer.getError());
396
397 auto Tapi =
398 object::TapiUniversal::create((*TapiFileBuffer)->getMemBufferRef());
399 if (!Tapi)
400 return Tapi.takeError();
401
402 auto InitCPUType = MachO::getCPUType(ES.getTargetTriple());
403 if (!InitCPUType)
404 return InitCPUType.takeError();
405
406 auto InitCPUSubType = MachO::getCPUSubType(ES.getTargetTriple());
407 if (!InitCPUSubType)
408 return InitCPUSubType.takeError();
409
411 if (GetFallbackArchs)
412 ArchsToTry = GetFallbackArchs(*InitCPUType, *InitCPUSubType);
413 else
414 ArchsToTry.push_back({*InitCPUType, *InitCPUSubType});
415
416 auto &IF = (*Tapi)->getInterfaceFile();
417
418 auto ArchSet = IF.getArchitectures();
419 for (auto [CPUType, CPUSubType] : ArchsToTry) {
420 auto A = MachO::getArchitectureFromCpuType(CPUType, CPUSubType);
421 if (ArchSet.has(A)) {
422 if (auto Interface = IF.extract(A)) {
423 for (auto *Sym : (*Interface)->exports())
424 Symbols.insert(ES.intern(Sym->getName()));
425 return Symbols;
426 } else
427 return Interface.takeError();
428 }
429 }
430
432 "MachO interface file at " + Path +
433 " does not contain a compatible slice for " +
434 ES.getTargetTriple().str(),
436}
437
439 GetFallbackArchsFn GetFallbackArchs) {
440 file_magic Magic;
441 if (auto EC = identify_magic(Path, Magic))
442 return createFileError(Path, EC);
443
444 switch (Magic) {
447 return getDylibInterfaceFromDylib(ES, Path, std::move(GetFallbackArchs));
449 return getDylibInterfaceFromTapiFile(ES, Path, std::move(GetFallbackArchs));
450 default:
451 return make_error<StringError>("Cannot get interface for " + Path +
452 " unrecognized file type",
454 }
455}
456
457} // End namespace orc.
458} // 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:480
static LLVM_ABI StringRef getArchTypeName(ArchType Kind)
Get the canonical name for the Kind architecture.
Definition Triple.cpp:24
@ UnknownObjectFormat
Definition Triple.h:320
@ UnknownVendor
Definition Triple.h:188
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::ArchType getArch() const override
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:1342
const Triple & getTargetTriple() const
Return the triple for the executor.
Definition Core.h:1385
SymbolStringPtr intern(StringRef SymName)
Add a symbol name to the SymbolStringPool and return a pointer to it.
Definition Core.h:1396
LLVM_ABI Expected< bool > operator()(object::Archive &A, MemoryBufferRef MemberBuf, size_t Index)
Definition MachO.cpp:235
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:95
@ 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:77
@ 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:286
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:389
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:145
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:293
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:438
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:61
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:205
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:318
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:101
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.
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
detail::scope_exit< std::decay_t< Callable > > make_scope_exit(Callable &&F)
Definition ScopeExit.h:59
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:98
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