]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lld / lib / ReaderWriter / MachO / MachONormalizedFileYAML.cpp
1 //===- lib/ReaderWriter/MachO/MachONormalizedFileYAML.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 uses YAML I/O to
11 /// provide the convert between YAML and the normalized mach-o (NM).
12 ///
13 ///                  +------------+         +------+
14 ///                  | normalized |   <->   | yaml |
15 ///                  +------------+         +------+
16
17 #include "MachONormalizedFile.h"
18 #include "lld/Common/LLVM.h"
19 #include "lld/Core/Error.h"
20 #include "lld/ReaderWriter/YamlContext.h"
21 #include "llvm/ADT/SmallString.h"
22 #include "llvm/ADT/StringRef.h"
23 #include "llvm/ADT/StringSwitch.h"
24 #include "llvm/ADT/Twine.h"
25 #include "llvm/BinaryFormat/MachO.h"
26 #include "llvm/Support/Casting.h"
27 #include "llvm/Support/ErrorHandling.h"
28 #include "llvm/Support/Format.h"
29 #include "llvm/Support/MemoryBuffer.h"
30 #include "llvm/Support/SourceMgr.h"
31 #include "llvm/Support/YAMLTraits.h"
32 #include "llvm/Support/raw_ostream.h"
33 #include <system_error>
34
35 using llvm::StringRef;
36 using namespace llvm::yaml;
37 using namespace llvm::MachO;
38 using namespace lld::mach_o::normalized;
39 using lld::YamlContext;
40
41 LLVM_YAML_IS_SEQUENCE_VECTOR(Segment)
42 LLVM_YAML_IS_SEQUENCE_VECTOR(DependentDylib)
43 LLVM_YAML_IS_SEQUENCE_VECTOR(RebaseLocation)
44 LLVM_YAML_IS_SEQUENCE_VECTOR(BindLocation)
45 LLVM_YAML_IS_SEQUENCE_VECTOR(Export)
46 LLVM_YAML_IS_SEQUENCE_VECTOR(DataInCode)
47
48
49 // for compatibility with gcc-4.7 in C++11 mode, add extra namespace
50 namespace llvm {
51 namespace yaml {
52
53 // A vector of Sections is a sequence.
54 template<>
55 struct SequenceTraits< std::vector<Section> > {
56   static size_t size(IO &io, std::vector<Section> &seq) {
57     return seq.size();
58   }
59   static Section& element(IO &io, std::vector<Section> &seq, size_t index) {
60     if ( index >= seq.size() )
61       seq.resize(index+1);
62     return seq[index];
63   }
64 };
65
66 template<>
67 struct SequenceTraits< std::vector<Symbol> > {
68   static size_t size(IO &io, std::vector<Symbol> &seq) {
69     return seq.size();
70   }
71   static Symbol& element(IO &io, std::vector<Symbol> &seq, size_t index) {
72     if ( index >= seq.size() )
73       seq.resize(index+1);
74     return seq[index];
75   }
76 };
77
78 // A vector of Relocations is a sequence.
79 template<>
80 struct SequenceTraits< Relocations > {
81   static size_t size(IO &io, Relocations &seq) {
82     return seq.size();
83   }
84   static Relocation& element(IO &io, Relocations &seq, size_t index) {
85     if ( index >= seq.size() )
86       seq.resize(index+1);
87     return seq[index];
88   }
89 };
90
91 // The content for a section is represented as a flow sequence of hex bytes.
92 template<>
93 struct SequenceTraits< ContentBytes > {
94   static size_t size(IO &io, ContentBytes &seq) {
95     return seq.size();
96   }
97   static Hex8& element(IO &io, ContentBytes &seq, size_t index) {
98     if ( index >= seq.size() )
99       seq.resize(index+1);
100     return seq[index];
101   }
102   static const bool flow = true;
103 };
104
105 // The indirect symbols for a section is represented as a flow sequence
106 // of numbers (symbol table indexes).
107 template<>
108 struct SequenceTraits< IndirectSymbols > {
109   static size_t size(IO &io, IndirectSymbols &seq) {
110     return seq.size();
111   }
112   static uint32_t& element(IO &io, IndirectSymbols &seq, size_t index) {
113     if ( index >= seq.size() )
114       seq.resize(index+1);
115     return seq[index];
116   }
117   static const bool flow = true;
118 };
119
120 template <>
121 struct ScalarEnumerationTraits<lld::MachOLinkingContext::Arch> {
122   static void enumeration(IO &io, lld::MachOLinkingContext::Arch &value) {
123     io.enumCase(value, "unknown",lld::MachOLinkingContext::arch_unknown);
124     io.enumCase(value, "ppc",    lld::MachOLinkingContext::arch_ppc);
125     io.enumCase(value, "x86",    lld::MachOLinkingContext::arch_x86);
126     io.enumCase(value, "x86_64", lld::MachOLinkingContext::arch_x86_64);
127     io.enumCase(value, "armv6",  lld::MachOLinkingContext::arch_armv6);
128     io.enumCase(value, "armv7",  lld::MachOLinkingContext::arch_armv7);
129     io.enumCase(value, "armv7s", lld::MachOLinkingContext::arch_armv7s);
130     io.enumCase(value, "arm64",  lld::MachOLinkingContext::arch_arm64);
131   }
132 };
133
134 template <>
135 struct ScalarEnumerationTraits<lld::MachOLinkingContext::OS> {
136   static void enumeration(IO &io, lld::MachOLinkingContext::OS &value) {
137     io.enumCase(value, "unknown",
138                           lld::MachOLinkingContext::OS::unknown);
139     io.enumCase(value, "Mac OS X",
140                           lld::MachOLinkingContext::OS::macOSX);
141     io.enumCase(value, "iOS",
142                           lld::MachOLinkingContext::OS::iOS);
143     io.enumCase(value, "iOS Simulator",
144                           lld::MachOLinkingContext::OS::iOS_simulator);
145   }
146 };
147
148
149 template <>
150 struct ScalarEnumerationTraits<HeaderFileType> {
151   static void enumeration(IO &io, HeaderFileType &value) {
152     io.enumCase(value, "MH_OBJECT",   llvm::MachO::MH_OBJECT);
153     io.enumCase(value, "MH_DYLIB",    llvm::MachO::MH_DYLIB);
154     io.enumCase(value, "MH_EXECUTE",  llvm::MachO::MH_EXECUTE);
155     io.enumCase(value, "MH_BUNDLE",   llvm::MachO::MH_BUNDLE);
156   }
157 };
158
159
160 template <>
161 struct ScalarBitSetTraits<FileFlags> {
162   static void bitset(IO &io, FileFlags &value) {
163     io.bitSetCase(value, "MH_TWOLEVEL",
164                           llvm::MachO::MH_TWOLEVEL);
165     io.bitSetCase(value, "MH_SUBSECTIONS_VIA_SYMBOLS",
166                           llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
167   }
168 };
169
170
171 template <>
172 struct ScalarEnumerationTraits<SectionType> {
173   static void enumeration(IO &io, SectionType &value) {
174     io.enumCase(value, "S_REGULAR",
175                         llvm::MachO::S_REGULAR);
176     io.enumCase(value, "S_ZEROFILL",
177                         llvm::MachO::S_ZEROFILL);
178     io.enumCase(value, "S_CSTRING_LITERALS",
179                         llvm::MachO::S_CSTRING_LITERALS);
180     io.enumCase(value, "S_4BYTE_LITERALS",
181                         llvm::MachO::S_4BYTE_LITERALS);
182     io.enumCase(value, "S_8BYTE_LITERALS",
183                         llvm::MachO::S_8BYTE_LITERALS);
184     io.enumCase(value, "S_LITERAL_POINTERS",
185                         llvm::MachO::S_LITERAL_POINTERS);
186     io.enumCase(value, "S_NON_LAZY_SYMBOL_POINTERS",
187                         llvm::MachO::S_NON_LAZY_SYMBOL_POINTERS);
188     io.enumCase(value, "S_LAZY_SYMBOL_POINTERS",
189                         llvm::MachO::S_LAZY_SYMBOL_POINTERS);
190     io.enumCase(value, "S_SYMBOL_STUBS",
191                         llvm::MachO::S_SYMBOL_STUBS);
192     io.enumCase(value, "S_MOD_INIT_FUNC_POINTERS",
193                         llvm::MachO::S_MOD_INIT_FUNC_POINTERS);
194     io.enumCase(value, "S_MOD_TERM_FUNC_POINTERS",
195                         llvm::MachO::S_MOD_TERM_FUNC_POINTERS);
196     io.enumCase(value, "S_COALESCED",
197                         llvm::MachO::S_COALESCED);
198     io.enumCase(value, "S_GB_ZEROFILL",
199                         llvm::MachO::S_GB_ZEROFILL);
200     io.enumCase(value, "S_INTERPOSING",
201                         llvm::MachO::S_INTERPOSING);
202     io.enumCase(value, "S_16BYTE_LITERALS",
203                         llvm::MachO::S_16BYTE_LITERALS);
204     io.enumCase(value, "S_DTRACE_DOF",
205                         llvm::MachO::S_DTRACE_DOF);
206     io.enumCase(value, "S_LAZY_DYLIB_SYMBOL_POINTERS",
207                         llvm::MachO::S_LAZY_DYLIB_SYMBOL_POINTERS);
208     io.enumCase(value, "S_THREAD_LOCAL_REGULAR",
209                         llvm::MachO::S_THREAD_LOCAL_REGULAR);
210     io.enumCase(value, "S_THREAD_LOCAL_ZEROFILL",
211                         llvm::MachO::S_THREAD_LOCAL_ZEROFILL);
212     io.enumCase(value, "S_THREAD_LOCAL_VARIABLES",
213                         llvm::MachO::S_THREAD_LOCAL_VARIABLES);
214     io.enumCase(value, "S_THREAD_LOCAL_VARIABLE_POINTERS",
215                         llvm::MachO::S_THREAD_LOCAL_VARIABLE_POINTERS);
216     io.enumCase(value, "S_THREAD_LOCAL_INIT_FUNCTION_POINTERS",
217                         llvm::MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS);
218   }
219 };
220
221 template <>
222 struct ScalarBitSetTraits<SectionAttr> {
223   static void bitset(IO &io, SectionAttr &value) {
224     io.bitSetCase(value, "S_ATTR_PURE_INSTRUCTIONS",
225                           llvm::MachO::S_ATTR_PURE_INSTRUCTIONS);
226     io.bitSetCase(value, "S_ATTR_SOME_INSTRUCTIONS",
227                           llvm::MachO::S_ATTR_SOME_INSTRUCTIONS);
228     io.bitSetCase(value, "S_ATTR_NO_DEAD_STRIP",
229                           llvm::MachO::S_ATTR_NO_DEAD_STRIP);
230     io.bitSetCase(value, "S_ATTR_EXT_RELOC",
231                           llvm::MachO::S_ATTR_EXT_RELOC);
232     io.bitSetCase(value, "S_ATTR_LOC_RELOC",
233                           llvm::MachO::S_ATTR_LOC_RELOC);
234     io.bitSetCase(value, "S_ATTR_DEBUG",
235                          llvm::MachO::S_ATTR_DEBUG);
236   }
237 };
238
239 /// This is a custom formatter for SectionAlignment.  Values are
240 /// the power to raise by, ie, the n in 2^n.
241 template <> struct ScalarTraits<SectionAlignment> {
242   static void output(const SectionAlignment &value, void *ctxt,
243                      raw_ostream &out) {
244     out << llvm::format("%d", (uint32_t)value);
245   }
246
247   static StringRef input(StringRef scalar, void *ctxt,
248                          SectionAlignment &value) {
249     uint32_t alignment;
250     if (scalar.getAsInteger(0, alignment)) {
251       return "malformed alignment value";
252     }
253     if (!llvm::isPowerOf2_32(alignment))
254       return "alignment must be a power of 2";
255     value = alignment;
256     return StringRef(); // returning empty string means success
257   }
258
259   static QuotingType mustQuote(StringRef) { return QuotingType::None; }
260 };
261
262 template <>
263 struct ScalarEnumerationTraits<NListType> {
264   static void enumeration(IO &io, NListType &value) {
265     io.enumCase(value, "N_UNDF",  llvm::MachO::N_UNDF);
266     io.enumCase(value, "N_ABS",   llvm::MachO::N_ABS);
267     io.enumCase(value, "N_SECT",  llvm::MachO::N_SECT);
268     io.enumCase(value, "N_PBUD",  llvm::MachO::N_PBUD);
269     io.enumCase(value, "N_INDR",  llvm::MachO::N_INDR);
270   }
271 };
272
273 template <>
274 struct ScalarBitSetTraits<SymbolScope> {
275   static void bitset(IO &io, SymbolScope &value) {
276     io.bitSetCase(value, "N_EXT",   llvm::MachO::N_EXT);
277     io.bitSetCase(value, "N_PEXT",  llvm::MachO::N_PEXT);
278   }
279 };
280
281 template <>
282 struct ScalarBitSetTraits<SymbolDesc> {
283   static void bitset(IO &io, SymbolDesc &value) {
284     io.bitSetCase(value, "N_NO_DEAD_STRIP",   llvm::MachO::N_NO_DEAD_STRIP);
285     io.bitSetCase(value, "N_WEAK_REF",        llvm::MachO::N_WEAK_REF);
286     io.bitSetCase(value, "N_WEAK_DEF",        llvm::MachO::N_WEAK_DEF);
287     io.bitSetCase(value, "N_ARM_THUMB_DEF",   llvm::MachO::N_ARM_THUMB_DEF);
288     io.bitSetCase(value, "N_SYMBOL_RESOLVER", llvm::MachO::N_SYMBOL_RESOLVER);
289   }
290 };
291
292
293 template <>
294 struct MappingTraits<Section> {
295   struct NormalizedContentBytes;
296   static void mapping(IO &io, Section &sect) {
297     io.mapRequired("segment",         sect.segmentName);
298     io.mapRequired("section",         sect.sectionName);
299     io.mapRequired("type",            sect.type);
300     io.mapOptional("attributes",      sect.attributes);
301     io.mapOptional("alignment",       sect.alignment, (SectionAlignment)1);
302     io.mapRequired("address",         sect.address);
303     if (isZeroFillSection(sect.type)) {
304       // S_ZEROFILL sections use "size:" instead of "content:"
305       uint64_t size = sect.content.size();
306       io.mapOptional("size",          size);
307       if (!io.outputting()) {
308         uint8_t *bytes = nullptr;
309         sect.content = makeArrayRef(bytes, size);
310       }
311     } else {
312       MappingNormalization<NormalizedContent, ArrayRef<uint8_t>> content(
313         io, sect.content);
314       io.mapOptional("content",         content->_normalizedContent);
315     }
316     io.mapOptional("relocations",     sect.relocations);
317     io.mapOptional("indirect-syms",   sect.indirectSymbols);
318   }
319
320   struct NormalizedContent {
321     NormalizedContent(IO &io) : _io(io) {}
322     NormalizedContent(IO &io, ArrayRef<uint8_t> content) : _io(io) {
323       // When writing yaml, copy content byte array to Hex8 vector.
324       for (auto &c : content) {
325         _normalizedContent.push_back(c);
326       }
327     }
328     ArrayRef<uint8_t> denormalize(IO &io) {
329       // When reading yaml, allocate byte array owned by NormalizedFile and
330       // copy Hex8 vector to byte array.
331       YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
332       assert(info != nullptr);
333       NormalizedFile *file = info->_normalizeMachOFile;
334       assert(file != nullptr);
335       size_t size = _normalizedContent.size();
336       if (!size)
337         return None;
338       uint8_t *bytes = file->ownedAllocations.Allocate<uint8_t>(size);
339       std::copy(_normalizedContent.begin(), _normalizedContent.end(), bytes);
340       return makeArrayRef(bytes, size);
341     }
342
343     IO                &_io;
344     ContentBytes       _normalizedContent;
345   };
346 };
347
348
349 template <>
350 struct MappingTraits<Relocation> {
351   static void mapping(IO &io, Relocation &reloc) {
352     io.mapRequired("offset",    reloc.offset);
353     io.mapOptional("scattered", reloc.scattered, false);
354     io.mapRequired("type",      reloc.type);
355     io.mapRequired("length",    reloc.length);
356     io.mapRequired("pc-rel",    reloc.pcRel);
357     if ( !reloc.scattered )
358      io.mapRequired("extern",   reloc.isExtern);
359     if ( reloc.scattered )
360      io.mapRequired("value",    reloc.value);
361     if ( !reloc.scattered )
362      io.mapRequired("symbol",   reloc.symbol);
363   }
364 };
365
366
367 template <>
368 struct ScalarEnumerationTraits<RelocationInfoType> {
369   static void enumeration(IO &io, RelocationInfoType &value) {
370     YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
371     assert(info != nullptr);
372     NormalizedFile *file = info->_normalizeMachOFile;
373     assert(file != nullptr);
374     switch (file->arch) {
375     case lld::MachOLinkingContext::arch_x86_64:
376       io.enumCase(value, "X86_64_RELOC_UNSIGNED",
377                                   llvm::MachO::X86_64_RELOC_UNSIGNED);
378       io.enumCase(value, "X86_64_RELOC_SIGNED",
379                                   llvm::MachO::X86_64_RELOC_SIGNED);
380       io.enumCase(value, "X86_64_RELOC_BRANCH",
381                                   llvm::MachO::X86_64_RELOC_BRANCH);
382       io.enumCase(value, "X86_64_RELOC_GOT_LOAD",
383                                   llvm::MachO::X86_64_RELOC_GOT_LOAD);
384       io.enumCase(value, "X86_64_RELOC_GOT",
385                                   llvm::MachO::X86_64_RELOC_GOT);
386       io.enumCase(value, "X86_64_RELOC_SUBTRACTOR",
387                                   llvm::MachO::X86_64_RELOC_SUBTRACTOR);
388       io.enumCase(value, "X86_64_RELOC_SIGNED_1",
389                                   llvm::MachO::X86_64_RELOC_SIGNED_1);
390       io.enumCase(value, "X86_64_RELOC_SIGNED_2",
391                                   llvm::MachO::X86_64_RELOC_SIGNED_2);
392       io.enumCase(value, "X86_64_RELOC_SIGNED_4",
393                                   llvm::MachO::X86_64_RELOC_SIGNED_4);
394       io.enumCase(value, "X86_64_RELOC_TLV",
395                                   llvm::MachO::X86_64_RELOC_TLV);
396       break;
397     case lld::MachOLinkingContext::arch_x86:
398       io.enumCase(value, "GENERIC_RELOC_VANILLA",
399                                   llvm::MachO::GENERIC_RELOC_VANILLA);
400       io.enumCase(value, "GENERIC_RELOC_PAIR",
401                                   llvm::MachO::GENERIC_RELOC_PAIR);
402       io.enumCase(value, "GENERIC_RELOC_SECTDIFF",
403                                   llvm::MachO::GENERIC_RELOC_SECTDIFF);
404       io.enumCase(value, "GENERIC_RELOC_LOCAL_SECTDIFF",
405                                   llvm::MachO::GENERIC_RELOC_LOCAL_SECTDIFF);
406       io.enumCase(value, "GENERIC_RELOC_TLV",
407                                   llvm::MachO::GENERIC_RELOC_TLV);
408       break;
409     case lld::MachOLinkingContext::arch_armv6:
410     case lld::MachOLinkingContext::arch_armv7:
411     case lld::MachOLinkingContext::arch_armv7s:
412        io.enumCase(value, "ARM_RELOC_VANILLA",
413                                   llvm::MachO::ARM_RELOC_VANILLA);
414       io.enumCase(value, "ARM_RELOC_PAIR",
415                                   llvm::MachO::ARM_RELOC_PAIR);
416       io.enumCase(value, "ARM_RELOC_SECTDIFF",
417                                   llvm::MachO::ARM_RELOC_SECTDIFF);
418       io.enumCase(value, "ARM_RELOC_LOCAL_SECTDIFF",
419                                   llvm::MachO::ARM_RELOC_LOCAL_SECTDIFF);
420       io.enumCase(value, "ARM_RELOC_BR24",
421                                   llvm::MachO::ARM_RELOC_BR24);
422       io.enumCase(value, "ARM_THUMB_RELOC_BR22",
423                                   llvm::MachO::ARM_THUMB_RELOC_BR22);
424       io.enumCase(value, "ARM_RELOC_HALF",
425                                   llvm::MachO::ARM_RELOC_HALF);
426       io.enumCase(value, "ARM_RELOC_HALF_SECTDIFF",
427                                   llvm::MachO::ARM_RELOC_HALF_SECTDIFF);
428       break;
429     case lld::MachOLinkingContext::arch_arm64:
430       io.enumCase(value, "ARM64_RELOC_UNSIGNED",
431                                   llvm::MachO::ARM64_RELOC_UNSIGNED);
432       io.enumCase(value, "ARM64_RELOC_SUBTRACTOR",
433                                   llvm::MachO::ARM64_RELOC_SUBTRACTOR);
434       io.enumCase(value, "ARM64_RELOC_BRANCH26",
435                                   llvm::MachO::ARM64_RELOC_BRANCH26);
436       io.enumCase(value, "ARM64_RELOC_PAGE21",
437                                   llvm::MachO::ARM64_RELOC_PAGE21);
438       io.enumCase(value, "ARM64_RELOC_PAGEOFF12",
439                                   llvm::MachO::ARM64_RELOC_PAGEOFF12);
440       io.enumCase(value, "ARM64_RELOC_GOT_LOAD_PAGE21",
441                                   llvm::MachO::ARM64_RELOC_GOT_LOAD_PAGE21);
442       io.enumCase(value, "ARM64_RELOC_GOT_LOAD_PAGEOFF12",
443                                   llvm::MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12);
444       io.enumCase(value, "ARM64_RELOC_POINTER_TO_GOT",
445                                   llvm::MachO::ARM64_RELOC_POINTER_TO_GOT);
446       io.enumCase(value, "ARM64_RELOC_TLVP_LOAD_PAGE21",
447                                   llvm::MachO::ARM64_RELOC_TLVP_LOAD_PAGE21);
448       io.enumCase(value, "ARM64_RELOC_TLVP_LOAD_PAGEOFF12",
449                                   llvm::MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12);
450       io.enumCase(value, "ARM64_RELOC_ADDEND",
451                                   llvm::MachO::ARM64_RELOC_ADDEND);
452       break;
453     default:
454       llvm_unreachable("unknown architecture");
455     }
456  }
457 };
458
459
460 template <>
461 struct MappingTraits<Symbol> {
462   static void mapping(IO &io, Symbol& sym) {
463     io.mapRequired("name",    sym.name);
464     io.mapRequired("type",    sym.type);
465     io.mapOptional("scope",   sym.scope, SymbolScope(0));
466     io.mapOptional("sect",    sym.sect, (uint8_t)0);
467     if (sym.type == llvm::MachO::N_UNDF) {
468       // In undef symbols, desc field contains alignment/ordinal info
469       // which is better represented as a hex vaule.
470       uint16_t t1 = sym.desc;
471       Hex16 t2 = t1;
472       io.mapOptional("desc",  t2, Hex16(0));
473       sym.desc = t2;
474     } else {
475       // In defined symbols, desc fit is a set of option bits.
476       io.mapOptional("desc",    sym.desc, SymbolDesc(0));
477     }
478     io.mapRequired("value",  sym.value);
479   }
480 };
481
482 // Custom mapping for VMProtect (e.g. "r-x").
483 template <>
484 struct ScalarTraits<VMProtect> {
485   static void output(const VMProtect &value, void*, raw_ostream &out) {
486     out << ( (value & llvm::MachO::VM_PROT_READ)    ? 'r' : '-');
487     out << ( (value & llvm::MachO::VM_PROT_WRITE)   ? 'w' : '-');
488     out << ( (value & llvm::MachO::VM_PROT_EXECUTE) ? 'x' : '-');
489   }
490   static StringRef input(StringRef scalar, void*, VMProtect &value) {
491     value = 0;
492     if (scalar.size() != 3)
493       return "segment access protection must be three chars (e.g. \"r-x\")";
494     switch (scalar[0]) {
495     case 'r':
496       value = llvm::MachO::VM_PROT_READ;
497       break;
498     case '-':
499       break;
500     default:
501       return "segment access protection first char must be 'r' or '-'";
502     }
503     switch (scalar[1]) {
504     case 'w':
505       value = value | llvm::MachO::VM_PROT_WRITE;
506       break;
507     case '-':
508       break;
509     default:
510       return "segment access protection second char must be 'w' or '-'";
511     }
512     switch (scalar[2]) {
513     case 'x':
514       value = value | llvm::MachO::VM_PROT_EXECUTE;
515       break;
516     case '-':
517       break;
518     default:
519       return "segment access protection third char must be 'x' or '-'";
520     }
521     // Return the empty string on success,
522     return StringRef();
523   }
524   static QuotingType mustQuote(StringRef) { return QuotingType::None; }
525 };
526
527
528 template <>
529 struct MappingTraits<Segment> {
530   static void mapping(IO &io, Segment& seg) {
531     io.mapRequired("name",            seg.name);
532     io.mapRequired("address",         seg.address);
533     io.mapRequired("size",            seg.size);
534     io.mapRequired("init-access",     seg.init_access);
535     io.mapRequired("max-access",      seg.max_access);
536   }
537 };
538
539 template <>
540 struct ScalarEnumerationTraits<LoadCommandType> {
541   static void enumeration(IO &io, LoadCommandType &value) {
542     io.enumCase(value, "LC_LOAD_DYLIB",
543                         llvm::MachO::LC_LOAD_DYLIB);
544     io.enumCase(value, "LC_LOAD_WEAK_DYLIB",
545                         llvm::MachO::LC_LOAD_WEAK_DYLIB);
546     io.enumCase(value, "LC_REEXPORT_DYLIB",
547                         llvm::MachO::LC_REEXPORT_DYLIB);
548     io.enumCase(value, "LC_LOAD_UPWARD_DYLIB",
549                         llvm::MachO::LC_LOAD_UPWARD_DYLIB);
550     io.enumCase(value, "LC_LAZY_LOAD_DYLIB",
551                         llvm::MachO::LC_LAZY_LOAD_DYLIB);
552     io.enumCase(value, "LC_VERSION_MIN_MACOSX",
553                         llvm::MachO::LC_VERSION_MIN_MACOSX);
554     io.enumCase(value, "LC_VERSION_MIN_IPHONEOS",
555                         llvm::MachO::LC_VERSION_MIN_IPHONEOS);
556     io.enumCase(value, "LC_VERSION_MIN_TVOS",
557                         llvm::MachO::LC_VERSION_MIN_TVOS);
558     io.enumCase(value, "LC_VERSION_MIN_WATCHOS",
559                         llvm::MachO::LC_VERSION_MIN_WATCHOS);
560   }
561 };
562
563 template <>
564 struct MappingTraits<DependentDylib> {
565   static void mapping(IO &io, DependentDylib& dylib) {
566     io.mapRequired("path",            dylib.path);
567     io.mapOptional("kind",            dylib.kind,
568                                       llvm::MachO::LC_LOAD_DYLIB);
569     io.mapOptional("compat-version",  dylib.compatVersion,
570                                       PackedVersion(0x10000));
571     io.mapOptional("current-version", dylib.currentVersion,
572                                       PackedVersion(0x10000));
573   }
574 };
575
576 template <>
577 struct ScalarEnumerationTraits<RebaseType> {
578   static void enumeration(IO &io, RebaseType &value) {
579     io.enumCase(value, "REBASE_TYPE_POINTER",
580                         llvm::MachO::REBASE_TYPE_POINTER);
581     io.enumCase(value, "REBASE_TYPE_TEXT_PCREL32",
582                         llvm::MachO::REBASE_TYPE_TEXT_PCREL32);
583     io.enumCase(value, "REBASE_TYPE_TEXT_ABSOLUTE32",
584                         llvm::MachO::REBASE_TYPE_TEXT_ABSOLUTE32);
585   }
586 };
587
588
589 template <>
590 struct MappingTraits<RebaseLocation> {
591   static void mapping(IO &io, RebaseLocation& rebase) {
592     io.mapRequired("segment-index",   rebase.segIndex);
593     io.mapRequired("segment-offset",  rebase.segOffset);
594     io.mapOptional("kind",            rebase.kind,
595                                       llvm::MachO::REBASE_TYPE_POINTER);
596   }
597 };
598
599
600
601 template <>
602 struct ScalarEnumerationTraits<BindType> {
603   static void enumeration(IO &io, BindType &value) {
604     io.enumCase(value, "BIND_TYPE_POINTER",
605                         llvm::MachO::BIND_TYPE_POINTER);
606     io.enumCase(value, "BIND_TYPE_TEXT_ABSOLUTE32",
607                         llvm::MachO::BIND_TYPE_TEXT_ABSOLUTE32);
608     io.enumCase(value, "BIND_TYPE_TEXT_PCREL32",
609                         llvm::MachO::BIND_TYPE_TEXT_PCREL32);
610   }
611 };
612
613 template <>
614 struct MappingTraits<BindLocation> {
615   static void mapping(IO &io, BindLocation &bind) {
616     io.mapRequired("segment-index",   bind.segIndex);
617     io.mapRequired("segment-offset",  bind.segOffset);
618     io.mapOptional("kind",            bind.kind,
619                                       llvm::MachO::BIND_TYPE_POINTER);
620     io.mapOptional("can-be-null",     bind.canBeNull, false);
621     io.mapRequired("ordinal",         bind.ordinal);
622     io.mapRequired("symbol-name",     bind.symbolName);
623     io.mapOptional("addend",          bind.addend, Hex64(0));
624   }
625 };
626
627
628 template <>
629 struct ScalarEnumerationTraits<ExportSymbolKind> {
630   static void enumeration(IO &io, ExportSymbolKind &value) {
631     io.enumCase(value, "EXPORT_SYMBOL_FLAGS_KIND_REGULAR",
632                         llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_REGULAR);
633     io.enumCase(value, "EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL",
634                         llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL);
635     io.enumCase(value, "EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE",
636                         llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);
637   }
638 };
639
640 template <>
641 struct ScalarBitSetTraits<ExportFlags> {
642   static void bitset(IO &io, ExportFlags &value) {
643     io.bitSetCase(value, "EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION",
644                           llvm::MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
645     io.bitSetCase(value, "EXPORT_SYMBOL_FLAGS_REEXPORT",
646                           llvm::MachO::EXPORT_SYMBOL_FLAGS_REEXPORT);
647     io.bitSetCase(value, "EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER",
648                           llvm::MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);
649   }
650 };
651
652
653 template <>
654 struct MappingTraits<Export> {
655   static void mapping(IO &io, Export &exp) {
656     io.mapRequired("name",         exp.name);
657     io.mapOptional("offset",       exp.offset);
658     io.mapOptional("kind",         exp.kind,
659                                 llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_REGULAR);
660     if (!io.outputting() || exp.flags)
661       io.mapOptional("flags",      exp.flags);
662     io.mapOptional("other",        exp.otherOffset, Hex32(0));
663     io.mapOptional("other-name",   exp.otherName, StringRef());
664   }
665 };
666
667 template <>
668 struct ScalarEnumerationTraits<DataRegionType> {
669   static void enumeration(IO &io, DataRegionType &value) {
670     io.enumCase(value, "DICE_KIND_DATA",
671                         llvm::MachO::DICE_KIND_DATA);
672     io.enumCase(value, "DICE_KIND_JUMP_TABLE8",
673                         llvm::MachO::DICE_KIND_JUMP_TABLE8);
674     io.enumCase(value, "DICE_KIND_JUMP_TABLE16",
675                         llvm::MachO::DICE_KIND_JUMP_TABLE16);
676     io.enumCase(value, "DICE_KIND_JUMP_TABLE32",
677                         llvm::MachO::DICE_KIND_JUMP_TABLE32);
678     io.enumCase(value, "DICE_KIND_ABS_JUMP_TABLE32",
679                         llvm::MachO::DICE_KIND_ABS_JUMP_TABLE32);
680   }
681 };
682
683 template <>
684 struct MappingTraits<DataInCode> {
685   static void mapping(IO &io, DataInCode &entry) {
686     io.mapRequired("offset",       entry.offset);
687     io.mapRequired("length",       entry.length);
688     io.mapRequired("kind",         entry.kind);
689   }
690 };
691
692 template <>
693 struct ScalarTraits<PackedVersion> {
694   static void output(const PackedVersion &value, void*, raw_ostream &out) {
695     out << llvm::format("%d.%d", (value >> 16), (value >> 8) & 0xFF);
696     if (value & 0xFF) {
697       out << llvm::format(".%d", (value & 0xFF));
698     }
699   }
700   static StringRef input(StringRef scalar, void*, PackedVersion &result) {
701     uint32_t value;
702     if (lld::MachOLinkingContext::parsePackedVersion(scalar, value))
703       return "malformed version number";
704     result = value;
705     // Return the empty string on success,
706     return StringRef();
707   }
708   static QuotingType mustQuote(StringRef) { return QuotingType::None; }
709 };
710
711 template <>
712 struct MappingTraits<NormalizedFile> {
713   static void mapping(IO &io, NormalizedFile &file) {
714     io.mapRequired("arch",             file.arch);
715     io.mapRequired("file-type",        file.fileType);
716     io.mapOptional("flags",            file.flags);
717     io.mapOptional("dependents",       file.dependentDylibs);
718     io.mapOptional("install-name",     file.installName,    StringRef());
719     io.mapOptional("compat-version",   file.compatVersion,  PackedVersion(0x10000));
720     io.mapOptional("current-version",  file.currentVersion, PackedVersion(0x10000));
721     io.mapOptional("has-UUID",         file.hasUUID,        true);
722     io.mapOptional("rpaths",           file.rpaths);
723     io.mapOptional("entry-point",      file.entryAddress,   Hex64(0));
724     io.mapOptional("stack-size",       file.stackSize,      Hex64(0));
725     io.mapOptional("source-version",   file.sourceVersion,  Hex64(0));
726     io.mapOptional("OS",               file.os);
727     io.mapOptional("min-os-version",   file.minOSverson,    PackedVersion(0));
728     io.mapOptional("min-os-version-kind",   file.minOSVersionKind, (LoadCommandType)0);
729     io.mapOptional("sdk-version",      file.sdkVersion,     PackedVersion(0));
730     io.mapOptional("segments",         file.segments);
731     io.mapOptional("sections",         file.sections);
732     io.mapOptional("local-symbols",    file.localSymbols);
733     io.mapOptional("global-symbols",   file.globalSymbols);
734     io.mapOptional("undefined-symbols",file.undefinedSymbols);
735     io.mapOptional("page-size",        file.pageSize,       Hex32(4096));
736     io.mapOptional("rebasings",        file.rebasingInfo);
737     io.mapOptional("bindings",         file.bindingInfo);
738     io.mapOptional("weak-bindings",    file.weakBindingInfo);
739     io.mapOptional("lazy-bindings",    file.lazyBindingInfo);
740     io.mapOptional("exports",          file.exportInfo);
741     io.mapOptional("dataInCode",       file.dataInCode);
742   }
743   static StringRef validate(IO &io, NormalizedFile &file) {
744     return StringRef();
745   }
746 };
747
748 } // namespace llvm
749 } // namespace yaml
750
751
752 namespace lld {
753 namespace mach_o {
754
755 /// Handles !mach-o tagged yaml documents.
756 bool MachOYamlIOTaggedDocumentHandler::handledDocTag(llvm::yaml::IO &io,
757                                                  const lld::File *&file) const {
758   if (!io.mapTag("!mach-o"))
759     return false;
760   // Step 1: parse yaml into normalized mach-o struct.
761   NormalizedFile nf;
762   YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
763   assert(info != nullptr);
764   assert(info->_normalizeMachOFile == nullptr);
765   info->_normalizeMachOFile = &nf;
766   MappingTraits<NormalizedFile>::mapping(io, nf);
767   // Step 2: parse normalized mach-o struct into atoms.
768   auto fileOrError = normalizedToAtoms(nf, info->_path, true);
769
770   // Check that we parsed successfully.
771   if (!fileOrError) {
772     std::string buffer;
773     llvm::raw_string_ostream stream(buffer);
774     handleAllErrors(fileOrError.takeError(),
775                     [&](const llvm::ErrorInfoBase &EI) {
776       EI.log(stream);
777       stream << "\n";
778     });
779     io.setError(stream.str());
780     return false;
781   }
782
783   if (nf.arch != _arch) {
784     io.setError(Twine("file is wrong architecture. Expected ("
785                       + MachOLinkingContext::nameFromArch(_arch)
786                       + ") found ("
787                       + MachOLinkingContext::nameFromArch(nf.arch)
788                       + ")"));
789     return false;
790   }
791   info->_normalizeMachOFile = nullptr;
792   file = fileOrError->release();
793   return true;
794 }
795
796
797
798 namespace normalized {
799
800 /// Parses a yaml encoded mach-o file to produce an in-memory normalized view.
801 llvm::Expected<std::unique_ptr<NormalizedFile>>
802 readYaml(std::unique_ptr<MemoryBuffer> &mb) {
803   // Make empty NormalizedFile.
804   std::unique_ptr<NormalizedFile> f(new NormalizedFile());
805
806   // Create YAML Input parser.
807   YamlContext yamlContext;
808   yamlContext._normalizeMachOFile = f.get();
809   llvm::yaml::Input yin(mb->getBuffer(), &yamlContext);
810
811   // Fill NormalizedFile by parsing yaml.
812   yin >> *f;
813
814   // Return error if there were parsing problems.
815   if (auto ec = yin.error())
816     return llvm::make_error<GenericError>(Twine("YAML parsing error: ")
817                                           + ec.message());
818
819   // Hand ownership of instantiated NormalizedFile to caller.
820   return std::move(f);
821 }
822
823
824 /// Writes a yaml encoded mach-o files from an in-memory normalized view.
825 std::error_code writeYaml(const NormalizedFile &file, raw_ostream &out) {
826   // YAML I/O is not const aware, so need to cast away ;-(
827   NormalizedFile *f = const_cast<NormalizedFile*>(&file);
828
829   // Create yaml Output writer, using yaml options for context.
830   YamlContext yamlContext;
831   yamlContext._normalizeMachOFile = f;
832   llvm::yaml::Output yout(out, &yamlContext);
833
834   // Stream out yaml.
835   yout << *f;
836
837   return std::error_code();
838 }
839
840 } // namespace normalized
841 } // namespace mach_o
842 } // namespace lld