LLVM 20.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"
16
17#define DEBUG_TYPE "orc"
18
19namespace llvm {
20namespace orc {
21
22static std::string objDesc(const MemoryBufferRef &Obj, const Triple &TT,
23 bool ObjIsSlice) {
24 std::string Desc;
25 if (ObjIsSlice)
26 Desc += (TT.getArchName() + " slice of universal binary").str();
28 return Desc;
29}
30
31template <typename HeaderType>
33 bool SwapEndianness, const Triple &TT,
34 bool ObjIsSlice) {
35 StringRef Data = Obj.getBuffer();
36
37 HeaderType Hdr;
38 memcpy(&Hdr, Data.data(), sizeof(HeaderType));
39
40 if (SwapEndianness)
41 swapStruct(Hdr);
42
43 if (Hdr.filetype != MachO::MH_OBJECT)
44 return make_error<StringError>(objDesc(Obj, TT, ObjIsSlice) +
45 " is not a MachO relocatable object",
47
48 auto ObjArch = object::MachOObjectFile::getArch(Hdr.cputype, Hdr.cpusubtype);
49 if (ObjArch != TT.getArch())
50 return make_error<StringError>(
51 objDesc(Obj, TT, ObjIsSlice) + Triple::getArchTypeName(ObjArch) +
52 ", cannot be loaded into " + TT.str() + " process",
54
55 return Error::success();
56}
57
59 bool ObjIsSlice) {
60 StringRef Data = Obj.getBuffer();
61
62 if (Data.size() < 4)
63 return make_error<StringError>(
64 objDesc(Obj, TT, ObjIsSlice) +
65 " is not a valid MachO relocatable object file (truncated header)",
67
68 uint32_t Magic;
69 memcpy(&Magic, Data.data(), sizeof(uint32_t));
70
71 switch (Magic) {
72 case MachO::MH_MAGIC:
73 case MachO::MH_CIGAM:
74 return checkMachORelocatableObject<MachO::mach_header>(
75 std::move(Obj), Magic == MachO::MH_CIGAM, TT, ObjIsSlice);
78 return checkMachORelocatableObject<MachO::mach_header_64>(
79 std::move(Obj), Magic == MachO::MH_CIGAM_64, TT, ObjIsSlice);
80 default:
81 return make_error<StringError>(
82 objDesc(Obj, TT, ObjIsSlice) +
83 " is not a valid MachO relocatable object (bad magic value)",
85 }
86}
87
89checkMachORelocatableObject(std::unique_ptr<MemoryBuffer> Obj, const Triple &TT,
90 bool ObjIsSlice) {
91 if (auto Err =
92 checkMachORelocatableObject(Obj->getMemBufferRef(), TT, ObjIsSlice))
93 return std::move(Err);
94 return std::move(Obj);
95}
96
99 std::optional<StringRef> IdentifierOverride) {
100 assert((TT.getObjectFormat() == Triple::UnknownObjectFormat ||
101 TT.getObjectFormat() == Triple::MachO) &&
102 "TT must specify MachO or Unknown object format");
103
104 if (!IdentifierOverride)
105 IdentifierOverride = Path;
106
109 if (!FDOrErr)
110 return createFileError(Path, FDOrErr.takeError());
111 sys::fs::file_t FD = *FDOrErr;
112 auto CloseFile = make_scope_exit([&]() { sys::fs::closeFile(FD); });
113
114 auto Buf =
115 MemoryBuffer::getOpenFile(FD, *IdentifierOverride, /*FileSize=*/-1);
116 if (!Buf)
117 return make_error<StringError>(
118 StringRef("Could not load MachO object at path ") + Path,
119 Buf.getError());
120
121 switch (identify_magic((*Buf)->getBuffer())) {
123 auto CheckedObj = checkMachORelocatableObject(std::move(*Buf), TT, false);
124 if (!CheckedObj)
125 return CheckedObj.takeError();
126 return std::make_pair(std::move(*CheckedObj),
128 }
130 return loadLinkableSliceFromMachOUniversalBinary(FD, std::move(*Buf), TT,
132 *IdentifierOverride);
133 default:
134 return make_error<StringError>(
135 Path + " does not contain a relocatable object file compatible with " +
136 TT.str(),
138 }
139}
140
143 std::unique_ptr<MemoryBuffer> UBBuf,
144 const Triple &TT, LoadArchives LA,
145 StringRef UBPath,
146 StringRef Identifier) {
147
148 auto UniversalBin =
149 object::MachOUniversalBinary::create(UBBuf->getMemBufferRef());
150 if (!UniversalBin)
151 return UniversalBin.takeError();
152
153 auto SliceRange = getMachOSliceRangeForTriple(**UniversalBin, TT);
154 if (!SliceRange)
155 return SliceRange.takeError();
156
157 auto Buf = MemoryBuffer::getOpenFileSlice(FD, Identifier, SliceRange->second,
158 SliceRange->first);
159 if (!Buf)
160 return make_error<StringError>(
161 "Could not load " + TT.getArchName() +
162 " slice of MachO universal binary at path " + UBPath,
163 Buf.getError());
164
165 switch (identify_magic((*Buf)->getBuffer())) {
167 if (LA != LoadArchives::Never)
168 return std::make_pair(std::move(*Buf), LinkableFileKind::Archive);
169 break;
171 if (LA != LoadArchives::Required) {
172 auto CheckedObj = checkMachORelocatableObject(std::move(*Buf), TT, true);
173 if (!CheckedObj)
174 return CheckedObj.takeError();
175 return std::make_pair(std::move(*CheckedObj),
177 }
178 break;
179 }
180 default:
181 break;
182 }
183
184 auto FT = [&] {
185 switch (LA) {
187 return "a mach-o relocatable object file";
189 return "a mach-o relocatable object file or archive";
191 return "an archive";
192 }
193 llvm_unreachable("Unknown LoadArchives enum");
194 };
195
196 return make_error<StringError>(TT.getArchName() + " slice of " + UBPath +
197 " does not contain " + FT(),
199}
200
203 const Triple &TT) {
204
205 for (const auto &Obj : UB.objects()) {
206 auto ObjTT = Obj.getTriple();
207 if (ObjTT.getArch() == TT.getArch() &&
208 ObjTT.getSubArch() == TT.getSubArch() &&
209 (TT.getVendor() == Triple::UnknownVendor ||
210 ObjTT.getVendor() == TT.getVendor())) {
211 // We found a match. Return the range for the slice.
212 return std::make_pair(Obj.getOffset(), Obj.getSize());
213 }
214 }
215
216 return make_error<StringError>(Twine("Universal binary ") + UB.getFileName() +
217 " does not contain a slice for " +
218 TT.str(),
220}
221
224
226 if (!UB)
227 return UB.takeError();
228
229 return getMachOSliceRangeForTriple(**UB, TT);
230}
231
233 if (!ObjCOnly)
234 return L.add(JD, MemoryBuffer::getMemBuffer(MemberBuf));
235
236 // We need to check whether this archive member contains any Objective-C
237 // or Swift metadata.
238
239 auto Obj = object::ObjectFile::createObjectFile(MemberBuf);
240 if (!Obj) {
241 // We silently ignore invalid files.
242 consumeError(Obj.takeError());
243 return Error::success();
244 }
245
246 if (auto *MachOObj = dyn_cast<object::MachOObjectFile>(&**Obj)) {
247 // Load the object if any recognized special section is present.
248 for (auto Sec : MachOObj->sections()) {
249 auto SegName =
250 MachOObj->getSectionFinalSegmentName(Sec.getRawDataRefImpl());
251 if (auto SecName = Sec.getName()) {
252 if (*SecName == "__objc_classlist" || *SecName == "__objc_protolist" ||
253 *SecName == "__objc_clsrolist" || *SecName == "__objc_catlist" ||
254 *SecName == "__objc_catlist2" || *SecName == "__objc_nlcatlist" ||
255 (SegName == "__TEXT" && (*SecName).starts_with("__swift") &&
256 *SecName != "__swift_modhash"))
257 return L.add(JD, MemoryBuffer::getMemBuffer(MemberBuf));
258 } else
259 return SecName.takeError();
260 }
261 }
262
263 return Error::success();
264}
265
266} // End namespace orc.
267} // End namespace llvm.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:337
Tagged union holding either a T or a Error.
Definition: Error.h:481
Error takeError()
Take ownership of the stored error.
Definition: Error.h:608
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 std::unique_ptr< MemoryBuffer > getMemBuffer(StringRef InputData, StringRef BufferName="", bool RequiresNullTerminator=true)
Open the specified memory range as 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:51
Triple - Helper class for working with autoconf configuration names.
Definition: Triple.h:44
static StringRef getArchTypeName(ArchType Kind)
Get the canonical name for the Kind architecture.
Definition: Triple.cpp:24
@ UnknownObjectFormat
Definition: Triple.h:308
@ UnknownVendor
Definition: Triple.h:181
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
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:209
Error operator()(MemoryBufferRef MemberBuf)
Definition: MachO.cpp:232
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:170
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ 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
@ MH_OBJECT
Definition: MachO.h:43
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:142
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:58
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:202
static std::string objDesc(const MemoryBufferRef &Obj, const Triple &TT, bool ObjIsSlice)
Definition: MachO.cpp:22
Expected< std::pair< std::unique_ptr< MemoryBuffer >, LinkableFileKind > > loadMachORelocatableObject(StringRef Path, const Triple &TT, LoadArchives LA, std::optional< StringRef > IdentifierOverride)
Definition: MachO.cpp:98
std::error_code closeFile(file_t &F)
Close the file object.
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
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:1385
detail::scope_exit< std::decay_t< Callable > > make_scope_exit(Callable &&F)
Definition: ScopeExit.h:59
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:1069
Description of the encoding of one expression Op.
@ archive
ar style archive file
Definition: Magic.h:25
@ macho_universal_binary
Mach-O universal binary.
Definition: Magic.h:43
@ macho_object
Mach-O Object file.
Definition: Magic.h:32