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