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"
17
18#define DEBUG_TYPE "orc"
19
20namespace llvm {
21namespace orc {
22
23static std::string objDesc(const MemoryBufferRef &Obj, const Triple &TT,
24 bool ObjIsSlice) {
25 std::string Desc;
26 if (ObjIsSlice)
27 Desc += (TT.getArchName() + " slice of universal binary").str();
29 return Desc;
30}
31
32template <typename HeaderType>
34 bool SwapEndianness, const Triple &TT,
35 bool ObjIsSlice) {
36 StringRef Data = Obj.getBuffer();
37
38 HeaderType Hdr;
39 memcpy(&Hdr, Data.data(), sizeof(HeaderType));
40
41 if (SwapEndianness)
42 swapStruct(Hdr);
43
44 if (Hdr.filetype != MachO::MH_OBJECT)
45 return make_error<StringError>(objDesc(Obj, TT, ObjIsSlice) +
46 " is not a MachO relocatable object",
48
49 auto ObjArch = object::MachOObjectFile::getArch(Hdr.cputype, Hdr.cpusubtype);
50 if (ObjArch != TT.getArch())
51 return make_error<StringError>(
52 objDesc(Obj, TT, ObjIsSlice) + Triple::getArchTypeName(ObjArch) +
53 ", cannot be loaded into " + TT.str() + " process",
55
56 return Error::success();
57}
58
60 bool ObjIsSlice) {
61 StringRef Data = Obj.getBuffer();
62
63 if (Data.size() < 4)
64 return make_error<StringError>(
65 objDesc(Obj, TT, ObjIsSlice) +
66 " is not a valid MachO relocatable object file (truncated header)",
68
69 uint32_t Magic;
70 memcpy(&Magic, Data.data(), sizeof(uint32_t));
71
72 switch (Magic) {
73 case MachO::MH_MAGIC:
74 case MachO::MH_CIGAM:
75 return checkMachORelocatableObject<MachO::mach_header>(
76 std::move(Obj), Magic == MachO::MH_CIGAM, TT, ObjIsSlice);
79 return checkMachORelocatableObject<MachO::mach_header_64>(
80 std::move(Obj), Magic == MachO::MH_CIGAM_64, TT, ObjIsSlice);
81 default:
82 return make_error<StringError>(
83 objDesc(Obj, TT, ObjIsSlice) +
84 " is not a valid MachO relocatable object (bad magic value)",
86 }
87}
88
90checkMachORelocatableObject(std::unique_ptr<MemoryBuffer> Obj, const Triple &TT,
91 bool ObjIsSlice) {
92 if (auto Err =
93 checkMachORelocatableObject(Obj->getMemBufferRef(), TT, ObjIsSlice))
94 return std::move(Err);
95 return std::move(Obj);
96}
97
100 std::optional<StringRef> IdentifierOverride) {
101 assert((TT.getObjectFormat() == Triple::UnknownObjectFormat ||
102 TT.getObjectFormat() == Triple::MachO) &&
103 "TT must specify MachO or Unknown object format");
104
105 if (!IdentifierOverride)
106 IdentifierOverride = Path;
107
110 if (!FDOrErr)
111 return createFileError(Path, FDOrErr.takeError());
112 sys::fs::file_t FD = *FDOrErr;
113 auto CloseFile = make_scope_exit([&]() { sys::fs::closeFile(FD); });
114
115 auto Buf =
116 MemoryBuffer::getOpenFile(FD, *IdentifierOverride, /*FileSize=*/-1);
117 if (!Buf)
118 return make_error<StringError>(
119 StringRef("Could not load MachO object at path ") + Path,
120 Buf.getError());
121
122 switch (identify_magic((*Buf)->getBuffer())) {
124 auto CheckedObj = checkMachORelocatableObject(std::move(*Buf), TT, false);
125 if (!CheckedObj)
126 return CheckedObj.takeError();
127 return std::make_pair(std::move(*CheckedObj),
129 }
131 return loadLinkableSliceFromMachOUniversalBinary(FD, std::move(*Buf), TT,
133 *IdentifierOverride);
134 default:
135 return make_error<StringError>(
136 Path + " does not contain a relocatable object file compatible with " +
137 TT.str(),
139 }
140}
141
144 std::unique_ptr<MemoryBuffer> UBBuf,
145 const Triple &TT, LoadArchives LA,
146 StringRef UBPath,
147 StringRef Identifier) {
148
149 auto UniversalBin =
150 object::MachOUniversalBinary::create(UBBuf->getMemBufferRef());
151 if (!UniversalBin)
152 return UniversalBin.takeError();
153
154 auto SliceRange = getMachOSliceRangeForTriple(**UniversalBin, TT);
155 if (!SliceRange)
156 return SliceRange.takeError();
157
158 auto Buf = MemoryBuffer::getOpenFileSlice(FD, Identifier, SliceRange->second,
159 SliceRange->first);
160 if (!Buf)
161 return make_error<StringError>(
162 "Could not load " + TT.getArchName() +
163 " slice of MachO universal binary at path " + UBPath,
164 Buf.getError());
165
166 switch (identify_magic((*Buf)->getBuffer())) {
168 if (LA != LoadArchives::Never)
169 return std::make_pair(std::move(*Buf), LinkableFileKind::Archive);
170 break;
172 if (LA != LoadArchives::Required) {
173 auto CheckedObj = checkMachORelocatableObject(std::move(*Buf), TT, true);
174 if (!CheckedObj)
175 return CheckedObj.takeError();
176 return std::make_pair(std::move(*CheckedObj),
178 }
179 break;
180 }
181 default:
182 break;
183 }
184
185 auto FT = [&] {
186 switch (LA) {
188 return "a mach-o relocatable object file";
190 return "a mach-o relocatable object file or archive";
192 return "an archive";
193 }
194 llvm_unreachable("Unknown LoadArchives enum");
195 };
196
197 return make_error<StringError>(TT.getArchName() + " slice of " + UBPath +
198 " does not contain " + FT(),
200}
201
204 const Triple &TT) {
205
206 for (const auto &Obj : UB.objects()) {
207 auto ObjTT = Obj.getTriple();
208 if (ObjTT.getArch() == TT.getArch() &&
209 ObjTT.getSubArch() == TT.getSubArch() &&
210 (TT.getVendor() == Triple::UnknownVendor ||
211 ObjTT.getVendor() == TT.getVendor())) {
212 // We found a match. Return the range for the slice.
213 return std::make_pair(Obj.getOffset(), Obj.getSize());
214 }
215 }
216
217 return make_error<StringError>(Twine("Universal binary ") + UB.getFileName() +
218 " does not contain a slice for " +
219 TT.str(),
221}
222
225
227 if (!UB)
228 return UB.takeError();
229
230 return getMachOSliceRangeForTriple(**UB, TT);
231}
232
234 object::Archive &A, MemoryBufferRef MemberBuf, size_t Index) {
235
236 auto LoadMember = [&]() {
238 Index);
239 };
240
241 if (!ObjCOnly) {
242 // If we're loading all files then just load the buffer immediately. Return
243 // false to indicate that there's no further loading to do here.
244 if (auto Err = L.add(JD, LoadMember()))
245 return Err;
246 return false;
247 }
248
249 // We need to check whether this archive member contains any Objective-C
250 // or Swift metadata.
251 auto Obj = object::ObjectFile::createObjectFile(MemberBuf);
252 if (!Obj) {
253 // Invalid files are not loadable, but don't invalidate the archive.
254 consumeError(Obj.takeError());
255 return false;
256 }
257
258 if (auto *MachOObj = dyn_cast<object::MachOObjectFile>(&**Obj)) {
259 // Load the object if any recognized special section is present.
260 for (auto Sec : MachOObj->sections()) {
261 auto SegName =
262 MachOObj->getSectionFinalSegmentName(Sec.getRawDataRefImpl());
263 if (auto SecName = Sec.getName()) {
264 if (*SecName == "__objc_classlist" || *SecName == "__objc_protolist" ||
265 *SecName == "__objc_clsrolist" || *SecName == "__objc_catlist" ||
266 *SecName == "__objc_catlist2" || *SecName == "__objc_nlcatlist" ||
267 (SegName == "__TEXT" && (*SecName).starts_with("__swift") &&
268 *SecName != "__swift_modhash")) {
269 if (auto Err = L.add(JD, LoadMember()))
270 return Err;
271 return false;
272 }
273 } else
274 return SecName.takeError();
275 }
276 }
277
278 // This is an object file but we didn't load it, so return true to indicate
279 // that it's still loadable.
280 return true;
281}
282
283} // End namespace orc.
284} // End namespace llvm.
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
uint32_t Index
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
StringRef getBufferIdentifier() const
StringRef getBuffer() const
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.
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
static LLVM_ABI StringRef getArchTypeName(ArchType Kind)
Get the canonical name for the Kind architecture.
Definition: Triple.cpp:24
@ UnknownObjectFormat
Definition: Triple.h:315
@ UnknownVendor
Definition: Triple.h:186
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)
Definition: ObjectFile.cpp:211
LLVM_ABI Expected< bool > operator()(object::Archive &A, MemoryBufferRef MemberBuf, size_t Index)
Definition: MachO.cpp:233
virtual Error add(ResourceTrackerSP RT, std::unique_ptr< MemoryBuffer > O, MaterializationUnit::Interface I)
Adds a MaterializationUnit for the object file in the given memory buffer to the JITDylib for the giv...
Definition: Layer.cpp:171
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.
@ MH_OBJECT
Definition: MachO.h:43
@ 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
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:143
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:59
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:203
static std::string objDesc(const MemoryBufferRef &Obj, const Triple &TT, bool ObjIsSlice)
Definition: MachO.cpp:23
Expected< std::pair< std::unique_ptr< MemoryBuffer >, LinkableFileKind > > loadMachORelocatableObject(StringRef Path, const Triple &TT, LoadArchives LA, std::optional< StringRef > IdentifierOverride)
Definition: MachO.cpp:99
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: AddressRanges.h:18
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
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
void consumeError(Error Err)
Consume a Error without doing anything.
Definition: Error.h:1083
Description of the encoding of one expression Op.
@ archive
ar style archive file
Definition: Magic.h:26
@ macho_universal_binary
Mach-O universal binary.
Definition: Magic.h:44
@ macho_object
Mach-O Object file.
Definition: Magic.h:33