]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lld / lib / ReaderWriter / YAML / ReaderWriterYAML.cpp
1 //===- lib/ReaderWriter/YAML/ReaderWriterYAML.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 #include "lld/Core/AbsoluteAtom.h"
10 #include "lld/Core/ArchiveLibraryFile.h"
11 #include "lld/Core/Atom.h"
12 #include "lld/Core/DefinedAtom.h"
13 #include "lld/Core/Error.h"
14 #include "lld/Core/File.h"
15 #include "lld/Core/LinkingContext.h"
16 #include "lld/Core/Reader.h"
17 #include "lld/Core/Reference.h"
18 #include "lld/Core/SharedLibraryAtom.h"
19 #include "lld/Core/Simple.h"
20 #include "lld/Core/UndefinedAtom.h"
21 #include "lld/Core/Writer.h"
22 #include "lld/ReaderWriter/YamlContext.h"
23 #include "llvm/ADT/ArrayRef.h"
24 #include "llvm/ADT/DenseMap.h"
25 #include "llvm/ADT/StringMap.h"
26 #include "llvm/ADT/StringRef.h"
27 #include "llvm/ADT/Twine.h"
28 #include "llvm/BinaryFormat/Magic.h"
29 #include "llvm/Support/Allocator.h"
30 #include "llvm/Support/Debug.h"
31 #include "llvm/Support/Error.h"
32 #include "llvm/Support/ErrorOr.h"
33 #include "llvm/Support/FileSystem.h"
34 #include "llvm/Support/Format.h"
35 #include "llvm/Support/MemoryBuffer.h"
36 #include "llvm/Support/YAMLTraits.h"
37 #include "llvm/Support/raw_ostream.h"
38 #include <cassert>
39 #include <cstdint>
40 #include <cstring>
41 #include <memory>
42 #include <string>
43 #include <system_error>
44 #include <vector>
45
46 using llvm::file_magic;
47 using llvm::yaml::MappingTraits;
48 using llvm::yaml::ScalarEnumerationTraits;
49 using llvm::yaml::ScalarTraits;
50 using llvm::yaml::IO;
51 using llvm::yaml::SequenceTraits;
52 using llvm::yaml::DocumentListTraits;
53
54 using namespace lld;
55
56 /// The conversion of Atoms to and from YAML uses LLVM's YAML I/O.  This
57 /// file just defines template specializations on the lld types which control
58 /// how the mapping is done to and from YAML.
59
60 namespace {
61
62 /// Used when writing yaml files.
63 /// In most cases, atoms names are unambiguous, so references can just
64 /// use the atom name as the target (e.g. target: foo).  But in a few
65 /// cases that does not work, so ref-names are added.  These are labels
66 /// used only in yaml.  The labels do not exist in the Atom model.
67 ///
68 /// One need for ref-names are when atoms have no user supplied name
69 /// (e.g. c-string literal).  Another case is when two object files with
70 /// identically named static functions are merged (ld -r) into one object file.
71 /// In that case referencing the function by name is ambiguous, so a unique
72 /// ref-name is added.
73 class RefNameBuilder {
74 public:
75   RefNameBuilder(const lld::File &file)
76       : _collisionCount(0), _unnamedCounter(0) {
77     // visit all atoms
78     for (const lld::DefinedAtom *atom : file.defined()) {
79       // Build map of atoms names to detect duplicates
80       if (!atom->name().empty())
81         buildDuplicateNameMap(*atom);
82
83       // Find references to unnamed atoms and create ref-names for them.
84       for (const lld::Reference *ref : *atom) {
85         // create refname for any unnamed reference target
86         const lld::Atom *target = ref->target();
87         if ((target != nullptr) && target->name().empty()) {
88           std::string storage;
89           llvm::raw_string_ostream buffer(storage);
90           buffer << llvm::format("L%03d", _unnamedCounter++);
91           StringRef newName = copyString(buffer.str());
92           _refNames[target] = newName;
93           DEBUG_WITH_TYPE("WriterYAML",
94                           llvm::dbgs() << "unnamed atom: creating ref-name: '"
95                                        << newName << "' ("
96                                        << (const void *)newName.data() << ", "
97                                        << newName.size() << ")\n");
98         }
99       }
100     }
101     for (const lld::UndefinedAtom *undefAtom : file.undefined()) {
102       buildDuplicateNameMap(*undefAtom);
103     }
104     for (const lld::SharedLibraryAtom *shlibAtom : file.sharedLibrary()) {
105       buildDuplicateNameMap(*shlibAtom);
106     }
107     for (const lld::AbsoluteAtom *absAtom : file.absolute()) {
108       if (!absAtom->name().empty())
109         buildDuplicateNameMap(*absAtom);
110     }
111   }
112
113   void buildDuplicateNameMap(const lld::Atom &atom) {
114     assert(!atom.name().empty());
115     NameToAtom::iterator pos = _nameMap.find(atom.name());
116     if (pos != _nameMap.end()) {
117       // Found name collision, give each a unique ref-name.
118       std::string Storage;
119       llvm::raw_string_ostream buffer(Storage);
120       buffer << atom.name() << llvm::format(".%03d", ++_collisionCount);
121       StringRef newName = copyString(buffer.str());
122       _refNames[&atom] = newName;
123       DEBUG_WITH_TYPE("WriterYAML",
124                       llvm::dbgs() << "name collsion: creating ref-name: '"
125                                    << newName << "' ("
126                                    << (const void *)newName.data()
127                                    << ", " << newName.size() << ")\n");
128       const lld::Atom *prevAtom = pos->second;
129       AtomToRefName::iterator pos2 = _refNames.find(prevAtom);
130       if (pos2 == _refNames.end()) {
131         // Only create ref-name for previous if none already created.
132         std::string Storage2;
133         llvm::raw_string_ostream buffer2(Storage2);
134         buffer2 << prevAtom->name() << llvm::format(".%03d", ++_collisionCount);
135         StringRef newName2 = copyString(buffer2.str());
136         _refNames[prevAtom] = newName2;
137         DEBUG_WITH_TYPE("WriterYAML",
138                         llvm::dbgs() << "name collsion: creating ref-name: '"
139                                      << newName2 << "' ("
140                                      << (const void *)newName2.data() << ", "
141                                      << newName2.size() << ")\n");
142       }
143     } else {
144       // First time we've seen this name, just add it to map.
145       _nameMap[atom.name()] = &atom;
146       DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
147                                         << "atom name seen for first time: '"
148                                         << atom.name() << "' ("
149                                         << (const void *)atom.name().data()
150                                         << ", " << atom.name().size() << ")\n");
151     }
152   }
153
154   bool hasRefName(const lld::Atom *atom) { return _refNames.count(atom); }
155
156   StringRef refName(const lld::Atom *atom) {
157     return _refNames.find(atom)->second;
158   }
159
160 private:
161   typedef llvm::StringMap<const lld::Atom *> NameToAtom;
162   typedef llvm::DenseMap<const lld::Atom *, std::string> AtomToRefName;
163
164   // Allocate a new copy of this string in _storage, so the strings
165   // can be freed when RefNameBuilder is destroyed.
166   StringRef copyString(StringRef str) {
167     char *s = _storage.Allocate<char>(str.size());
168     memcpy(s, str.data(), str.size());
169     return StringRef(s, str.size());
170   }
171
172   unsigned int                         _collisionCount;
173   unsigned int                         _unnamedCounter;
174   NameToAtom                           _nameMap;
175   AtomToRefName                        _refNames;
176   llvm::BumpPtrAllocator               _storage;
177 };
178
179 /// Used when reading yaml files to find the target of a reference
180 /// that could be a name or ref-name.
181 class RefNameResolver {
182 public:
183   RefNameResolver(const lld::File *file, IO &io);
184
185   const lld::Atom *lookup(StringRef name) const {
186     NameToAtom::const_iterator pos = _nameMap.find(name);
187     if (pos != _nameMap.end())
188       return pos->second;
189     _io.setError(Twine("no such atom name: ") + name);
190     return nullptr;
191   }
192
193 private:
194   typedef llvm::StringMap<const lld::Atom *> NameToAtom;
195
196   void add(StringRef name, const lld::Atom *atom) {
197     if (_nameMap.count(name)) {
198       _io.setError(Twine("duplicate atom name: ") + name);
199     } else {
200       _nameMap[name] = atom;
201     }
202   }
203
204   IO &_io;
205   NameToAtom _nameMap;
206 };
207
208 /// Mapping of Atoms.
209 template <typename T> class AtomList {
210   using Ty = std::vector<OwningAtomPtr<T>>;
211
212 public:
213   typename Ty::iterator begin() { return _atoms.begin(); }
214   typename Ty::iterator end() { return _atoms.end(); }
215   Ty _atoms;
216 };
217
218 /// Mapping of kind: field in yaml files.
219 enum FileKinds {
220   fileKindObjectAtoms, // atom based object file encoded in yaml
221   fileKindArchive,     // static archive library encoded in yaml
222   fileKindObjectMachO  // mach-o object files encoded in yaml
223 };
224
225 struct ArchMember {
226   FileKinds         _kind;
227   StringRef         _name;
228   const lld::File  *_content;
229 };
230
231 // The content bytes in a DefinedAtom are just uint8_t but we want
232 // special formatting, so define a strong type.
233 LLVM_YAML_STRONG_TYPEDEF(uint8_t, ImplicitHex8)
234
235 // SharedLibraryAtoms have a bool canBeNull() method which we'd like to be
236 // more readable than just true/false.
237 LLVM_YAML_STRONG_TYPEDEF(bool, ShlibCanBeNull)
238
239 // lld::Reference::Kind is a tuple of <namespace, arch, value>.
240 // For yaml, we just want one string that encapsulates the tuple.
241 struct RefKind {
242   Reference::KindNamespace  ns;
243   Reference::KindArch       arch;
244   Reference::KindValue      value;
245 };
246
247 } // end anonymous namespace
248
249 LLVM_YAML_IS_SEQUENCE_VECTOR(ArchMember)
250 LLVM_YAML_IS_SEQUENCE_VECTOR(const lld::Reference *)
251 // Always write DefinedAtoms content bytes as a flow sequence.
252 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(ImplicitHex8)
253
254 // for compatibility with gcc-4.7 in C++11 mode, add extra namespace
255 namespace llvm {
256 namespace yaml {
257
258 // This is a custom formatter for RefKind
259 template <> struct ScalarTraits<RefKind> {
260   static void output(const RefKind &kind, void *ctxt, raw_ostream &out) {
261     assert(ctxt != nullptr);
262     YamlContext *info = reinterpret_cast<YamlContext *>(ctxt);
263     assert(info->_registry);
264     StringRef str;
265     if (info->_registry->referenceKindToString(kind.ns, kind.arch, kind.value,
266                                                str))
267       out << str;
268     else
269       out << (int)(kind.ns) << "-" << (int)(kind.arch) << "-" << kind.value;
270   }
271
272   static StringRef input(StringRef scalar, void *ctxt, RefKind &kind) {
273     assert(ctxt != nullptr);
274     YamlContext *info = reinterpret_cast<YamlContext *>(ctxt);
275     assert(info->_registry);
276     if (info->_registry->referenceKindFromString(scalar, kind.ns, kind.arch,
277                                                  kind.value))
278       return StringRef();
279     return StringRef("unknown reference kind");
280   }
281
282   static QuotingType mustQuote(StringRef) { return QuotingType::None; }
283 };
284
285 template <> struct ScalarEnumerationTraits<lld::File::Kind> {
286   static void enumeration(IO &io, lld::File::Kind &value) {
287     io.enumCase(value, "error-object",   lld::File::kindErrorObject);
288     io.enumCase(value, "object",         lld::File::kindMachObject);
289     io.enumCase(value, "shared-library", lld::File::kindSharedLibrary);
290     io.enumCase(value, "static-library", lld::File::kindArchiveLibrary);
291   }
292 };
293
294 template <> struct ScalarEnumerationTraits<lld::Atom::Scope> {
295   static void enumeration(IO &io, lld::Atom::Scope &value) {
296     io.enumCase(value, "global", lld::Atom::scopeGlobal);
297     io.enumCase(value, "hidden", lld::Atom::scopeLinkageUnit);
298     io.enumCase(value, "static", lld::Atom::scopeTranslationUnit);
299   }
300 };
301
302 template <> struct ScalarEnumerationTraits<lld::DefinedAtom::SectionChoice> {
303   static void enumeration(IO &io, lld::DefinedAtom::SectionChoice &value) {
304     io.enumCase(value, "content", lld::DefinedAtom::sectionBasedOnContent);
305     io.enumCase(value, "custom",  lld::DefinedAtom::sectionCustomPreferred);
306     io.enumCase(value, "custom-required",
307                                  lld::DefinedAtom::sectionCustomRequired);
308   }
309 };
310
311 template <> struct ScalarEnumerationTraits<lld::DefinedAtom::Interposable> {
312   static void enumeration(IO &io, lld::DefinedAtom::Interposable &value) {
313     io.enumCase(value, "no",           DefinedAtom::interposeNo);
314     io.enumCase(value, "yes",          DefinedAtom::interposeYes);
315     io.enumCase(value, "yes-and-weak", DefinedAtom::interposeYesAndRuntimeWeak);
316   }
317 };
318
319 template <> struct ScalarEnumerationTraits<lld::DefinedAtom::Merge> {
320   static void enumeration(IO &io, lld::DefinedAtom::Merge &value) {
321     io.enumCase(value, "no",           lld::DefinedAtom::mergeNo);
322     io.enumCase(value, "as-tentative", lld::DefinedAtom::mergeAsTentative);
323     io.enumCase(value, "as-weak",      lld::DefinedAtom::mergeAsWeak);
324     io.enumCase(value, "as-addressed-weak",
325                                    lld::DefinedAtom::mergeAsWeakAndAddressUsed);
326     io.enumCase(value, "by-content",   lld::DefinedAtom::mergeByContent);
327     io.enumCase(value, "same-name-and-size",
328                 lld::DefinedAtom::mergeSameNameAndSize);
329     io.enumCase(value, "largest", lld::DefinedAtom::mergeByLargestSection);
330   }
331 };
332
333 template <> struct ScalarEnumerationTraits<lld::DefinedAtom::DeadStripKind> {
334   static void enumeration(IO &io, lld::DefinedAtom::DeadStripKind &value) {
335     io.enumCase(value, "normal", lld::DefinedAtom::deadStripNormal);
336     io.enumCase(value, "never",  lld::DefinedAtom::deadStripNever);
337     io.enumCase(value, "always", lld::DefinedAtom::deadStripAlways);
338   }
339 };
340
341 template <> struct ScalarEnumerationTraits<lld::DefinedAtom::DynamicExport> {
342   static void enumeration(IO &io, lld::DefinedAtom::DynamicExport &value) {
343     io.enumCase(value, "normal", lld::DefinedAtom::dynamicExportNormal);
344     io.enumCase(value, "always", lld::DefinedAtom::dynamicExportAlways);
345   }
346 };
347
348 template <> struct ScalarEnumerationTraits<lld::DefinedAtom::CodeModel> {
349   static void enumeration(IO &io, lld::DefinedAtom::CodeModel &value) {
350     io.enumCase(value, "none", lld::DefinedAtom::codeNA);
351     io.enumCase(value, "mips-pic", lld::DefinedAtom::codeMipsPIC);
352     io.enumCase(value, "mips-micro", lld::DefinedAtom::codeMipsMicro);
353     io.enumCase(value, "mips-micro-pic", lld::DefinedAtom::codeMipsMicroPIC);
354     io.enumCase(value, "mips-16", lld::DefinedAtom::codeMips16);
355     io.enumCase(value, "arm-thumb", lld::DefinedAtom::codeARMThumb);
356     io.enumCase(value, "arm-a", lld::DefinedAtom::codeARM_a);
357     io.enumCase(value, "arm-d", lld::DefinedAtom::codeARM_d);
358     io.enumCase(value, "arm-t", lld::DefinedAtom::codeARM_t);
359   }
360 };
361
362 template <>
363 struct ScalarEnumerationTraits<lld::DefinedAtom::ContentPermissions> {
364   static void enumeration(IO &io, lld::DefinedAtom::ContentPermissions &value) {
365     io.enumCase(value, "---",     lld::DefinedAtom::perm___);
366     io.enumCase(value, "r--",     lld::DefinedAtom::permR__);
367     io.enumCase(value, "r-x",     lld::DefinedAtom::permR_X);
368     io.enumCase(value, "rw-",     lld::DefinedAtom::permRW_);
369     io.enumCase(value, "rwx",     lld::DefinedAtom::permRWX);
370     io.enumCase(value, "rw-l",    lld::DefinedAtom::permRW_L);
371     io.enumCase(value, "unknown", lld::DefinedAtom::permUnknown);
372   }
373 };
374
375 template <> struct ScalarEnumerationTraits<lld::DefinedAtom::ContentType> {
376   static void enumeration(IO &io, lld::DefinedAtom::ContentType &value) {
377     io.enumCase(value, "unknown",         DefinedAtom::typeUnknown);
378     io.enumCase(value, "code",            DefinedAtom::typeCode);
379     io.enumCase(value, "stub",            DefinedAtom::typeStub);
380     io.enumCase(value, "constant",        DefinedAtom::typeConstant);
381     io.enumCase(value, "data",            DefinedAtom::typeData);
382     io.enumCase(value, "quick-data",      DefinedAtom::typeDataFast);
383     io.enumCase(value, "zero-fill",       DefinedAtom::typeZeroFill);
384     io.enumCase(value, "zero-fill-quick", DefinedAtom::typeZeroFillFast);
385     io.enumCase(value, "const-data",      DefinedAtom::typeConstData);
386     io.enumCase(value, "got",             DefinedAtom::typeGOT);
387     io.enumCase(value, "resolver",        DefinedAtom::typeResolver);
388     io.enumCase(value, "branch-island",   DefinedAtom::typeBranchIsland);
389     io.enumCase(value, "branch-shim",     DefinedAtom::typeBranchShim);
390     io.enumCase(value, "stub-helper",     DefinedAtom::typeStubHelper);
391     io.enumCase(value, "c-string",        DefinedAtom::typeCString);
392     io.enumCase(value, "utf16-string",    DefinedAtom::typeUTF16String);
393     io.enumCase(value, "unwind-cfi",      DefinedAtom::typeCFI);
394     io.enumCase(value, "unwind-lsda",     DefinedAtom::typeLSDA);
395     io.enumCase(value, "const-4-byte",    DefinedAtom::typeLiteral4);
396     io.enumCase(value, "const-8-byte",    DefinedAtom::typeLiteral8);
397     io.enumCase(value, "const-16-byte",   DefinedAtom::typeLiteral16);
398     io.enumCase(value, "lazy-pointer",    DefinedAtom::typeLazyPointer);
399     io.enumCase(value, "lazy-dylib-pointer",
400                                           DefinedAtom::typeLazyDylibPointer);
401     io.enumCase(value, "cfstring",        DefinedAtom::typeCFString);
402     io.enumCase(value, "initializer-pointer",
403                                           DefinedAtom::typeInitializerPtr);
404     io.enumCase(value, "terminator-pointer",
405                                           DefinedAtom::typeTerminatorPtr);
406     io.enumCase(value, "c-string-pointer",DefinedAtom::typeCStringPtr);
407     io.enumCase(value, "objc-class-pointer",
408                                           DefinedAtom::typeObjCClassPtr);
409     io.enumCase(value, "objc-category-list",
410                                           DefinedAtom::typeObjC2CategoryList);
411     io.enumCase(value, "objc-image-info",
412                                           DefinedAtom::typeObjCImageInfo);
413     io.enumCase(value, "objc-method-list",
414                                           DefinedAtom::typeObjCMethodList);
415     io.enumCase(value, "objc-class1",     DefinedAtom::typeObjC1Class);
416     io.enumCase(value, "dtraceDOF",       DefinedAtom::typeDTraceDOF);
417     io.enumCase(value, "interposing-tuples",
418                                           DefinedAtom::typeInterposingTuples);
419     io.enumCase(value, "lto-temp",        DefinedAtom::typeTempLTO);
420     io.enumCase(value, "compact-unwind",  DefinedAtom::typeCompactUnwindInfo);
421     io.enumCase(value, "unwind-info",     DefinedAtom::typeProcessedUnwindInfo);
422     io.enumCase(value, "tlv-thunk",       DefinedAtom::typeThunkTLV);
423     io.enumCase(value, "tlv-data",        DefinedAtom::typeTLVInitialData);
424     io.enumCase(value, "tlv-zero-fill",   DefinedAtom::typeTLVInitialZeroFill);
425     io.enumCase(value, "tlv-initializer-ptr",
426                                           DefinedAtom::typeTLVInitializerPtr);
427     io.enumCase(value, "mach_header",     DefinedAtom::typeMachHeader);
428     io.enumCase(value, "dso_handle",      DefinedAtom::typeDSOHandle);
429     io.enumCase(value, "sectcreate",      DefinedAtom::typeSectCreate);
430   }
431 };
432
433 template <> struct ScalarEnumerationTraits<lld::UndefinedAtom::CanBeNull> {
434   static void enumeration(IO &io, lld::UndefinedAtom::CanBeNull &value) {
435     io.enumCase(value, "never",       lld::UndefinedAtom::canBeNullNever);
436     io.enumCase(value, "at-runtime",  lld::UndefinedAtom::canBeNullAtRuntime);
437     io.enumCase(value, "at-buildtime",lld::UndefinedAtom::canBeNullAtBuildtime);
438   }
439 };
440
441 template <> struct ScalarEnumerationTraits<ShlibCanBeNull> {
442   static void enumeration(IO &io, ShlibCanBeNull &value) {
443     io.enumCase(value, "never",      false);
444     io.enumCase(value, "at-runtime", true);
445   }
446 };
447
448 template <>
449 struct ScalarEnumerationTraits<lld::SharedLibraryAtom::Type> {
450   static void enumeration(IO &io, lld::SharedLibraryAtom::Type &value) {
451     io.enumCase(value, "code",    lld::SharedLibraryAtom::Type::Code);
452     io.enumCase(value, "data",    lld::SharedLibraryAtom::Type::Data);
453     io.enumCase(value, "unknown", lld::SharedLibraryAtom::Type::Unknown);
454   }
455 };
456
457 /// This is a custom formatter for lld::DefinedAtom::Alignment.  Values look
458 /// like:
459 ///     8           # 8-byte aligned
460 ///     7 mod 16    # 16-byte aligned plus 7 bytes
461 template <> struct ScalarTraits<lld::DefinedAtom::Alignment> {
462   static void output(const lld::DefinedAtom::Alignment &value, void *ctxt,
463                      raw_ostream &out) {
464     if (value.modulus == 0) {
465       out << llvm::format("%d", value.value);
466     } else {
467       out << llvm::format("%d mod %d", value.modulus, value.value);
468     }
469   }
470
471   static StringRef input(StringRef scalar, void *ctxt,
472                          lld::DefinedAtom::Alignment &value) {
473     value.modulus = 0;
474     size_t modStart = scalar.find("mod");
475     if (modStart != StringRef::npos) {
476       StringRef modStr = scalar.slice(0, modStart);
477       modStr = modStr.rtrim();
478       unsigned int modulus;
479       if (modStr.getAsInteger(0, modulus)) {
480         return "malformed alignment modulus";
481       }
482       value.modulus = modulus;
483       scalar = scalar.drop_front(modStart + 3);
484       scalar = scalar.ltrim();
485     }
486     unsigned int power;
487     if (scalar.getAsInteger(0, power)) {
488       return "malformed alignment power";
489     }
490     value.value = power;
491     if (value.modulus >= power) {
492       return "malformed alignment, modulus too large for power";
493     }
494     return StringRef(); // returning empty string means success
495   }
496
497   static QuotingType mustQuote(StringRef) { return QuotingType::None; }
498 };
499
500 template <> struct ScalarEnumerationTraits<FileKinds> {
501   static void enumeration(IO &io, FileKinds &value) {
502     io.enumCase(value, "object",        fileKindObjectAtoms);
503     io.enumCase(value, "archive",       fileKindArchive);
504     io.enumCase(value, "object-mach-o", fileKindObjectMachO);
505   }
506 };
507
508 template <> struct MappingTraits<ArchMember> {
509   static void mapping(IO &io, ArchMember &member) {
510     io.mapOptional("kind",    member._kind, fileKindObjectAtoms);
511     io.mapOptional("name",    member._name);
512     io.mapRequired("content", member._content);
513   }
514 };
515
516 // Declare that an AtomList is a yaml sequence.
517 template <typename T> struct SequenceTraits<AtomList<T> > {
518   static size_t size(IO &io, AtomList<T> &seq) { return seq._atoms.size(); }
519   static T *&element(IO &io, AtomList<T> &seq, size_t index) {
520     if (index >= seq._atoms.size())
521       seq._atoms.resize(index + 1);
522     return seq._atoms[index].get();
523   }
524 };
525
526 // Declare that an AtomRange is a yaml sequence.
527 template <typename T> struct SequenceTraits<File::AtomRange<T> > {
528   static size_t size(IO &io, File::AtomRange<T> &seq) { return seq.size(); }
529   static T *&element(IO &io, File::AtomRange<T> &seq, size_t index) {
530     assert(io.outputting() && "AtomRange only used when outputting");
531     assert(index < seq.size() && "Out of range access");
532     return seq[index].get();
533   }
534 };
535
536 // Used to allow DefinedAtom content bytes to be a flow sequence of
537 // two-digit hex numbers without the leading 0x (e.g. FF, 04, 0A)
538 template <> struct ScalarTraits<ImplicitHex8> {
539   static void output(const ImplicitHex8 &val, void *, raw_ostream &out) {
540     uint8_t num = val;
541     out << llvm::format("%02X", num);
542   }
543
544   static StringRef input(StringRef str, void *, ImplicitHex8 &val) {
545     unsigned long long n;
546     if (getAsUnsignedInteger(str, 16, n))
547       return "invalid two-digit-hex number";
548     if (n > 0xFF)
549       return "out of range two-digit-hex number";
550     val = n;
551     return StringRef(); // returning empty string means success
552   }
553
554   static QuotingType mustQuote(StringRef) { return QuotingType::None; }
555 };
556
557 // YAML conversion for std::vector<const lld::File*>
558 template <> struct DocumentListTraits<std::vector<const lld::File *> > {
559   static size_t size(IO &io, std::vector<const lld::File *> &seq) {
560     return seq.size();
561   }
562   static const lld::File *&element(IO &io, std::vector<const lld::File *> &seq,
563                                    size_t index) {
564     if (index >= seq.size())
565       seq.resize(index + 1);
566     return seq[index];
567   }
568 };
569
570 // YAML conversion for const lld::File*
571 template <> struct MappingTraits<const lld::File *> {
572   class NormArchiveFile : public lld::ArchiveLibraryFile {
573   public:
574     NormArchiveFile(IO &io) : ArchiveLibraryFile("") {}
575
576     NormArchiveFile(IO &io, const lld::File *file)
577         : ArchiveLibraryFile(file->path()), _path(file->path()) {
578       // If we want to support writing archives, this constructor would
579       // need to populate _members.
580     }
581
582     const lld::File *denormalize(IO &io) { return this; }
583
584     const AtomRange<lld::DefinedAtom> defined() const override {
585       return _noDefinedAtoms;
586     }
587
588     const AtomRange<lld::UndefinedAtom> undefined() const override {
589       return _noUndefinedAtoms;
590     }
591
592     const AtomRange<lld::SharedLibraryAtom> sharedLibrary() const override {
593       return _noSharedLibraryAtoms;
594     }
595
596     const AtomRange<lld::AbsoluteAtom> absolute() const override {
597       return _noAbsoluteAtoms;
598     }
599
600     void clearAtoms() override {
601       _noDefinedAtoms.clear();
602       _noUndefinedAtoms.clear();
603       _noSharedLibraryAtoms.clear();
604       _noAbsoluteAtoms.clear();
605     }
606
607     File *find(StringRef name) override {
608       for (const ArchMember &member : _members)
609         for (const lld::DefinedAtom *atom : member._content->defined())
610           if (name == atom->name())
611             return const_cast<File *>(member._content);
612       return nullptr;
613     }
614
615     std::error_code
616     parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
617       return std::error_code();
618     }
619
620     StringRef               _path;
621     std::vector<ArchMember> _members;
622   };
623
624   class NormalizedFile : public lld::File {
625   public:
626     NormalizedFile(IO &io)
627       : File("", kindNormalizedObject), _io(io), _rnb(nullptr),
628         _definedAtomsRef(_definedAtoms._atoms),
629         _undefinedAtomsRef(_undefinedAtoms._atoms),
630         _sharedLibraryAtomsRef(_sharedLibraryAtoms._atoms),
631         _absoluteAtomsRef(_absoluteAtoms._atoms) {}
632
633     NormalizedFile(IO &io, const lld::File *file)
634         : File(file->path(), kindNormalizedObject), _io(io),
635           _rnb(new RefNameBuilder(*file)), _path(file->path()),
636         _definedAtomsRef(file->defined()),
637         _undefinedAtomsRef(file->undefined()),
638         _sharedLibraryAtomsRef(file->sharedLibrary()),
639         _absoluteAtomsRef(file->absolute()) {
640     }
641
642     ~NormalizedFile() override {
643     }
644
645     const lld::File *denormalize(IO &io);
646
647     const AtomRange<lld::DefinedAtom> defined() const override {
648       return _definedAtomsRef;
649     }
650
651     const AtomRange<lld::UndefinedAtom> undefined() const override {
652       return _undefinedAtomsRef;
653     }
654
655     const AtomRange<lld::SharedLibraryAtom> sharedLibrary() const override {
656       return _sharedLibraryAtomsRef;
657     }
658
659     const AtomRange<lld::AbsoluteAtom> absolute() const override {
660       return _absoluteAtomsRef;
661     }
662
663     void clearAtoms() override {
664       _definedAtoms._atoms.clear();
665       _undefinedAtoms._atoms.clear();
666       _sharedLibraryAtoms._atoms.clear();
667       _absoluteAtoms._atoms.clear();
668     }
669
670     // Allocate a new copy of this string in _storage, so the strings
671     // can be freed when File is destroyed.
672     StringRef copyString(StringRef str) {
673       char *s = _storage.Allocate<char>(str.size());
674       memcpy(s, str.data(), str.size());
675       return StringRef(s, str.size());
676     }
677
678     IO                                  &_io;
679     std::unique_ptr<RefNameBuilder>      _rnb;
680     StringRef                            _path;
681     AtomList<lld::DefinedAtom>           _definedAtoms;
682     AtomList<lld::UndefinedAtom>         _undefinedAtoms;
683     AtomList<lld::SharedLibraryAtom>     _sharedLibraryAtoms;
684     AtomList<lld::AbsoluteAtom>          _absoluteAtoms;
685     AtomRange<lld::DefinedAtom>          _definedAtomsRef;
686     AtomRange<lld::UndefinedAtom>        _undefinedAtomsRef;
687     AtomRange<lld::SharedLibraryAtom>    _sharedLibraryAtomsRef;
688     AtomRange<lld::AbsoluteAtom>         _absoluteAtomsRef;
689     llvm::BumpPtrAllocator               _storage;
690   };
691
692   static void mapping(IO &io, const lld::File *&file) {
693     YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
694     assert(info != nullptr);
695     // Let any register tag handler process this.
696     if (info->_registry && info->_registry->handleTaggedDoc(io, file))
697       return;
698     // If no registered handler claims this tag and there is no tag,
699     // grandfather in as "!native".
700     if (io.mapTag("!native", true) || io.mapTag("tag:yaml.org,2002:map"))
701       mappingAtoms(io, file);
702   }
703
704   static void mappingAtoms(IO &io, const lld::File *&file) {
705     YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
706     MappingNormalizationHeap<NormalizedFile, const lld::File *>
707       keys(io, file, nullptr);
708     assert(info != nullptr);
709     info->_file = keys.operator->();
710
711     io.mapOptional("path",                 keys->_path);
712
713     if (io.outputting()) {
714       io.mapOptional("defined-atoms",        keys->_definedAtomsRef);
715       io.mapOptional("undefined-atoms",      keys->_undefinedAtomsRef);
716       io.mapOptional("shared-library-atoms", keys->_sharedLibraryAtomsRef);
717       io.mapOptional("absolute-atoms",       keys->_absoluteAtomsRef);
718     } else {
719       io.mapOptional("defined-atoms",        keys->_definedAtoms);
720       io.mapOptional("undefined-atoms",      keys->_undefinedAtoms);
721       io.mapOptional("shared-library-atoms", keys->_sharedLibraryAtoms);
722       io.mapOptional("absolute-atoms",       keys->_absoluteAtoms);
723     }
724   }
725
726   static void mappingArchive(IO &io, const lld::File *&file) {
727     YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
728     MappingNormalizationHeap<NormArchiveFile, const lld::File *>
729       keys(io, file, &info->_file->allocator());
730
731     io.mapOptional("path",    keys->_path);
732     io.mapOptional("members", keys->_members);
733   }
734 };
735
736 // YAML conversion for const lld::Reference*
737 template <> struct MappingTraits<const lld::Reference *> {
738   class NormalizedReference : public lld::Reference {
739   public:
740     NormalizedReference(IO &io)
741         : lld::Reference(lld::Reference::KindNamespace::all,
742                          lld::Reference::KindArch::all, 0),
743           _target(nullptr), _offset(0), _addend(0), _tag(0) {}
744
745     NormalizedReference(IO &io, const lld::Reference *ref)
746         : lld::Reference(ref->kindNamespace(), ref->kindArch(),
747                          ref->kindValue()),
748           _target(nullptr), _targetName(targetName(io, ref)),
749           _offset(ref->offsetInAtom()), _addend(ref->addend()),
750           _tag(ref->tag()) {
751       _mappedKind.ns = ref->kindNamespace();
752       _mappedKind.arch = ref->kindArch();
753       _mappedKind.value = ref->kindValue();
754     }
755
756     const lld::Reference *denormalize(IO &io) {
757       YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
758       assert(info != nullptr);
759       typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
760       NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
761       if (!_targetName.empty())
762         _targetName = f->copyString(_targetName);
763       DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
764                                         << "created Reference to name: '"
765                                         << _targetName << "' ("
766                                         << (const void *)_targetName.data()
767                                         << ", " << _targetName.size() << ")\n");
768       setKindNamespace(_mappedKind.ns);
769       setKindArch(_mappedKind.arch);
770       setKindValue(_mappedKind.value);
771       return this;
772     }
773
774     void bind(const RefNameResolver &);
775     static StringRef targetName(IO &io, const lld::Reference *ref);
776
777     uint64_t offsetInAtom() const override { return _offset; }
778     const lld::Atom *target() const override { return _target; }
779     Addend addend() const override { return _addend; }
780     void setAddend(Addend a) override { _addend = a; }
781     void setTarget(const lld::Atom *a) override { _target = a; }
782
783     const lld::Atom *_target;
784     StringRef        _targetName;
785     uint32_t         _offset;
786     Addend           _addend;
787     RefKind          _mappedKind;
788     uint32_t         _tag;
789   };
790
791   static void mapping(IO &io, const lld::Reference *&ref) {
792     YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
793     MappingNormalizationHeap<NormalizedReference, const lld::Reference *> keys(
794         io, ref, &info->_file->allocator());
795
796     io.mapRequired("kind",   keys->_mappedKind);
797     io.mapOptional("offset", keys->_offset);
798     io.mapOptional("target", keys->_targetName);
799     io.mapOptional("addend", keys->_addend, (lld::Reference::Addend)0);
800     io.mapOptional("tag",    keys->_tag, 0u);
801   }
802 };
803
804 // YAML conversion for const lld::DefinedAtom*
805 template <> struct MappingTraits<const lld::DefinedAtom *> {
806
807   class NormalizedAtom : public lld::DefinedAtom {
808   public:
809     NormalizedAtom(IO &io)
810         : _file(fileFromContext(io)), _contentType(), _alignment(1) {
811       static uint32_t ordinalCounter = 1;
812       _ordinal = ordinalCounter++;
813     }
814
815     NormalizedAtom(IO &io, const lld::DefinedAtom *atom)
816         : _file(fileFromContext(io)), _name(atom->name()),
817           _scope(atom->scope()), _interpose(atom->interposable()),
818           _merge(atom->merge()), _contentType(atom->contentType()),
819           _alignment(atom->alignment()), _sectionChoice(atom->sectionChoice()),
820           _deadStrip(atom->deadStrip()), _dynamicExport(atom->dynamicExport()),
821           _codeModel(atom->codeModel()),
822           _permissions(atom->permissions()), _size(atom->size()),
823           _sectionName(atom->customSectionName()),
824           _sectionSize(atom->sectionSize()) {
825       for (const lld::Reference *r : *atom)
826         _references.push_back(r);
827       if (!atom->occupiesDiskSpace())
828         return;
829       ArrayRef<uint8_t> cont = atom->rawContent();
830       _content.reserve(cont.size());
831       for (uint8_t x : cont)
832         _content.push_back(x);
833     }
834
835     ~NormalizedAtom() override = default;
836
837     const lld::DefinedAtom *denormalize(IO &io) {
838       YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
839       assert(info != nullptr);
840       typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
841       NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
842       if (!_name.empty())
843         _name = f->copyString(_name);
844       if (!_refName.empty())
845         _refName = f->copyString(_refName);
846       if (!_sectionName.empty())
847         _sectionName = f->copyString(_sectionName);
848       DEBUG_WITH_TYPE("WriterYAML",
849                       llvm::dbgs() << "created DefinedAtom named: '" << _name
850                                    << "' (" << (const void *)_name.data()
851                                    << ", " << _name.size() << ")\n");
852       return this;
853     }
854
855     void bind(const RefNameResolver &);
856
857     // Extract current File object from YAML I/O parsing context
858     const lld::File &fileFromContext(IO &io) {
859       YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
860       assert(info != nullptr);
861       assert(info->_file != nullptr);
862       return *info->_file;
863     }
864
865     const lld::File &file() const override { return _file; }
866     StringRef name() const override { return _name; }
867     uint64_t size() const override { return _size; }
868     Scope scope() const override { return _scope; }
869     Interposable interposable() const override { return _interpose; }
870     Merge merge() const override { return _merge; }
871     ContentType contentType() const override { return _contentType; }
872     Alignment alignment() const override { return _alignment; }
873     SectionChoice sectionChoice() const override { return _sectionChoice; }
874     StringRef customSectionName() const override { return _sectionName; }
875     uint64_t sectionSize() const override { return _sectionSize; }
876     DeadStripKind deadStrip() const override { return _deadStrip; }
877     DynamicExport dynamicExport() const override { return _dynamicExport; }
878     CodeModel codeModel() const override { return _codeModel; }
879     ContentPermissions permissions() const override { return _permissions; }
880     ArrayRef<uint8_t> rawContent() const override {
881       if (!occupiesDiskSpace())
882         return ArrayRef<uint8_t>();
883       return ArrayRef<uint8_t>(
884           reinterpret_cast<const uint8_t *>(_content.data()), _content.size());
885     }
886
887     uint64_t ordinal() const override { return _ordinal; }
888
889     reference_iterator begin() const override {
890       uintptr_t index = 0;
891       const void *it = reinterpret_cast<const void *>(index);
892       return reference_iterator(*this, it);
893     }
894     reference_iterator end() const override {
895       uintptr_t index = _references.size();
896       const void *it = reinterpret_cast<const void *>(index);
897       return reference_iterator(*this, it);
898     }
899     const lld::Reference *derefIterator(const void *it) const override {
900       uintptr_t index = reinterpret_cast<uintptr_t>(it);
901       assert(index < _references.size());
902       return _references[index];
903     }
904     void incrementIterator(const void *&it) const override {
905       uintptr_t index = reinterpret_cast<uintptr_t>(it);
906       ++index;
907       it = reinterpret_cast<const void *>(index);
908     }
909
910     void addReference(Reference::KindNamespace ns,
911                       Reference::KindArch arch,
912                       Reference::KindValue kindValue, uint64_t off,
913                       const Atom *target, Reference::Addend a) override {
914       assert(target && "trying to create reference to nothing");
915       auto node = new (file().allocator()) SimpleReference(ns, arch, kindValue,
916                                                            off, target, a);
917       _references.push_back(node);
918     }
919
920     const lld::File                    &_file;
921     StringRef                           _name;
922     StringRef                           _refName;
923     Scope                               _scope;
924     Interposable                        _interpose;
925     Merge                               _merge;
926     ContentType                         _contentType;
927     Alignment                           _alignment;
928     SectionChoice                       _sectionChoice;
929     DeadStripKind                       _deadStrip;
930     DynamicExport                       _dynamicExport;
931     CodeModel                           _codeModel;
932     ContentPermissions                  _permissions;
933     uint32_t                            _ordinal;
934     std::vector<ImplicitHex8>           _content;
935     uint64_t                            _size;
936     StringRef                           _sectionName;
937     uint64_t                            _sectionSize;
938     std::vector<const lld::Reference *> _references;
939   };
940
941   static void mapping(IO &io, const lld::DefinedAtom *&atom) {
942     YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
943     MappingNormalizationHeap<NormalizedAtom, const lld::DefinedAtom *> keys(
944         io, atom, &info->_file->allocator());
945     if (io.outputting()) {
946       // If writing YAML, check if atom needs a ref-name.
947       typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
948       assert(info != nullptr);
949       NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
950       assert(f);
951       assert(f->_rnb);
952       if (f->_rnb->hasRefName(atom)) {
953         keys->_refName = f->_rnb->refName(atom);
954       }
955     }
956
957     io.mapOptional("name",             keys->_name,    StringRef());
958     io.mapOptional("ref-name",         keys->_refName, StringRef());
959     io.mapOptional("scope",            keys->_scope,
960                                          DefinedAtom::scopeTranslationUnit);
961     io.mapOptional("type",             keys->_contentType,
962                                          DefinedAtom::typeCode);
963     io.mapOptional("content",          keys->_content);
964     io.mapOptional("size",             keys->_size, (uint64_t)keys->_content.size());
965     io.mapOptional("interposable",     keys->_interpose,
966                                          DefinedAtom::interposeNo);
967     io.mapOptional("merge",            keys->_merge, DefinedAtom::mergeNo);
968     io.mapOptional("alignment",        keys->_alignment,
969                                          DefinedAtom::Alignment(1));
970     io.mapOptional("section-choice",   keys->_sectionChoice,
971                                          DefinedAtom::sectionBasedOnContent);
972     io.mapOptional("section-name",     keys->_sectionName, StringRef());
973     io.mapOptional("section-size",     keys->_sectionSize, (uint64_t)0);
974     io.mapOptional("dead-strip",       keys->_deadStrip,
975                                          DefinedAtom::deadStripNormal);
976     io.mapOptional("dynamic-export",   keys->_dynamicExport,
977                                          DefinedAtom::dynamicExportNormal);
978     io.mapOptional("code-model",       keys->_codeModel, DefinedAtom::codeNA);
979     // default permissions based on content type
980     io.mapOptional("permissions",      keys->_permissions,
981                                          DefinedAtom::permissions(
982                                                           keys->_contentType));
983     io.mapOptional("references",       keys->_references);
984   }
985 };
986
987 template <> struct MappingTraits<lld::DefinedAtom *> {
988   static void mapping(IO &io, lld::DefinedAtom *&atom) {
989     const lld::DefinedAtom *atomPtr = atom;
990     MappingTraits<const lld::DefinedAtom *>::mapping(io, atomPtr);
991     atom = const_cast<lld::DefinedAtom *>(atomPtr);
992   }
993 };
994
995 // YAML conversion for const lld::UndefinedAtom*
996 template <> struct MappingTraits<const lld::UndefinedAtom *> {
997   class NormalizedAtom : public lld::UndefinedAtom {
998   public:
999     NormalizedAtom(IO &io)
1000         : _file(fileFromContext(io)), _canBeNull(canBeNullNever) {}
1001
1002     NormalizedAtom(IO &io, const lld::UndefinedAtom *atom)
1003         : _file(fileFromContext(io)), _name(atom->name()),
1004           _canBeNull(atom->canBeNull()) {}
1005
1006     ~NormalizedAtom() override = default;
1007
1008     const lld::UndefinedAtom *denormalize(IO &io) {
1009       YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
1010       assert(info != nullptr);
1011       typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
1012       NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
1013       if (!_name.empty())
1014         _name = f->copyString(_name);
1015
1016       DEBUG_WITH_TYPE("WriterYAML",
1017                       llvm::dbgs() << "created UndefinedAtom named: '" << _name
1018                       << "' (" << (const void *)_name.data() << ", "
1019                       << _name.size() << ")\n");
1020       return this;
1021     }
1022
1023     // Extract current File object from YAML I/O parsing context
1024     const lld::File &fileFromContext(IO &io) {
1025       YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
1026       assert(info != nullptr);
1027       assert(info->_file != nullptr);
1028       return *info->_file;
1029     }
1030
1031     const lld::File &file() const override { return _file; }
1032     StringRef name() const override { return _name; }
1033     CanBeNull canBeNull() const override { return _canBeNull; }
1034
1035     const lld::File     &_file;
1036     StringRef            _name;
1037     CanBeNull            _canBeNull;
1038   };
1039
1040   static void mapping(IO &io, const lld::UndefinedAtom *&atom) {
1041     YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
1042     MappingNormalizationHeap<NormalizedAtom, const lld::UndefinedAtom *> keys(
1043         io, atom, &info->_file->allocator());
1044
1045     io.mapRequired("name",        keys->_name);
1046     io.mapOptional("can-be-null", keys->_canBeNull,
1047                                   lld::UndefinedAtom::canBeNullNever);
1048   }
1049 };
1050
1051 template <> struct MappingTraits<lld::UndefinedAtom *> {
1052   static void mapping(IO &io, lld::UndefinedAtom *&atom) {
1053     const lld::UndefinedAtom *atomPtr = atom;
1054     MappingTraits<const lld::UndefinedAtom *>::mapping(io, atomPtr);
1055     atom = const_cast<lld::UndefinedAtom *>(atomPtr);
1056   }
1057 };
1058
1059 // YAML conversion for const lld::SharedLibraryAtom*
1060 template <> struct MappingTraits<const lld::SharedLibraryAtom *> {
1061   class NormalizedAtom : public lld::SharedLibraryAtom {
1062   public:
1063     NormalizedAtom(IO &io)
1064         : _file(fileFromContext(io)), _canBeNull(false),
1065           _type(Type::Unknown), _size(0) {}
1066
1067     NormalizedAtom(IO &io, const lld::SharedLibraryAtom *atom)
1068         : _file(fileFromContext(io)), _name(atom->name()),
1069           _loadName(atom->loadName()), _canBeNull(atom->canBeNullAtRuntime()),
1070           _type(atom->type()), _size(atom->size()) {}
1071
1072     ~NormalizedAtom() override = default;
1073
1074     const lld::SharedLibraryAtom *denormalize(IO &io) {
1075       YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
1076       assert(info != nullptr);
1077       typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
1078       NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
1079       if (!_name.empty())
1080         _name = f->copyString(_name);
1081       if (!_loadName.empty())
1082         _loadName = f->copyString(_loadName);
1083
1084       DEBUG_WITH_TYPE("WriterYAML",
1085                       llvm::dbgs() << "created SharedLibraryAtom named: '"
1086                                    << _name << "' ("
1087                                    << (const void *)_name.data()
1088                                    << ", " << _name.size() << ")\n");
1089       return this;
1090     }
1091
1092     // Extract current File object from YAML I/O parsing context
1093     const lld::File &fileFromContext(IO &io) {
1094       YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
1095       assert(info != nullptr);
1096       assert(info->_file != nullptr);
1097       return *info->_file;
1098     }
1099
1100     const lld::File &file() const override { return _file; }
1101     StringRef name() const override { return _name; }
1102     StringRef loadName() const override { return _loadName; }
1103     bool canBeNullAtRuntime() const override { return _canBeNull; }
1104     Type type() const override { return _type; }
1105     uint64_t size() const override { return _size; }
1106
1107     const lld::File &_file;
1108     StringRef        _name;
1109     StringRef        _loadName;
1110     ShlibCanBeNull   _canBeNull;
1111     Type             _type;
1112     uint64_t         _size;
1113   };
1114
1115   static void mapping(IO &io, const lld::SharedLibraryAtom *&atom) {
1116
1117     YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
1118     MappingNormalizationHeap<NormalizedAtom, const lld::SharedLibraryAtom *>
1119     keys(io, atom, &info->_file->allocator());
1120
1121     io.mapRequired("name",        keys->_name);
1122     io.mapOptional("load-name",   keys->_loadName);
1123     io.mapOptional("can-be-null", keys->_canBeNull, (ShlibCanBeNull) false);
1124     io.mapOptional("type",        keys->_type, SharedLibraryAtom::Type::Code);
1125     io.mapOptional("size",        keys->_size, uint64_t(0));
1126   }
1127 };
1128
1129 template <> struct MappingTraits<lld::SharedLibraryAtom *> {
1130   static void mapping(IO &io, lld::SharedLibraryAtom *&atom) {
1131     const lld::SharedLibraryAtom *atomPtr = atom;
1132     MappingTraits<const lld::SharedLibraryAtom *>::mapping(io, atomPtr);
1133     atom = const_cast<lld::SharedLibraryAtom *>(atomPtr);
1134   }
1135 };
1136
1137 // YAML conversion for const lld::AbsoluteAtom*
1138 template <> struct MappingTraits<const lld::AbsoluteAtom *> {
1139   class NormalizedAtom : public lld::AbsoluteAtom {
1140   public:
1141     NormalizedAtom(IO &io)
1142         : _file(fileFromContext(io)), _scope(), _value(0) {}
1143
1144     NormalizedAtom(IO &io, const lld::AbsoluteAtom *atom)
1145         : _file(fileFromContext(io)), _name(atom->name()),
1146           _scope(atom->scope()), _value(atom->value()) {}
1147
1148     ~NormalizedAtom() override = default;
1149
1150     const lld::AbsoluteAtom *denormalize(IO &io) {
1151       YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
1152       assert(info != nullptr);
1153       typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
1154       NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
1155       if (!_name.empty())
1156         _name = f->copyString(_name);
1157
1158       DEBUG_WITH_TYPE("WriterYAML",
1159                       llvm::dbgs() << "created AbsoluteAtom named: '" << _name
1160                                    << "' (" << (const void *)_name.data()
1161                                    << ", " << _name.size() << ")\n");
1162       return this;
1163     }
1164
1165     // Extract current File object from YAML I/O parsing context
1166     const lld::File &fileFromContext(IO &io) {
1167       YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
1168       assert(info != nullptr);
1169       assert(info->_file != nullptr);
1170       return *info->_file;
1171     }
1172
1173     const lld::File &file() const override { return _file; }
1174     StringRef name() const override { return _name; }
1175     uint64_t value() const override { return _value; }
1176     Scope scope() const override { return _scope; }
1177
1178     const lld::File &_file;
1179     StringRef        _name;
1180     StringRef        _refName;
1181     Scope            _scope;
1182     Hex64            _value;
1183   };
1184
1185   static void mapping(IO &io, const lld::AbsoluteAtom *&atom) {
1186     YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
1187     MappingNormalizationHeap<NormalizedAtom, const lld::AbsoluteAtom *> keys(
1188         io, atom, &info->_file->allocator());
1189
1190     if (io.outputting()) {
1191       typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
1192       YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
1193       assert(info != nullptr);
1194       NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
1195       assert(f);
1196       assert(f->_rnb);
1197       if (f->_rnb->hasRefName(atom)) {
1198         keys->_refName = f->_rnb->refName(atom);
1199       }
1200     }
1201
1202     io.mapRequired("name",     keys->_name);
1203     io.mapOptional("ref-name", keys->_refName, StringRef());
1204     io.mapOptional("scope",    keys->_scope);
1205     io.mapRequired("value",    keys->_value);
1206   }
1207 };
1208
1209 template <> struct MappingTraits<lld::AbsoluteAtom *> {
1210   static void mapping(IO &io, lld::AbsoluteAtom *&atom) {
1211     const lld::AbsoluteAtom *atomPtr = atom;
1212     MappingTraits<const lld::AbsoluteAtom *>::mapping(io, atomPtr);
1213     atom = const_cast<lld::AbsoluteAtom *>(atomPtr);
1214   }
1215 };
1216
1217 } // end namespace llvm
1218 } // end namespace yaml
1219
1220 RefNameResolver::RefNameResolver(const lld::File *file, IO &io) : _io(io) {
1221   typedef MappingTraits<const lld::DefinedAtom *>::NormalizedAtom
1222   NormalizedAtom;
1223   for (const lld::DefinedAtom *a : file->defined()) {
1224     const auto *na = (const NormalizedAtom *)a;
1225     if (!na->_refName.empty())
1226       add(na->_refName, a);
1227     else if (!na->_name.empty())
1228       add(na->_name, a);
1229   }
1230
1231   for (const lld::UndefinedAtom *a : file->undefined())
1232     add(a->name(), a);
1233
1234   for (const lld::SharedLibraryAtom *a : file->sharedLibrary())
1235     add(a->name(), a);
1236
1237   typedef MappingTraits<const lld::AbsoluteAtom *>::NormalizedAtom NormAbsAtom;
1238   for (const lld::AbsoluteAtom *a : file->absolute()) {
1239     const auto *na = (const NormAbsAtom *)a;
1240     if (na->_refName.empty())
1241       add(na->_name, a);
1242     else
1243       add(na->_refName, a);
1244   }
1245 }
1246
1247 inline const lld::File *
1248 MappingTraits<const lld::File *>::NormalizedFile::denormalize(IO &io) {
1249   typedef MappingTraits<const lld::DefinedAtom *>::NormalizedAtom
1250   NormalizedAtom;
1251
1252   RefNameResolver nameResolver(this, io);
1253   // Now that all atoms are parsed, references can be bound.
1254   for (const lld::DefinedAtom *a : this->defined()) {
1255     auto *normAtom = (NormalizedAtom *)const_cast<DefinedAtom *>(a);
1256     normAtom->bind(nameResolver);
1257   }
1258
1259   return this;
1260 }
1261
1262 inline void MappingTraits<const lld::DefinedAtom *>::NormalizedAtom::bind(
1263     const RefNameResolver &resolver) {
1264   typedef MappingTraits<const lld::Reference *>::NormalizedReference
1265   NormalizedReference;
1266   for (const lld::Reference *ref : _references) {
1267     auto *normRef = (NormalizedReference *)const_cast<Reference *>(ref);
1268     normRef->bind(resolver);
1269   }
1270 }
1271
1272 inline void MappingTraits<const lld::Reference *>::NormalizedReference::bind(
1273     const RefNameResolver &resolver) {
1274   _target = resolver.lookup(_targetName);
1275 }
1276
1277 inline StringRef
1278 MappingTraits<const lld::Reference *>::NormalizedReference::targetName(
1279     IO &io, const lld::Reference *ref) {
1280   if (ref->target() == nullptr)
1281     return StringRef();
1282   YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
1283   assert(info != nullptr);
1284   typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
1285   NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
1286   RefNameBuilder &rnb = *f->_rnb;
1287   if (rnb.hasRefName(ref->target()))
1288     return rnb.refName(ref->target());
1289   return ref->target()->name();
1290 }
1291
1292 namespace lld {
1293 namespace yaml {
1294
1295 class Writer : public lld::Writer {
1296 public:
1297   Writer(const LinkingContext &context) : _ctx(context) {}
1298
1299   llvm::Error writeFile(const lld::File &file, StringRef outPath) override {
1300     // Create stream to path.
1301     std::error_code ec;
1302     llvm::raw_fd_ostream out(outPath, ec, llvm::sys::fs::F_Text);
1303     if (ec)
1304       return llvm::errorCodeToError(ec);
1305
1306     // Create yaml Output writer, using yaml options for context.
1307     YamlContext yamlContext;
1308     yamlContext._ctx = &_ctx;
1309     yamlContext._registry = &_ctx.registry();
1310     llvm::yaml::Output yout(out, &yamlContext);
1311
1312     // Write yaml output.
1313     const lld::File *fileRef = &file;
1314     yout << fileRef;
1315
1316     return llvm::Error::success();
1317   }
1318
1319 private:
1320   const LinkingContext &_ctx;
1321 };
1322
1323 } // end namespace yaml
1324
1325 namespace {
1326
1327 /// Handles !native tagged yaml documents.
1328 class NativeYamlIOTaggedDocumentHandler : public YamlIOTaggedDocumentHandler {
1329   bool handledDocTag(llvm::yaml::IO &io, const lld::File *&file) const override {
1330     if (io.mapTag("!native")) {
1331       MappingTraits<const lld::File *>::mappingAtoms(io, file);
1332       return true;
1333     }
1334     return false;
1335   }
1336 };
1337
1338 /// Handles !archive tagged yaml documents.
1339 class ArchiveYamlIOTaggedDocumentHandler : public YamlIOTaggedDocumentHandler {
1340   bool handledDocTag(llvm::yaml::IO &io, const lld::File *&file) const override {
1341     if (io.mapTag("!archive")) {
1342       MappingTraits<const lld::File *>::mappingArchive(io, file);
1343       return true;
1344     }
1345     return false;
1346   }
1347 };
1348
1349 class YAMLReader : public Reader {
1350 public:
1351   YAMLReader(const Registry &registry) : _registry(registry) {}
1352
1353   bool canParse(file_magic magic, MemoryBufferRef mb) const override {
1354     StringRef name = mb.getBufferIdentifier();
1355     return name.endswith(".objtxt") || name.endswith(".yaml");
1356   }
1357
1358   ErrorOr<std::unique_ptr<File>>
1359   loadFile(std::unique_ptr<MemoryBuffer> mb,
1360            const class Registry &) const override {
1361     // Create YAML Input Reader.
1362     YamlContext yamlContext;
1363     yamlContext._registry = &_registry;
1364     yamlContext._path = mb->getBufferIdentifier();
1365     llvm::yaml::Input yin(mb->getBuffer(), &yamlContext);
1366
1367     // Fill vector with File objects created by parsing yaml.
1368     std::vector<const lld::File *> createdFiles;
1369     yin >> createdFiles;
1370     assert(createdFiles.size() == 1);
1371
1372     // Error out now if there were parsing errors.
1373     if (yin.error())
1374       return make_error_code(lld::YamlReaderError::illegal_value);
1375
1376     std::shared_ptr<MemoryBuffer> smb(mb.release());
1377     const File *file = createdFiles[0];
1378     // Note: loadFile() should return vector of *const* File
1379     File *f = const_cast<File *>(file);
1380     f->setLastError(std::error_code());
1381     f->setSharedMemoryBuffer(smb);
1382     return std::unique_ptr<File>(f);
1383   }
1384
1385 private:
1386   const Registry &_registry;
1387 };
1388
1389 } // end anonymous namespace
1390
1391 void Registry::addSupportYamlFiles() {
1392   add(std::unique_ptr<Reader>(new YAMLReader(*this)));
1393   add(std::unique_ptr<YamlIOTaggedDocumentHandler>(
1394                                     new NativeYamlIOTaggedDocumentHandler()));
1395   add(std::unique_ptr<YamlIOTaggedDocumentHandler>(
1396                                     new ArchiveYamlIOTaggedDocumentHandler()));
1397 }
1398
1399 std::unique_ptr<Writer> createWriterYAML(const LinkingContext &context) {
1400   return std::unique_ptr<Writer>(new lld::yaml::Writer(context));
1401 }
1402
1403 } // end namespace lld