1 //===- lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp ---------===//
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 ///
10 /// \file For mach-o object files, this implementation converts from
11 /// mach-o on-disk binary format to in-memory normalized mach-o.
12 ///
13 /// +---------------+
14 /// | binary mach-o |
15 /// +---------------+
16 /// |
17 /// |
18 /// v
19 /// +------------+
20 /// | normalized |
21 /// +------------+
22
23 #include "ArchHandler.h"
24 #include "MachONormalizedFile.h"
25 #include "MachONormalizedFileBinaryUtils.h"
26 #include "lld/Common/LLVM.h"
27 #include "lld/Core/Error.h"
28 #include "lld/Core/SharedLibraryFile.h"
29 #include "llvm/ADT/STLExtras.h"
30 #include "llvm/ADT/SmallString.h"
31 #include "llvm/ADT/StringRef.h"
32 #include "llvm/ADT/StringSwitch.h"
33 #include "llvm/ADT/Twine.h"
34 #include "llvm/BinaryFormat/MachO.h"
35 #include "llvm/BinaryFormat/Magic.h"
36 #include "llvm/Object/MachO.h"
37 #include "llvm/Support/Casting.h"
38 #include "llvm/Support/Errc.h"
39 #include "llvm/Support/ErrorHandling.h"
40 #include "llvm/Support/FileOutputBuffer.h"
41 #include "llvm/Support/Host.h"
42 #include "llvm/Support/MemoryBuffer.h"
43 #include "llvm/Support/raw_ostream.h"
44 #include <functional>
45 #include <system_error>
46
47 using namespace llvm::MachO;
48 using llvm::object::ExportEntry;
49 using llvm::file_magic;
50 using llvm::object::MachOObjectFile;
51
52 namespace lld {
53 namespace mach_o {
54 namespace normalized {
55
56 // Utility to call a lambda expression on each load command.
forEachLoadCommand(StringRef lcRange,unsigned lcCount,bool isBig,bool is64,std::function<bool (uint32_t cmd,uint32_t size,const char * lc)> func)57 static llvm::Error forEachLoadCommand(
58 StringRef lcRange, unsigned lcCount, bool isBig, bool is64,
59 std::function<bool(uint32_t cmd, uint32_t size, const char *lc)> func) {
60 const char* p = lcRange.begin();
61 for (unsigned i=0; i < lcCount; ++i) {
62 const load_command *lc = reinterpret_cast<const load_command*>(p);
63 load_command lcCopy;
64 const load_command *slc = lc;
65 if (isBig != llvm::sys::IsBigEndianHost) {
66 memcpy(&lcCopy, lc, sizeof(load_command));
67 swapStruct(lcCopy);
68 slc = &lcCopy;
69 }
70 if ( (p + slc->cmdsize) > lcRange.end() )
71 return llvm::make_error<GenericError>("Load command exceeds range");
72
73 if (func(slc->cmd, slc->cmdsize, p))
74 return llvm::Error::success();
75
76 p += slc->cmdsize;
77 }
78
79 return llvm::Error::success();
80 }
81
appendRelocations(Relocations & relocs,StringRef buffer,bool bigEndian,uint32_t reloff,uint32_t nreloc)82 static std::error_code appendRelocations(Relocations &relocs, StringRef buffer,
83 bool bigEndian,
84 uint32_t reloff, uint32_t nreloc) {
85 if ((reloff + nreloc*8) > buffer.size())
86 return make_error_code(llvm::errc::executable_format_error);
87 const any_relocation_info* relocsArray =
88 reinterpret_cast<const any_relocation_info*>(buffer.begin()+reloff);
89
90 for(uint32_t i=0; i < nreloc; ++i) {
91 relocs.push_back(unpackRelocation(relocsArray[i], bigEndian));
92 }
93 return std::error_code();
94 }
95
96 static std::error_code
appendIndirectSymbols(IndirectSymbols & isyms,StringRef buffer,bool isBig,uint32_t istOffset,uint32_t istCount,uint32_t startIndex,uint32_t count)97 appendIndirectSymbols(IndirectSymbols &isyms, StringRef buffer, bool isBig,
98 uint32_t istOffset, uint32_t istCount,
99 uint32_t startIndex, uint32_t count) {
100 if ((istOffset + istCount*4) > buffer.size())
101 return make_error_code(llvm::errc::executable_format_error);
102 if (startIndex+count > istCount)
103 return make_error_code(llvm::errc::executable_format_error);
104 const uint8_t *indirectSymbolArray = (const uint8_t *)buffer.data();
105
106 for(uint32_t i=0; i < count; ++i) {
107 isyms.push_back(read32(
108 indirectSymbolArray + (startIndex + i) * sizeof(uint32_t), isBig));
109 }
110 return std::error_code();
111 }
112
113
readBigEndian(T t)114 template <typename T> static T readBigEndian(T t) {
115 if (llvm::sys::IsLittleEndianHost)
116 llvm::sys::swapByteOrder(t);
117 return t;
118 }
119
120
isMachOHeader(const mach_header * mh,bool & is64,bool & isBig)121 static bool isMachOHeader(const mach_header *mh, bool &is64, bool &isBig) {
122 switch (read32(&mh->magic, false)) {
123 case llvm::MachO::MH_MAGIC:
124 is64 = false;
125 isBig = false;
126 return true;
127 case llvm::MachO::MH_MAGIC_64:
128 is64 = true;
129 isBig = false;
130 return true;
131 case llvm::MachO::MH_CIGAM:
132 is64 = false;
133 isBig = true;
134 return true;
135 case llvm::MachO::MH_CIGAM_64:
136 is64 = true;
137 isBig = true;
138 return true;
139 default:
140 return false;
141 }
142 }
143
144
isThinObjectFile(StringRef path,MachOLinkingContext::Arch & arch)145 bool isThinObjectFile(StringRef path, MachOLinkingContext::Arch &arch) {
146 // Try opening and mapping file at path.
147 ErrorOr<std::unique_ptr<MemoryBuffer>> b = MemoryBuffer::getFileOrSTDIN(path);
148 if (b.getError())
149 return false;
150
151 // If file length < 32 it is too small to be mach-o object file.
152 StringRef fileBuffer = b->get()->getBuffer();
153 if (fileBuffer.size() < 32)
154 return false;
155
156 // If file buffer does not start with MH_MAGIC (and variants), not obj file.
157 const mach_header *mh = reinterpret_cast<const mach_header *>(
158 fileBuffer.begin());
159 bool is64, isBig;
160 if (!isMachOHeader(mh, is64, isBig))
161 return false;
162
163 // If not MH_OBJECT, not object file.
164 if (read32(&mh->filetype, isBig) != MH_OBJECT)
165 return false;
166
167 // Lookup up arch from cpu/subtype pair.
168 arch = MachOLinkingContext::archFromCpuType(
169 read32(&mh->cputype, isBig),
170 read32(&mh->cpusubtype, isBig));
171 return true;
172 }
173
sliceFromFatFile(MemoryBufferRef mb,MachOLinkingContext::Arch arch,uint32_t & offset,uint32_t & size)174 bool sliceFromFatFile(MemoryBufferRef mb, MachOLinkingContext::Arch arch,
175 uint32_t &offset, uint32_t &size) {
176 const char *start = mb.getBufferStart();
177 const llvm::MachO::fat_header *fh =
178 reinterpret_cast<const llvm::MachO::fat_header *>(start);
179 if (readBigEndian(fh->magic) != llvm::MachO::FAT_MAGIC)
180 return false;
181 uint32_t nfat_arch = readBigEndian(fh->nfat_arch);
182 const fat_arch *fstart =
183 reinterpret_cast<const fat_arch *>(start + sizeof(fat_header));
184 const fat_arch *fend =
185 reinterpret_cast<const fat_arch *>(start + sizeof(fat_header) +
186 sizeof(fat_arch) * nfat_arch);
187 const uint32_t reqCpuType = MachOLinkingContext::cpuTypeFromArch(arch);
188 const uint32_t reqCpuSubtype = MachOLinkingContext::cpuSubtypeFromArch(arch);
189 for (const fat_arch *fa = fstart; fa < fend; ++fa) {
190 if ((readBigEndian(fa->cputype) == reqCpuType) &&
191 (readBigEndian(fa->cpusubtype) == reqCpuSubtype)) {
192 offset = readBigEndian(fa->offset);
193 size = readBigEndian(fa->size);
194 if ((offset + size) > mb.getBufferSize())
195 return false;
196 return true;
197 }
198 }
199 return false;
200 }
201
202 /// Reads a mach-o file and produces an in-memory normalized view.
203 llvm::Expected<std::unique_ptr<NormalizedFile>>
readBinary(std::unique_ptr<MemoryBuffer> & mb,const MachOLinkingContext::Arch arch)204 readBinary(std::unique_ptr<MemoryBuffer> &mb,
205 const MachOLinkingContext::Arch arch) {
206 // Make empty NormalizedFile.
207 std::unique_ptr<NormalizedFile> f(new NormalizedFile());
208
209 const char *start = mb->getBufferStart();
210 size_t objSize = mb->getBufferSize();
211 const mach_header *mh = reinterpret_cast<const mach_header *>(start);
212
213 uint32_t sliceOffset;
214 uint32_t sliceSize;
215 if (sliceFromFatFile(mb->getMemBufferRef(), arch, sliceOffset, sliceSize)) {
216 start = &start[sliceOffset];
217 objSize = sliceSize;
218 mh = reinterpret_cast<const mach_header *>(start);
219 }
220
221 // Determine endianness and pointer size for mach-o file.
222 bool is64, isBig;
223 if (!isMachOHeader(mh, is64, isBig))
224 return llvm::make_error<GenericError>("File is not a mach-o");
225
226 // Endian swap header, if needed.
227 mach_header headerCopy;
228 const mach_header *smh = mh;
229 if (isBig != llvm::sys::IsBigEndianHost) {
230 memcpy(&headerCopy, mh, sizeof(mach_header));
231 swapStruct(headerCopy);
232 smh = &headerCopy;
233 }
234
235 // Validate head and load commands fit in buffer.
236 const uint32_t lcCount = smh->ncmds;
237 const char *lcStart =
238 start + (is64 ? sizeof(mach_header_64) : sizeof(mach_header));
239 StringRef lcRange(lcStart, smh->sizeofcmds);
240 if (lcRange.end() > (start + objSize))
241 return llvm::make_error<GenericError>("Load commands exceed file size");
242
243 // Get architecture from mach_header.
244 f->arch = MachOLinkingContext::archFromCpuType(smh->cputype, smh->cpusubtype);
245 if (f->arch != arch) {
246 return llvm::make_error<GenericError>(
247 Twine("file is wrong architecture. Expected "
248 "(" + MachOLinkingContext::nameFromArch(arch)
249 + ") found ("
250 + MachOLinkingContext::nameFromArch(f->arch)
251 + ")" ));
252 }
253 // Copy file type and flags
254 f->fileType = HeaderFileType(smh->filetype);
255 f->flags = smh->flags;
256
257
258 // Pre-scan load commands looking for indirect symbol table.
259 uint32_t indirectSymbolTableOffset = 0;
260 uint32_t indirectSymbolTableCount = 0;
261 auto ec = forEachLoadCommand(lcRange, lcCount, isBig, is64,
262 [&](uint32_t cmd, uint32_t size,
263 const char *lc) -> bool {
264 if (cmd == LC_DYSYMTAB) {
265 const dysymtab_command *d = reinterpret_cast<const dysymtab_command*>(lc);
266 indirectSymbolTableOffset = read32(&d->indirectsymoff, isBig);
267 indirectSymbolTableCount = read32(&d->nindirectsyms, isBig);
268 return true;
269 }
270 return false;
271 });
272 if (ec)
273 return std::move(ec);
274
275 // Walk load commands looking for segments/sections and the symbol table.
276 const data_in_code_entry *dataInCode = nullptr;
277 const dyld_info_command *dyldInfo = nullptr;
278 uint32_t dataInCodeSize = 0;
279 ec = forEachLoadCommand(lcRange, lcCount, isBig, is64,
280 [&] (uint32_t cmd, uint32_t size, const char* lc) -> bool {
281 switch(cmd) {
282 case LC_SEGMENT_64:
283 if (is64) {
284 const segment_command_64 *seg =
285 reinterpret_cast<const segment_command_64*>(lc);
286 const unsigned sectionCount = read32(&seg->nsects, isBig);
287 const section_64 *sects = reinterpret_cast<const section_64*>
288 (lc + sizeof(segment_command_64));
289 const unsigned lcSize = sizeof(segment_command_64)
290 + sectionCount*sizeof(section_64);
291 // Verify sections don't extend beyond end of segment load command.
292 if (lcSize > size)
293 return true;
294 for (unsigned i=0; i < sectionCount; ++i) {
295 const section_64 *sect = §s[i];
296 Section section;
297 section.segmentName = getString16(sect->segname);
298 section.sectionName = getString16(sect->sectname);
299 section.type = (SectionType)(read32(§->flags, isBig) &
300 SECTION_TYPE);
301 section.attributes = read32(§->flags, isBig) & SECTION_ATTRIBUTES;
302 section.alignment = 1 << read32(§->align, isBig);
303 section.address = read64(§->addr, isBig);
304 const uint8_t *content =
305 (const uint8_t *)start + read32(§->offset, isBig);
306 size_t contentSize = read64(§->size, isBig);
307 // Note: this assign() is copying the content bytes. Ideally,
308 // we can use a custom allocator for vector to avoid the copy.
309 section.content = llvm::makeArrayRef(content, contentSize);
310 appendRelocations(section.relocations, mb->getBuffer(), isBig,
311 read32(§->reloff, isBig),
312 read32(§->nreloc, isBig));
313 if (section.type == S_NON_LAZY_SYMBOL_POINTERS) {
314 appendIndirectSymbols(section.indirectSymbols, mb->getBuffer(),
315 isBig,
316 indirectSymbolTableOffset,
317 indirectSymbolTableCount,
318 read32(§->reserved1, isBig),
319 contentSize/4);
320 }
321 f->sections.push_back(section);
322 }
323 }
324 break;
325 case LC_SEGMENT:
326 if (!is64) {
327 const segment_command *seg =
328 reinterpret_cast<const segment_command*>(lc);
329 const unsigned sectionCount = read32(&seg->nsects, isBig);
330 const section *sects = reinterpret_cast<const section*>
331 (lc + sizeof(segment_command));
332 const unsigned lcSize = sizeof(segment_command)
333 + sectionCount*sizeof(section);
334 // Verify sections don't extend beyond end of segment load command.
335 if (lcSize > size)
336 return true;
337 for (unsigned i=0; i < sectionCount; ++i) {
338 const section *sect = §s[i];
339 Section section;
340 section.segmentName = getString16(sect->segname);
341 section.sectionName = getString16(sect->sectname);
342 section.type = (SectionType)(read32(§->flags, isBig) &
343 SECTION_TYPE);
344 section.attributes =
345 read32((const uint8_t *)§->flags, isBig) & SECTION_ATTRIBUTES;
346 section.alignment = 1 << read32(§->align, isBig);
347 section.address = read32(§->addr, isBig);
348 const uint8_t *content =
349 (const uint8_t *)start + read32(§->offset, isBig);
350 size_t contentSize = read32(§->size, isBig);
351 // Note: this assign() is copying the content bytes. Ideally,
352 // we can use a custom allocator for vector to avoid the copy.
353 section.content = llvm::makeArrayRef(content, contentSize);
354 appendRelocations(section.relocations, mb->getBuffer(), isBig,
355 read32(§->reloff, isBig),
356 read32(§->nreloc, isBig));
357 if (section.type == S_NON_LAZY_SYMBOL_POINTERS) {
358 appendIndirectSymbols(
359 section.indirectSymbols, mb->getBuffer(), isBig,
360 indirectSymbolTableOffset, indirectSymbolTableCount,
361 read32(§->reserved1, isBig), contentSize / 4);
362 }
363 f->sections.push_back(section);
364 }
365 }
366 break;
367 case LC_SYMTAB: {
368 const symtab_command *st = reinterpret_cast<const symtab_command*>(lc);
369 const char *strings = start + read32(&st->stroff, isBig);
370 const uint32_t strSize = read32(&st->strsize, isBig);
371 // Validate string pool and symbol table all in buffer.
372 if (read32((const uint8_t *)&st->stroff, isBig) +
373 read32((const uint8_t *)&st->strsize, isBig) >
374 objSize)
375 return true;
376 if (is64) {
377 const uint32_t symOffset = read32(&st->symoff, isBig);
378 const uint32_t symCount = read32(&st->nsyms, isBig);
379 if ( symOffset+(symCount*sizeof(nlist_64)) > objSize)
380 return true;
381 const nlist_64 *symbols =
382 reinterpret_cast<const nlist_64 *>(start + symOffset);
383 // Convert each nlist_64 to a lld::mach_o::normalized::Symbol.
384 for(uint32_t i=0; i < symCount; ++i) {
385 nlist_64 tempSym;
386 memcpy(&tempSym, &symbols[i], sizeof(nlist_64));
387 const nlist_64 *sin = &tempSym;
388 if (isBig != llvm::sys::IsBigEndianHost)
389 swapStruct(tempSym);
390 Symbol sout;
391 if (sin->n_strx > strSize)
392 return true;
393 sout.name = &strings[sin->n_strx];
394 sout.type = static_cast<NListType>(sin->n_type & (N_STAB|N_TYPE));
395 sout.scope = (sin->n_type & (N_PEXT|N_EXT));
396 sout.sect = sin->n_sect;
397 sout.desc = sin->n_desc;
398 sout.value = sin->n_value;
399 if (sin->n_type & N_STAB)
400 f->stabsSymbols.push_back(sout);
401 else if (sout.type == N_UNDF)
402 f->undefinedSymbols.push_back(sout);
403 else if (sin->n_type & N_EXT)
404 f->globalSymbols.push_back(sout);
405 else
406 f->localSymbols.push_back(sout);
407 }
408 } else {
409 const uint32_t symOffset = read32(&st->symoff, isBig);
410 const uint32_t symCount = read32(&st->nsyms, isBig);
411 if ( symOffset+(symCount*sizeof(nlist)) > objSize)
412 return true;
413 const nlist *symbols =
414 reinterpret_cast<const nlist *>(start + symOffset);
415 // Convert each nlist to a lld::mach_o::normalized::Symbol.
416 for(uint32_t i=0; i < symCount; ++i) {
417 const nlist *sin = &symbols[i];
418 nlist tempSym;
419 if (isBig != llvm::sys::IsBigEndianHost) {
420 tempSym = *sin; swapStruct(tempSym); sin = &tempSym;
421 }
422 Symbol sout;
423 if (sin->n_strx > strSize)
424 return true;
425 sout.name = &strings[sin->n_strx];
426 sout.type = (NListType)(sin->n_type & N_TYPE);
427 sout.scope = (sin->n_type & (N_PEXT|N_EXT));
428 sout.sect = sin->n_sect;
429 sout.desc = sin->n_desc;
430 sout.value = sin->n_value;
431 if (sout.type == N_UNDF)
432 f->undefinedSymbols.push_back(sout);
433 else if (sout.scope == (SymbolScope)N_EXT)
434 f->globalSymbols.push_back(sout);
435 else if (sin->n_type & N_STAB)
436 f->stabsSymbols.push_back(sout);
437 else
438 f->localSymbols.push_back(sout);
439 }
440 }
441 }
442 break;
443 case LC_ID_DYLIB: {
444 const dylib_command *dl = reinterpret_cast<const dylib_command*>(lc);
445 f->installName = lc + read32(&dl->dylib.name, isBig);
446 f->currentVersion = read32(&dl->dylib.current_version, isBig);
447 f->compatVersion = read32(&dl->dylib.compatibility_version, isBig);
448 }
449 break;
450 case LC_DATA_IN_CODE: {
451 const linkedit_data_command *ldc =
452 reinterpret_cast<const linkedit_data_command*>(lc);
453 dataInCode = reinterpret_cast<const data_in_code_entry *>(
454 start + read32(&ldc->dataoff, isBig));
455 dataInCodeSize = read32(&ldc->datasize, isBig);
456 }
457 break;
458 case LC_LOAD_DYLIB:
459 case LC_LOAD_WEAK_DYLIB:
460 case LC_REEXPORT_DYLIB:
461 case LC_LOAD_UPWARD_DYLIB: {
462 const dylib_command *dl = reinterpret_cast<const dylib_command*>(lc);
463 DependentDylib entry;
464 entry.path = lc + read32(&dl->dylib.name, isBig);
465 entry.kind = LoadCommandType(cmd);
466 entry.compatVersion = read32(&dl->dylib.compatibility_version, isBig);
467 entry.currentVersion = read32(&dl->dylib.current_version, isBig);
468 f->dependentDylibs.push_back(entry);
469 }
470 break;
471 case LC_RPATH: {
472 const rpath_command *rpc = reinterpret_cast<const rpath_command *>(lc);
473 f->rpaths.push_back(lc + read32(&rpc->path, isBig));
474 }
475 break;
476 case LC_DYLD_INFO:
477 case LC_DYLD_INFO_ONLY:
478 dyldInfo = reinterpret_cast<const dyld_info_command*>(lc);
479 break;
480 case LC_VERSION_MIN_MACOSX:
481 case LC_VERSION_MIN_IPHONEOS:
482 case LC_VERSION_MIN_WATCHOS:
483 case LC_VERSION_MIN_TVOS:
484 // If we are emitting an object file, then we may take the load command
485 // kind from these commands and pass it on to the output
486 // file.
487 f->minOSVersionKind = (LoadCommandType)cmd;
488 break;
489 }
490 return false;
491 });
492 if (ec)
493 return std::move(ec);
494
495 if (dataInCode) {
496 // Convert on-disk data_in_code_entry array to DataInCode vector.
497 for (unsigned i=0; i < dataInCodeSize/sizeof(data_in_code_entry); ++i) {
498 DataInCode entry;
499 entry.offset = read32(&dataInCode[i].offset, isBig);
500 entry.length = read16(&dataInCode[i].length, isBig);
501 entry.kind =
502 (DataRegionType)read16((const uint8_t *)&dataInCode[i].kind, isBig);
503 f->dataInCode.push_back(entry);
504 }
505 }
506
507 if (dyldInfo) {
508 // If any exports, extract and add to normalized exportInfo vector.
509 if (dyldInfo->export_size) {
510 const uint8_t *trieStart = reinterpret_cast<const uint8_t *>(
511 start + read32(&dyldInfo->export_off, isBig));
512 ArrayRef<uint8_t> trie(trieStart, read32(&dyldInfo->export_size, isBig));
513 Error Err = Error::success();
514 for (const ExportEntry &trieExport : MachOObjectFile::exports(Err, trie)) {
515 Export normExport;
516 normExport.name = trieExport.name().copy(f->ownedAllocations);
517 normExport.offset = trieExport.address();
518 normExport.kind = ExportSymbolKind(trieExport.flags() & EXPORT_SYMBOL_FLAGS_KIND_MASK);
519 normExport.flags = trieExport.flags() & ~EXPORT_SYMBOL_FLAGS_KIND_MASK;
520 normExport.otherOffset = trieExport.other();
521 if (!trieExport.otherName().empty())
522 normExport.otherName = trieExport.otherName().copy(f->ownedAllocations);
523 f->exportInfo.push_back(normExport);
524 }
525 if (Err)
526 return std::move(Err);
527 }
528 }
529
530 return std::move(f);
531 }
532
533 class MachOObjectReader : public Reader {
534 public:
MachOObjectReader(MachOLinkingContext & ctx)535 MachOObjectReader(MachOLinkingContext &ctx) : _ctx(ctx) {}
536
canParse(file_magic magic,MemoryBufferRef mb) const537 bool canParse(file_magic magic, MemoryBufferRef mb) const override {
538 return (magic == file_magic::macho_object && mb.getBufferSize() > 32);
539 }
540
541 ErrorOr<std::unique_ptr<File>>
loadFile(std::unique_ptr<MemoryBuffer> mb,const Registry & registry) const542 loadFile(std::unique_ptr<MemoryBuffer> mb,
543 const Registry ®istry) const override {
544 std::unique_ptr<File> ret =
545 std::make_unique<MachOFile>(std::move(mb), &_ctx);
546 return std::move(ret);
547 }
548
549 private:
550 MachOLinkingContext &_ctx;
551 };
552
553 class MachODylibReader : public Reader {
554 public:
MachODylibReader(MachOLinkingContext & ctx)555 MachODylibReader(MachOLinkingContext &ctx) : _ctx(ctx) {}
556
canParse(file_magic magic,MemoryBufferRef mb) const557 bool canParse(file_magic magic, MemoryBufferRef mb) const override {
558 switch (magic) {
559 case file_magic::macho_dynamically_linked_shared_lib:
560 case file_magic::macho_dynamically_linked_shared_lib_stub:
561 return mb.getBufferSize() > 32;
562 default:
563 return false;
564 }
565 }
566
567 ErrorOr<std::unique_ptr<File>>
loadFile(std::unique_ptr<MemoryBuffer> mb,const Registry & registry) const568 loadFile(std::unique_ptr<MemoryBuffer> mb,
569 const Registry ®istry) const override {
570 std::unique_ptr<File> ret =
571 std::make_unique<MachODylibFile>(std::move(mb), &_ctx);
572 return std::move(ret);
573 }
574
575 private:
576 MachOLinkingContext &_ctx;
577 };
578
579 class MachOTAPIReader : public Reader {
580 public:
MachOTAPIReader(MachOLinkingContext & ctx)581 MachOTAPIReader(MachOLinkingContext &ctx) : _ctx(ctx) {}
582
canParse(file_magic magic,MemoryBufferRef mb) const583 bool canParse(file_magic magic, MemoryBufferRef mb) const override {
584 return magic == file_magic::tapi_file;
585 }
586
587 ErrorOr<std::unique_ptr<File>>
loadFile(std::unique_ptr<MemoryBuffer> mb,const Registry & registry) const588 loadFile(std::unique_ptr<MemoryBuffer> mb,
589 const Registry ®istry) const override {
590 std::unique_ptr<File> ret =
591 std::make_unique<TAPIFile>(std::move(mb), &_ctx);
592 return std::move(ret);
593 }
594
595 private:
596 MachOLinkingContext &_ctx;
597 };
598
599 } // namespace normalized
600 } // namespace mach_o
601
addSupportMachOObjects(MachOLinkingContext & ctx)602 void Registry::addSupportMachOObjects(MachOLinkingContext &ctx) {
603 MachOLinkingContext::Arch arch = ctx.arch();
604 add(std::unique_ptr<Reader>(new mach_o::normalized::MachOObjectReader(ctx)));
605 add(std::unique_ptr<Reader>(new mach_o::normalized::MachODylibReader(ctx)));
606 add(std::unique_ptr<Reader>(new mach_o::normalized::MachOTAPIReader(ctx)));
607 addKindTable(Reference::KindNamespace::mach_o, ctx.archHandler().kindArch(),
608 ctx.archHandler().kindStrings());
609 add(std::unique_ptr<YamlIOTaggedDocumentHandler>(
610 new mach_o::MachOYamlIOTaggedDocumentHandler(arch)));
611 }
612
613
614 } // namespace lld
615