Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/MachO.cpp
213799 views
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
9
#include "llvm/ExecutionEngine/Orc/MachO.h"
10
11
#include "llvm/ADT/ScopeExit.h"
12
#include "llvm/BinaryFormat/MachO.h"
13
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
14
#include "llvm/ExecutionEngine/Orc/Layer.h"
15
#include "llvm/Object/MachOUniversal.h"
16
#include "llvm/Support/FileSystem.h"
17
18
#define DEBUG_TYPE "orc"
19
20
namespace llvm {
21
namespace orc {
22
23
static 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();
28
Desc += Obj.getBufferIdentifier();
29
return Desc;
30
}
31
32
template <typename HeaderType>
33
static Error checkMachORelocatableObject(MemoryBufferRef Obj,
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",
47
inconvertibleErrorCode());
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",
54
inconvertibleErrorCode());
55
56
return Error::success();
57
}
58
59
Error checkMachORelocatableObject(MemoryBufferRef Obj, const Triple &TT,
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)",
67
inconvertibleErrorCode());
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);
77
case MachO::MH_MAGIC_64:
78
case MachO::MH_CIGAM_64:
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)",
85
inconvertibleErrorCode());
86
}
87
}
88
89
Expected<std::unique_ptr<MemoryBuffer>>
90
checkMachORelocatableObject(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
98
Expected<std::pair<std::unique_ptr<MemoryBuffer>, LinkableFileKind>>
99
loadMachORelocatableObject(StringRef Path, const Triple &TT, LoadArchives LA,
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
108
Expected<sys::fs::file_t> FDOrErr =
109
sys::fs::openNativeFileForRead(Path, sys::fs::OF_None);
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())) {
123
case file_magic::macho_object: {
124
auto CheckedObj = checkMachORelocatableObject(std::move(*Buf), TT, false);
125
if (!CheckedObj)
126
return CheckedObj.takeError();
127
return std::make_pair(std::move(*CheckedObj),
128
LinkableFileKind::RelocatableObject);
129
}
130
case file_magic::macho_universal_binary:
131
return loadLinkableSliceFromMachOUniversalBinary(FD, std::move(*Buf), TT,
132
LoadArchives::Never, Path,
133
*IdentifierOverride);
134
default:
135
return make_error<StringError>(
136
Path + " does not contain a relocatable object file compatible with " +
137
TT.str(),
138
inconvertibleErrorCode());
139
}
140
}
141
142
Expected<std::pair<std::unique_ptr<MemoryBuffer>, LinkableFileKind>>
143
loadLinkableSliceFromMachOUniversalBinary(sys::fs::file_t FD,
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())) {
167
case file_magic::archive:
168
if (LA != LoadArchives::Never)
169
return std::make_pair(std::move(*Buf), LinkableFileKind::Archive);
170
break;
171
case file_magic::macho_object: {
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),
177
LinkableFileKind::RelocatableObject);
178
}
179
break;
180
}
181
default:
182
break;
183
}
184
185
auto FT = [&] {
186
switch (LA) {
187
case LoadArchives::Never:
188
return "a mach-o relocatable object file";
189
case LoadArchives::Allowed:
190
return "a mach-o relocatable object file or archive";
191
case LoadArchives::Required:
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(),
199
inconvertibleErrorCode());
200
}
201
202
Expected<std::pair<size_t, size_t>>
203
getMachOSliceRangeForTriple(object::MachOUniversalBinary &UB,
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(),
220
inconvertibleErrorCode());
221
}
222
223
Expected<std::pair<size_t, size_t>>
224
getMachOSliceRangeForTriple(MemoryBufferRef UBBuf, const Triple &TT) {
225
226
auto UB = object::MachOUniversalBinary::create(UBBuf);
227
if (!UB)
228
return UB.takeError();
229
230
return getMachOSliceRangeForTriple(**UB, TT);
231
}
232
233
Expected<bool> ForceLoadMachOArchiveMembers::operator()(
234
object::Archive &A, MemoryBufferRef MemberBuf, size_t Index) {
235
236
auto LoadMember = [&]() {
237
return StaticLibraryDefinitionGenerator::createMemberBuffer(A, MemberBuf,
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.
285
286