• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 = &sects[i];
296           Section section;
297           section.segmentName = getString16(sect->segname);
298           section.sectionName = getString16(sect->sectname);
299           section.type = (SectionType)(read32(&sect->flags, isBig) &
300                                        SECTION_TYPE);
301           section.attributes  = read32(&sect->flags, isBig) & SECTION_ATTRIBUTES;
302           section.alignment   = 1 << read32(&sect->align, isBig);
303           section.address     = read64(&sect->addr, isBig);
304           const uint8_t *content =
305             (const uint8_t *)start + read32(&sect->offset, isBig);
306           size_t contentSize = read64(&sect->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(&sect->reloff, isBig),
312                             read32(&sect->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(&sect->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 = &sects[i];
339           Section section;
340           section.segmentName = getString16(sect->segname);
341           section.sectionName = getString16(sect->sectname);
342           section.type = (SectionType)(read32(&sect->flags, isBig) &
343                                        SECTION_TYPE);
344           section.attributes =
345               read32((const uint8_t *)&sect->flags, isBig) & SECTION_ATTRIBUTES;
346           section.alignment   = 1 << read32(&sect->align, isBig);
347           section.address     = read32(&sect->addr, isBig);
348           const uint8_t *content =
349             (const uint8_t *)start + read32(&sect->offset, isBig);
350           size_t contentSize = read32(&sect->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(&sect->reloff, isBig),
356                             read32(&sect->nreloc, isBig));
357           if (section.type == S_NON_LAZY_SYMBOL_POINTERS) {
358             appendIndirectSymbols(
359                 section.indirectSymbols, mb->getBuffer(), isBig,
360                 indirectSymbolTableOffset, indirectSymbolTableCount,
361                 read32(&sect->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 &registry) 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 &registry) 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 &registry) 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