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