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