Coverage Report

Created: 2017-09-19 22:28

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