1 //===- lib/ReaderWriter/YAML/ReaderWriterYAML.cpp -------------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
43 #include <system_error>
46 using llvm::file_magic;
47 using llvm::yaml::MappingTraits;
48 using llvm::yaml::ScalarEnumerationTraits;
49 using llvm::yaml::ScalarTraits;
51 using llvm::yaml::SequenceTraits;
52 using llvm::yaml::DocumentListTraits;
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.
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.
68 /// One need for ref-names are when atoms have no user supplied name
69 /// (e.g. c-string literal). Another case is when two object files with
70 /// identically named static functions are merged (ld -r) into one object file.
71 /// In that case referencing the function by name is ambiguous, so a unique
72 /// ref-name is added.
73 class RefNameBuilder {
75 RefNameBuilder(const lld::File &file)
76 : _collisionCount(0), _unnamedCounter(0) {
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);
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()) {
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: '"
96 << (const void *)newName.data() << ", "
97 << newName.size() << ")\n");
101 for (const lld::UndefinedAtom *undefAtom : file.undefined()) {
102 buildDuplicateNameMap(*undefAtom);
104 for (const lld::SharedLibraryAtom *shlibAtom : file.sharedLibrary()) {
105 buildDuplicateNameMap(*shlibAtom);
107 for (const lld::AbsoluteAtom *absAtom : file.absolute()) {
108 if (!absAtom->name().empty())
109 buildDuplicateNameMap(*absAtom);
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.
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: '"
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: '"
140 << (const void *)newName2.data() << ", "
141 << newName2.size() << ")\n");
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");
154 bool hasRefName(const lld::Atom *atom) { return _refNames.count(atom); }
156 StringRef refName(const lld::Atom *atom) {
157 return _refNames.find(atom)->second;
161 typedef llvm::StringMap<const lld::Atom *> NameToAtom;
162 typedef llvm::DenseMap<const lld::Atom *, std::string> AtomToRefName;
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());
172 unsigned int _collisionCount;
173 unsigned int _unnamedCounter;
175 AtomToRefName _refNames;
176 llvm::BumpPtrAllocator _storage;
179 /// Used when reading yaml files to find the target of a reference
180 /// that could be a name or ref-name.
181 class RefNameResolver {
183 RefNameResolver(const lld::File *file, IO &io);
185 const lld::Atom *lookup(StringRef name) const {
186 NameToAtom::const_iterator pos = _nameMap.find(name);
187 if (pos != _nameMap.end())
189 _io.setError(Twine("no such atom name: ") + name);
194 typedef llvm::StringMap<const lld::Atom *> NameToAtom;
196 void add(StringRef name, const lld::Atom *atom) {
197 if (_nameMap.count(name)) {
198 _io.setError(Twine("duplicate atom name: ") + name);
200 _nameMap[name] = atom;
208 /// Mapping of Atoms.
209 template <typename T> class AtomList {
210 using Ty = std::vector<OwningAtomPtr<T>>;
213 typename Ty::iterator begin() { return _atoms.begin(); }
214 typename Ty::iterator end() { return _atoms.end(); }
218 /// Mapping of kind: field in yaml files.
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
228 const lld::File *_content;
231 // The content bytes in a DefinedAtom are just uint8_t but we want
232 // special formatting, so define a strong type.
233 LLVM_YAML_STRONG_TYPEDEF(uint8_t, ImplicitHex8)
235 // SharedLibraryAtoms have a bool canBeNull() method which we'd like to be
236 // more readable than just true/false.
237 LLVM_YAML_STRONG_TYPEDEF(bool, ShlibCanBeNull)
239 // lld::Reference::Kind is a tuple of <namespace, arch, value>.
240 // For yaml, we just want one string that encapsulates the tuple.
242 Reference::KindNamespace ns;
243 Reference::KindArch arch;
244 Reference::KindValue value;
247 } // end anonymous namespace
249 LLVM_YAML_IS_SEQUENCE_VECTOR(ArchMember)
250 LLVM_YAML_IS_SEQUENCE_VECTOR(const lld::Reference *)
251 // Always write DefinedAtoms content bytes as a flow sequence.
252 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(ImplicitHex8)
254 // for compatibility with gcc-4.7 in C++11 mode, add extra namespace
258 // This is a custom formatter for RefKind
259 template <> struct ScalarTraits<RefKind> {
260 static void output(const RefKind &kind, void *ctxt, raw_ostream &out) {
261 assert(ctxt != nullptr);
262 YamlContext *info = reinterpret_cast<YamlContext *>(ctxt);
263 assert(info->_registry);
265 if (info->_registry->referenceKindToString(kind.ns, kind.arch, kind.value,
269 out << (int)(kind.ns) << "-" << (int)(kind.arch) << "-" << kind.value;
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,
279 return StringRef("unknown reference kind");
282 static QuotingType mustQuote(StringRef) { return QuotingType::None; }
285 template <> struct ScalarEnumerationTraits<lld::File::Kind> {
286 static void enumeration(IO &io, lld::File::Kind &value) {
287 io.enumCase(value, "error-object", lld::File::kindErrorObject);
288 io.enumCase(value, "object", lld::File::kindMachObject);
289 io.enumCase(value, "shared-library", lld::File::kindSharedLibrary);
290 io.enumCase(value, "static-library", lld::File::kindArchiveLibrary);
294 template <> struct ScalarEnumerationTraits<lld::Atom::Scope> {
295 static void enumeration(IO &io, lld::Atom::Scope &value) {
296 io.enumCase(value, "global", lld::Atom::scopeGlobal);
297 io.enumCase(value, "hidden", lld::Atom::scopeLinkageUnit);
298 io.enumCase(value, "static", lld::Atom::scopeTranslationUnit);
302 template <> struct ScalarEnumerationTraits<lld::DefinedAtom::SectionChoice> {
303 static void enumeration(IO &io, lld::DefinedAtom::SectionChoice &value) {
304 io.enumCase(value, "content", lld::DefinedAtom::sectionBasedOnContent);
305 io.enumCase(value, "custom", lld::DefinedAtom::sectionCustomPreferred);
306 io.enumCase(value, "custom-required",
307 lld::DefinedAtom::sectionCustomRequired);
311 template <> struct ScalarEnumerationTraits<lld::DefinedAtom::Interposable> {
312 static void enumeration(IO &io, lld::DefinedAtom::Interposable &value) {
313 io.enumCase(value, "no", DefinedAtom::interposeNo);
314 io.enumCase(value, "yes", DefinedAtom::interposeYes);
315 io.enumCase(value, "yes-and-weak", DefinedAtom::interposeYesAndRuntimeWeak);
319 template <> struct ScalarEnumerationTraits<lld::DefinedAtom::Merge> {
320 static void enumeration(IO &io, lld::DefinedAtom::Merge &value) {
321 io.enumCase(value, "no", lld::DefinedAtom::mergeNo);
322 io.enumCase(value, "as-tentative", lld::DefinedAtom::mergeAsTentative);
323 io.enumCase(value, "as-weak", lld::DefinedAtom::mergeAsWeak);
324 io.enumCase(value, "as-addressed-weak",
325 lld::DefinedAtom::mergeAsWeakAndAddressUsed);
326 io.enumCase(value, "by-content", lld::DefinedAtom::mergeByContent);
327 io.enumCase(value, "same-name-and-size",
328 lld::DefinedAtom::mergeSameNameAndSize);
329 io.enumCase(value, "largest", lld::DefinedAtom::mergeByLargestSection);
333 template <> struct ScalarEnumerationTraits<lld::DefinedAtom::DeadStripKind> {
334 static void enumeration(IO &io, lld::DefinedAtom::DeadStripKind &value) {
335 io.enumCase(value, "normal", lld::DefinedAtom::deadStripNormal);
336 io.enumCase(value, "never", lld::DefinedAtom::deadStripNever);
337 io.enumCase(value, "always", lld::DefinedAtom::deadStripAlways);
341 template <> struct ScalarEnumerationTraits<lld::DefinedAtom::DynamicExport> {
342 static void enumeration(IO &io, lld::DefinedAtom::DynamicExport &value) {
343 io.enumCase(value, "normal", lld::DefinedAtom::dynamicExportNormal);
344 io.enumCase(value, "always", lld::DefinedAtom::dynamicExportAlways);
348 template <> struct ScalarEnumerationTraits<lld::DefinedAtom::CodeModel> {
349 static void enumeration(IO &io, lld::DefinedAtom::CodeModel &value) {
350 io.enumCase(value, "none", lld::DefinedAtom::codeNA);
351 io.enumCase(value, "mips-pic", lld::DefinedAtom::codeMipsPIC);
352 io.enumCase(value, "mips-micro", lld::DefinedAtom::codeMipsMicro);
353 io.enumCase(value, "mips-micro-pic", lld::DefinedAtom::codeMipsMicroPIC);
354 io.enumCase(value, "mips-16", lld::DefinedAtom::codeMips16);
355 io.enumCase(value, "arm-thumb", lld::DefinedAtom::codeARMThumb);
356 io.enumCase(value, "arm-a", lld::DefinedAtom::codeARM_a);
357 io.enumCase(value, "arm-d", lld::DefinedAtom::codeARM_d);
358 io.enumCase(value, "arm-t", lld::DefinedAtom::codeARM_t);
363 struct ScalarEnumerationTraits<lld::DefinedAtom::ContentPermissions> {
364 static void enumeration(IO &io, lld::DefinedAtom::ContentPermissions &value) {
365 io.enumCase(value, "---", lld::DefinedAtom::perm___);
366 io.enumCase(value, "r--", lld::DefinedAtom::permR__);
367 io.enumCase(value, "r-x", lld::DefinedAtom::permR_X);
368 io.enumCase(value, "rw-", lld::DefinedAtom::permRW_);
369 io.enumCase(value, "rwx", lld::DefinedAtom::permRWX);
370 io.enumCase(value, "rw-l", lld::DefinedAtom::permRW_L);
371 io.enumCase(value, "unknown", lld::DefinedAtom::permUnknown);
375 template <> struct ScalarEnumerationTraits<lld::DefinedAtom::ContentType> {
376 static void enumeration(IO &io, lld::DefinedAtom::ContentType &value) {
377 io.enumCase(value, "unknown", DefinedAtom::typeUnknown);
378 io.enumCase(value, "code", DefinedAtom::typeCode);
379 io.enumCase(value, "stub", DefinedAtom::typeStub);
380 io.enumCase(value, "constant", DefinedAtom::typeConstant);
381 io.enumCase(value, "data", DefinedAtom::typeData);
382 io.enumCase(value, "quick-data", DefinedAtom::typeDataFast);
383 io.enumCase(value, "zero-fill", DefinedAtom::typeZeroFill);
384 io.enumCase(value, "zero-fill-quick", DefinedAtom::typeZeroFillFast);
385 io.enumCase(value, "const-data", DefinedAtom::typeConstData);
386 io.enumCase(value, "got", DefinedAtom::typeGOT);
387 io.enumCase(value, "resolver", DefinedAtom::typeResolver);
388 io.enumCase(value, "branch-island", DefinedAtom::typeBranchIsland);
389 io.enumCase(value, "branch-shim", DefinedAtom::typeBranchShim);
390 io.enumCase(value, "stub-helper", DefinedAtom::typeStubHelper);
391 io.enumCase(value, "c-string", DefinedAtom::typeCString);
392 io.enumCase(value, "utf16-string", DefinedAtom::typeUTF16String);
393 io.enumCase(value, "unwind-cfi", DefinedAtom::typeCFI);
394 io.enumCase(value, "unwind-lsda", DefinedAtom::typeLSDA);
395 io.enumCase(value, "const-4-byte", DefinedAtom::typeLiteral4);
396 io.enumCase(value, "const-8-byte", DefinedAtom::typeLiteral8);
397 io.enumCase(value, "const-16-byte", DefinedAtom::typeLiteral16);
398 io.enumCase(value, "lazy-pointer", DefinedAtom::typeLazyPointer);
399 io.enumCase(value, "lazy-dylib-pointer",
400 DefinedAtom::typeLazyDylibPointer);
401 io.enumCase(value, "cfstring", DefinedAtom::typeCFString);
402 io.enumCase(value, "initializer-pointer",
403 DefinedAtom::typeInitializerPtr);
404 io.enumCase(value, "terminator-pointer",
405 DefinedAtom::typeTerminatorPtr);
406 io.enumCase(value, "c-string-pointer",DefinedAtom::typeCStringPtr);
407 io.enumCase(value, "objc-class-pointer",
408 DefinedAtom::typeObjCClassPtr);
409 io.enumCase(value, "objc-category-list",
410 DefinedAtom::typeObjC2CategoryList);
411 io.enumCase(value, "objc-image-info",
412 DefinedAtom::typeObjCImageInfo);
413 io.enumCase(value, "objc-method-list",
414 DefinedAtom::typeObjCMethodList);
415 io.enumCase(value, "objc-class1", DefinedAtom::typeObjC1Class);
416 io.enumCase(value, "dtraceDOF", DefinedAtom::typeDTraceDOF);
417 io.enumCase(value, "interposing-tuples",
418 DefinedAtom::typeInterposingTuples);
419 io.enumCase(value, "lto-temp", DefinedAtom::typeTempLTO);
420 io.enumCase(value, "compact-unwind", DefinedAtom::typeCompactUnwindInfo);
421 io.enumCase(value, "unwind-info", DefinedAtom::typeProcessedUnwindInfo);
422 io.enumCase(value, "tlv-thunk", DefinedAtom::typeThunkTLV);
423 io.enumCase(value, "tlv-data", DefinedAtom::typeTLVInitialData);
424 io.enumCase(value, "tlv-zero-fill", DefinedAtom::typeTLVInitialZeroFill);
425 io.enumCase(value, "tlv-initializer-ptr",
426 DefinedAtom::typeTLVInitializerPtr);
427 io.enumCase(value, "mach_header", DefinedAtom::typeMachHeader);
428 io.enumCase(value, "dso_handle", DefinedAtom::typeDSOHandle);
429 io.enumCase(value, "sectcreate", DefinedAtom::typeSectCreate);
433 template <> struct ScalarEnumerationTraits<lld::UndefinedAtom::CanBeNull> {
434 static void enumeration(IO &io, lld::UndefinedAtom::CanBeNull &value) {
435 io.enumCase(value, "never", lld::UndefinedAtom::canBeNullNever);
436 io.enumCase(value, "at-runtime", lld::UndefinedAtom::canBeNullAtRuntime);
437 io.enumCase(value, "at-buildtime",lld::UndefinedAtom::canBeNullAtBuildtime);
441 template <> struct ScalarEnumerationTraits<ShlibCanBeNull> {
442 static void enumeration(IO &io, ShlibCanBeNull &value) {
443 io.enumCase(value, "never", false);
444 io.enumCase(value, "at-runtime", true);
449 struct ScalarEnumerationTraits<lld::SharedLibraryAtom::Type> {
450 static void enumeration(IO &io, lld::SharedLibraryAtom::Type &value) {
451 io.enumCase(value, "code", lld::SharedLibraryAtom::Type::Code);
452 io.enumCase(value, "data", lld::SharedLibraryAtom::Type::Data);
453 io.enumCase(value, "unknown", lld::SharedLibraryAtom::Type::Unknown);
457 /// This is a custom formatter for lld::DefinedAtom::Alignment. Values look
459 /// 8 # 8-byte aligned
460 /// 7 mod 16 # 16-byte aligned plus 7 bytes
461 template <> struct ScalarTraits<lld::DefinedAtom::Alignment> {
462 static void output(const lld::DefinedAtom::Alignment &value, void *ctxt,
464 if (value.modulus == 0) {
465 out << llvm::format("%d", value.value);
467 out << llvm::format("%d mod %d", value.modulus, value.value);
471 static StringRef input(StringRef scalar, void *ctxt,
472 lld::DefinedAtom::Alignment &value) {
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";
482 value.modulus = modulus;
483 scalar = scalar.drop_front(modStart + 3);
484 scalar = scalar.ltrim();
487 if (scalar.getAsInteger(0, power)) {
488 return "malformed alignment power";
491 if (value.modulus >= power) {
492 return "malformed alignment, modulus too large for power";
494 return StringRef(); // returning empty string means success
497 static QuotingType mustQuote(StringRef) { return QuotingType::None; }
500 template <> struct ScalarEnumerationTraits<FileKinds> {
501 static void enumeration(IO &io, FileKinds &value) {
502 io.enumCase(value, "object", fileKindObjectAtoms);
503 io.enumCase(value, "archive", fileKindArchive);
504 io.enumCase(value, "object-mach-o", fileKindObjectMachO);
508 template <> struct MappingTraits<ArchMember> {
509 static void mapping(IO &io, ArchMember &member) {
510 io.mapOptional("kind", member._kind, fileKindObjectAtoms);
511 io.mapOptional("name", member._name);
512 io.mapRequired("content", member._content);
516 // Declare that an AtomList is a yaml sequence.
517 template <typename T> struct SequenceTraits<AtomList<T> > {
518 static size_t size(IO &io, AtomList<T> &seq) { return seq._atoms.size(); }
519 static T *&element(IO &io, AtomList<T> &seq, size_t index) {
520 if (index >= seq._atoms.size())
521 seq._atoms.resize(index + 1);
522 return seq._atoms[index].get();
526 // Declare that an AtomRange is a yaml sequence.
527 template <typename T> struct SequenceTraits<File::AtomRange<T> > {
528 static size_t size(IO &io, File::AtomRange<T> &seq) { return seq.size(); }
529 static T *&element(IO &io, File::AtomRange<T> &seq, size_t index) {
530 assert(io.outputting() && "AtomRange only used when outputting");
531 assert(index < seq.size() && "Out of range access");
532 return seq[index].get();
536 // Used to allow DefinedAtom content bytes to be a flow sequence of
537 // two-digit hex numbers without the leading 0x (e.g. FF, 04, 0A)
538 template <> struct ScalarTraits<ImplicitHex8> {
539 static void output(const ImplicitHex8 &val, void *, raw_ostream &out) {
541 out << llvm::format("%02X", num);
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";
549 return "out of range two-digit-hex number";
551 return StringRef(); // returning empty string means success
554 static QuotingType mustQuote(StringRef) { return QuotingType::None; }
557 // YAML conversion for std::vector<const lld::File*>
558 template <> struct DocumentListTraits<std::vector<const lld::File *> > {
559 static size_t size(IO &io, std::vector<const lld::File *> &seq) {
562 static const lld::File *&element(IO &io, std::vector<const lld::File *> &seq,
564 if (index >= seq.size())
565 seq.resize(index + 1);
570 // YAML conversion for const lld::File*
571 template <> struct MappingTraits<const lld::File *> {
572 class NormArchiveFile : public lld::ArchiveLibraryFile {
574 NormArchiveFile(IO &io) : ArchiveLibraryFile("") {}
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.
582 const lld::File *denormalize(IO &io) { return this; }
584 const AtomRange<lld::DefinedAtom> defined() const override {
585 return _noDefinedAtoms;
588 const AtomRange<lld::UndefinedAtom> undefined() const override {
589 return _noUndefinedAtoms;
592 const AtomRange<lld::SharedLibraryAtom> sharedLibrary() const override {
593 return _noSharedLibraryAtoms;
596 const AtomRange<lld::AbsoluteAtom> absolute() const override {
597 return _noAbsoluteAtoms;
600 void clearAtoms() override {
601 _noDefinedAtoms.clear();
602 _noUndefinedAtoms.clear();
603 _noSharedLibraryAtoms.clear();
604 _noAbsoluteAtoms.clear();
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);
616 parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
617 return std::error_code();
621 std::vector<ArchMember> _members;
624 class NormalizedFile : public lld::File {
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) {}
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()) {
642 ~NormalizedFile() override {
645 const lld::File *denormalize(IO &io);
647 const AtomRange<lld::DefinedAtom> defined() const override {
648 return _definedAtomsRef;
651 const AtomRange<lld::UndefinedAtom> undefined() const override {
652 return _undefinedAtomsRef;
655 const AtomRange<lld::SharedLibraryAtom> sharedLibrary() const override {
656 return _sharedLibraryAtomsRef;
659 const AtomRange<lld::AbsoluteAtom> absolute() const override {
660 return _absoluteAtomsRef;
663 void clearAtoms() override {
664 _definedAtoms._atoms.clear();
665 _undefinedAtoms._atoms.clear();
666 _sharedLibraryAtoms._atoms.clear();
667 _absoluteAtoms._atoms.clear();
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());
679 std::unique_ptr<RefNameBuilder> _rnb;
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;
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))
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);
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->();
711 io.mapOptional("path", keys->_path);
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);
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);
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());
731 io.mapOptional("path", keys->_path);
732 io.mapOptional("members", keys->_members);
736 // YAML conversion for const lld::Reference*
737 template <> struct MappingTraits<const lld::Reference *> {
738 class NormalizedReference : public lld::Reference {
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) {}
745 NormalizedReference(IO &io, const lld::Reference *ref)
746 : lld::Reference(ref->kindNamespace(), ref->kindArch(),
748 _target(nullptr), _targetName(targetName(io, ref)),
749 _offset(ref->offsetInAtom()), _addend(ref->addend()),
751 _mappedKind.ns = ref->kindNamespace();
752 _mappedKind.arch = ref->kindArch();
753 _mappedKind.value = ref->kindValue();
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);
774 void bind(const RefNameResolver &);
775 static StringRef targetName(IO &io, const lld::Reference *ref);
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; }
783 const lld::Atom *_target;
784 StringRef _targetName;
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());
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);
804 // YAML conversion for const lld::DefinedAtom*
805 template <> struct MappingTraits<const lld::DefinedAtom *> {
807 class NormalizedAtom : public lld::DefinedAtom {
809 NormalizedAtom(IO &io)
810 : _file(fileFromContext(io)), _contentType(), _alignment(1) {
811 static uint32_t ordinalCounter = 1;
812 _ordinal = ordinalCounter++;
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())
829 ArrayRef<uint8_t> cont = atom->rawContent();
830 _content.reserve(cont.size());
831 for (uint8_t x : cont)
832 _content.push_back(x);
835 ~NormalizedAtom() override = default;
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);
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");
855 void bind(const RefNameResolver &);
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);
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());
887 uint64_t ordinal() const override { return _ordinal; }
889 reference_iterator begin() const override {
891 const void *it = reinterpret_cast<const void *>(index);
892 return reference_iterator(*this, it);
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);
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];
904 void incrementIterator(const void *&it) const override {
905 uintptr_t index = reinterpret_cast<uintptr_t>(it);
907 it = reinterpret_cast<const void *>(index);
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,
917 _references.push_back(node);
920 const lld::File &_file;
924 Interposable _interpose;
926 ContentType _contentType;
927 Alignment _alignment;
928 SectionChoice _sectionChoice;
929 DeadStripKind _deadStrip;
930 DynamicExport _dynamicExport;
931 CodeModel _codeModel;
932 ContentPermissions _permissions;
934 std::vector<ImplicitHex8> _content;
936 StringRef _sectionName;
937 uint64_t _sectionSize;
938 std::vector<const lld::Reference *> _references;
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);
952 if (f->_rnb->hasRefName(atom)) {
953 keys->_refName = f->_rnb->refName(atom);
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);
987 template <> struct MappingTraits<lld::DefinedAtom *> {
988 static void mapping(IO &io, lld::DefinedAtom *&atom) {
989 const lld::DefinedAtom *atomPtr = atom;
990 MappingTraits<const lld::DefinedAtom *>::mapping(io, atomPtr);
991 atom = const_cast<lld::DefinedAtom *>(atomPtr);
995 // YAML conversion for const lld::UndefinedAtom*
996 template <> struct MappingTraits<const lld::UndefinedAtom *> {
997 class NormalizedAtom : public lld::UndefinedAtom {
999 NormalizedAtom(IO &io)
1000 : _file(fileFromContext(io)), _canBeNull(canBeNullNever) {}
1002 NormalizedAtom(IO &io, const lld::UndefinedAtom *atom)
1003 : _file(fileFromContext(io)), _name(atom->name()),
1004 _canBeNull(atom->canBeNull()) {}
1006 ~NormalizedAtom() override = default;
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);
1014 _name = f->copyString(_name);
1016 DEBUG_WITH_TYPE("WriterYAML",
1017 llvm::dbgs() << "created UndefinedAtom named: '" << _name
1018 << "' (" << (const void *)_name.data() << ", "
1019 << _name.size() << ")\n");
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;
1031 const lld::File &file() const override { return _file; }
1032 StringRef name() const override { return _name; }
1033 CanBeNull canBeNull() const override { return _canBeNull; }
1035 const lld::File &_file;
1037 CanBeNull _canBeNull;
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());
1045 io.mapRequired("name", keys->_name);
1046 io.mapOptional("can-be-null", keys->_canBeNull,
1047 lld::UndefinedAtom::canBeNullNever);
1051 template <> struct MappingTraits<lld::UndefinedAtom *> {
1052 static void mapping(IO &io, lld::UndefinedAtom *&atom) {
1053 const lld::UndefinedAtom *atomPtr = atom;
1054 MappingTraits<const lld::UndefinedAtom *>::mapping(io, atomPtr);
1055 atom = const_cast<lld::UndefinedAtom *>(atomPtr);
1059 // YAML conversion for const lld::SharedLibraryAtom*
1060 template <> struct MappingTraits<const lld::SharedLibraryAtom *> {
1061 class NormalizedAtom : public lld::SharedLibraryAtom {
1063 NormalizedAtom(IO &io)
1064 : _file(fileFromContext(io)), _canBeNull(false),
1065 _type(Type::Unknown), _size(0) {}
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()) {}
1072 ~NormalizedAtom() override = default;
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);
1080 _name = f->copyString(_name);
1081 if (!_loadName.empty())
1082 _loadName = f->copyString(_loadName);
1084 DEBUG_WITH_TYPE("WriterYAML",
1085 llvm::dbgs() << "created SharedLibraryAtom named: '"
1087 << (const void *)_name.data()
1088 << ", " << _name.size() << ")\n");
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;
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; }
1107 const lld::File &_file;
1109 StringRef _loadName;
1110 ShlibCanBeNull _canBeNull;
1115 static void mapping(IO &io, const lld::SharedLibraryAtom *&atom) {
1117 YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
1118 MappingNormalizationHeap<NormalizedAtom, const lld::SharedLibraryAtom *>
1119 keys(io, atom, &info->_file->allocator());
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));
1129 template <> struct MappingTraits<lld::SharedLibraryAtom *> {
1130 static void mapping(IO &io, lld::SharedLibraryAtom *&atom) {
1131 const lld::SharedLibraryAtom *atomPtr = atom;
1132 MappingTraits<const lld::SharedLibraryAtom *>::mapping(io, atomPtr);
1133 atom = const_cast<lld::SharedLibraryAtom *>(atomPtr);
1137 // YAML conversion for const lld::AbsoluteAtom*
1138 template <> struct MappingTraits<const lld::AbsoluteAtom *> {
1139 class NormalizedAtom : public lld::AbsoluteAtom {
1141 NormalizedAtom(IO &io)
1142 : _file(fileFromContext(io)), _scope(), _value(0) {}
1144 NormalizedAtom(IO &io, const lld::AbsoluteAtom *atom)
1145 : _file(fileFromContext(io)), _name(atom->name()),
1146 _scope(atom->scope()), _value(atom->value()) {}
1148 ~NormalizedAtom() override = default;
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);
1156 _name = f->copyString(_name);
1158 DEBUG_WITH_TYPE("WriterYAML",
1159 llvm::dbgs() << "created AbsoluteAtom named: '" << _name
1160 << "' (" << (const void *)_name.data()
1161 << ", " << _name.size() << ")\n");
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;
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; }
1178 const lld::File &_file;
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());
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);
1197 if (f->_rnb->hasRefName(atom)) {
1198 keys->_refName = f->_rnb->refName(atom);
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);
1209 template <> struct MappingTraits<lld::AbsoluteAtom *> {
1210 static void mapping(IO &io, lld::AbsoluteAtom *&atom) {
1211 const lld::AbsoluteAtom *atomPtr = atom;
1212 MappingTraits<const lld::AbsoluteAtom *>::mapping(io, atomPtr);
1213 atom = const_cast<lld::AbsoluteAtom *>(atomPtr);
1217 } // end namespace llvm
1218 } // end namespace yaml
1220 RefNameResolver::RefNameResolver(const lld::File *file, IO &io) : _io(io) {
1221 typedef MappingTraits<const lld::DefinedAtom *>::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())
1231 for (const lld::UndefinedAtom *a : file->undefined())
1234 for (const lld::SharedLibraryAtom *a : file->sharedLibrary())
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())
1243 add(na->_refName, a);
1247 inline const lld::File *
1248 MappingTraits<const lld::File *>::NormalizedFile::denormalize(IO &io) {
1249 typedef MappingTraits<const lld::DefinedAtom *>::NormalizedAtom
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);
1262 inline void MappingTraits<const lld::DefinedAtom *>::NormalizedAtom::bind(
1263 const RefNameResolver &resolver) {
1264 typedef MappingTraits<const lld::Reference *>::NormalizedReference
1265 NormalizedReference;
1266 for (const lld::Reference *ref : _references) {
1267 auto *normRef = (NormalizedReference *)const_cast<Reference *>(ref);
1268 normRef->bind(resolver);
1272 inline void MappingTraits<const lld::Reference *>::NormalizedReference::bind(
1273 const RefNameResolver &resolver) {
1274 _target = resolver.lookup(_targetName);
1278 MappingTraits<const lld::Reference *>::NormalizedReference::targetName(
1279 IO &io, const lld::Reference *ref) {
1280 if (ref->target() == nullptr)
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();
1295 class Writer : public lld::Writer {
1297 Writer(const LinkingContext &context) : _ctx(context) {}
1299 llvm::Error writeFile(const lld::File &file, StringRef outPath) override {
1300 // Create stream to path.
1302 llvm::raw_fd_ostream out(outPath, ec, llvm::sys::fs::OF_Text);
1304 return llvm::errorCodeToError(ec);
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);
1312 // Write yaml output.
1313 const lld::File *fileRef = &file;
1316 return llvm::Error::success();
1320 const LinkingContext &_ctx;
1323 } // end namespace yaml
1327 /// Handles !native tagged yaml documents.
1328 class NativeYamlIOTaggedDocumentHandler : public YamlIOTaggedDocumentHandler {
1329 bool handledDocTag(llvm::yaml::IO &io, const lld::File *&file) const override {
1330 if (io.mapTag("!native")) {
1331 MappingTraits<const lld::File *>::mappingAtoms(io, file);
1338 /// Handles !archive tagged yaml documents.
1339 class ArchiveYamlIOTaggedDocumentHandler : public YamlIOTaggedDocumentHandler {
1340 bool handledDocTag(llvm::yaml::IO &io, const lld::File *&file) const override {
1341 if (io.mapTag("!archive")) {
1342 MappingTraits<const lld::File *>::mappingArchive(io, file);
1349 class YAMLReader : public Reader {
1351 YAMLReader(const Registry ®istry) : _registry(registry) {}
1353 bool canParse(file_magic magic, MemoryBufferRef mb) const override {
1354 StringRef name = mb.getBufferIdentifier();
1355 return name.endswith(".objtxt") || name.endswith(".yaml");
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);
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);
1372 // Error out now if there were parsing errors.
1374 return make_error_code(lld::YamlReaderError::illegal_value);
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);
1386 const Registry &_registry;
1389 } // end anonymous namespace
1391 void Registry::addSupportYamlFiles() {
1392 add(std::unique_ptr<Reader>(new YAMLReader(*this)));
1393 add(std::unique_ptr<YamlIOTaggedDocumentHandler>(
1394 new NativeYamlIOTaggedDocumentHandler()));
1395 add(std::unique_ptr<YamlIOTaggedDocumentHandler>(
1396 new ArchiveYamlIOTaggedDocumentHandler()));
1399 std::unique_ptr<Writer> createWriterYAML(const LinkingContext &context) {
1400 return std::unique_ptr<Writer>(new lld::yaml::Writer(context));
1403 } // end namespace lld