1 //===- lib/ReaderWriter/YAML/ReaderWriterYAML.cpp -------------------------===//
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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"
44 #include <system_error>
47 using llvm::file_magic;
48 using llvm::yaml::MappingTraits;
49 using llvm::yaml::ScalarEnumerationTraits;
50 using llvm::yaml::ScalarTraits;
52 using llvm::yaml::SequenceTraits;
53 using llvm::yaml::DocumentListTraits;
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.
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.
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 {
76 RefNameBuilder(const lld::File &file)
77 : _collisionCount(0), _unnamedCounter(0) {
79 for (const lld::DefinedAtom *atom : file.defined()) {
80 // Build map of atoms names to detect duplicates
81 if (!atom->name().empty())
82 buildDuplicateNameMap(*atom);
84 // Find references to unnamed atoms and create ref-names for them.
85 for (const lld::Reference *ref : *atom) {
86 // create refname for any unnamed reference target
87 const lld::Atom *target = ref->target();
88 if ((target != nullptr) && target->name().empty()) {
90 llvm::raw_string_ostream buffer(storage);
91 buffer << llvm::format("L%03d", _unnamedCounter++);
92 StringRef newName = copyString(buffer.str());
93 _refNames[target] = newName;
94 DEBUG_WITH_TYPE("WriterYAML",
95 llvm::dbgs() << "unnamed atom: creating ref-name: '"
97 << (const void *)newName.data() << ", "
98 << newName.size() << ")\n");
102 for (const lld::UndefinedAtom *undefAtom : file.undefined()) {
103 buildDuplicateNameMap(*undefAtom);
105 for (const lld::SharedLibraryAtom *shlibAtom : file.sharedLibrary()) {
106 buildDuplicateNameMap(*shlibAtom);
108 for (const lld::AbsoluteAtom *absAtom : file.absolute()) {
109 if (!absAtom->name().empty())
110 buildDuplicateNameMap(*absAtom);
114 void buildDuplicateNameMap(const lld::Atom &atom) {
115 assert(!atom.name().empty());
116 NameToAtom::iterator pos = _nameMap.find(atom.name());
117 if (pos != _nameMap.end()) {
118 // Found name collision, give each a unique ref-name.
120 llvm::raw_string_ostream buffer(Storage);
121 buffer << atom.name() << llvm::format(".%03d", ++_collisionCount);
122 StringRef newName = copyString(buffer.str());
123 _refNames[&atom] = newName;
124 DEBUG_WITH_TYPE("WriterYAML",
125 llvm::dbgs() << "name collsion: creating ref-name: '"
127 << (const void *)newName.data()
128 << ", " << newName.size() << ")\n");
129 const lld::Atom *prevAtom = pos->second;
130 AtomToRefName::iterator pos2 = _refNames.find(prevAtom);
131 if (pos2 == _refNames.end()) {
132 // Only create ref-name for previous if none already created.
133 std::string Storage2;
134 llvm::raw_string_ostream buffer2(Storage2);
135 buffer2 << prevAtom->name() << llvm::format(".%03d", ++_collisionCount);
136 StringRef newName2 = copyString(buffer2.str());
137 _refNames[prevAtom] = newName2;
138 DEBUG_WITH_TYPE("WriterYAML",
139 llvm::dbgs() << "name collsion: creating ref-name: '"
141 << (const void *)newName2.data() << ", "
142 << newName2.size() << ")\n");
145 // First time we've seen this name, just add it to map.
146 _nameMap[atom.name()] = &atom;
147 DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
148 << "atom name seen for first time: '"
149 << atom.name() << "' ("
150 << (const void *)atom.name().data()
151 << ", " << atom.name().size() << ")\n");
155 bool hasRefName(const lld::Atom *atom) { return _refNames.count(atom); }
157 StringRef refName(const lld::Atom *atom) {
158 return _refNames.find(atom)->second;
162 typedef llvm::StringMap<const lld::Atom *> NameToAtom;
163 typedef llvm::DenseMap<const lld::Atom *, std::string> AtomToRefName;
165 // Allocate a new copy of this string in _storage, so the strings
166 // can be freed when RefNameBuilder is destroyed.
167 StringRef copyString(StringRef str) {
168 char *s = _storage.Allocate<char>(str.size());
169 memcpy(s, str.data(), str.size());
170 return StringRef(s, str.size());
173 unsigned int _collisionCount;
174 unsigned int _unnamedCounter;
176 AtomToRefName _refNames;
177 llvm::BumpPtrAllocator _storage;
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 {
184 RefNameResolver(const lld::File *file, IO &io);
186 const lld::Atom *lookup(StringRef name) const {
187 NameToAtom::const_iterator pos = _nameMap.find(name);
188 if (pos != _nameMap.end())
190 _io.setError(Twine("no such atom name: ") + name);
195 typedef llvm::StringMap<const lld::Atom *> NameToAtom;
197 void add(StringRef name, const lld::Atom *atom) {
198 if (_nameMap.count(name)) {
199 _io.setError(Twine("duplicate atom name: ") + name);
201 _nameMap[name] = atom;
209 /// Mapping of Atoms.
210 template <typename T> class AtomList {
211 using Ty = std::vector<OwningAtomPtr<T>>;
214 typename Ty::iterator begin() { return _atoms.begin(); }
215 typename Ty::iterator end() { return _atoms.end(); }
219 /// Mapping of kind: field in yaml files.
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
229 const lld::File *_content;
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)
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)
240 // lld::Reference::Kind is a tuple of <namespace, arch, value>.
241 // For yaml, we just want one string that encapsulates the tuple.
243 Reference::KindNamespace ns;
244 Reference::KindArch arch;
245 Reference::KindValue value;
248 } // end anonymous namespace
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)
255 // for compatibility with gcc-4.7 in C++11 mode, add extra namespace
259 // This is a custom formatter for RefKind
260 template <> struct ScalarTraits<RefKind> {
261 static void output(const RefKind &kind, void *ctxt, raw_ostream &out) {
262 assert(ctxt != nullptr);
263 YamlContext *info = reinterpret_cast<YamlContext *>(ctxt);
264 assert(info->_registry);
266 if (info->_registry->referenceKindToString(kind.ns, kind.arch, kind.value,
270 out << (int)(kind.ns) << "-" << (int)(kind.arch) << "-" << kind.value;
273 static StringRef input(StringRef scalar, void *ctxt, RefKind &kind) {
274 assert(ctxt != nullptr);
275 YamlContext *info = reinterpret_cast<YamlContext *>(ctxt);
276 assert(info->_registry);
277 if (info->_registry->referenceKindFromString(scalar, kind.ns, kind.arch,
280 return StringRef("unknown reference kind");
283 static QuotingType mustQuote(StringRef) { return QuotingType::None; }
286 template <> struct ScalarEnumerationTraits<lld::File::Kind> {
287 static void enumeration(IO &io, lld::File::Kind &value) {
288 io.enumCase(value, "error-object", lld::File::kindErrorObject);
289 io.enumCase(value, "object", lld::File::kindMachObject);
290 io.enumCase(value, "shared-library", lld::File::kindSharedLibrary);
291 io.enumCase(value, "static-library", lld::File::kindArchiveLibrary);
295 template <> struct ScalarEnumerationTraits<lld::Atom::Scope> {
296 static void enumeration(IO &io, lld::Atom::Scope &value) {
297 io.enumCase(value, "global", lld::Atom::scopeGlobal);
298 io.enumCase(value, "hidden", lld::Atom::scopeLinkageUnit);
299 io.enumCase(value, "static", lld::Atom::scopeTranslationUnit);
303 template <> struct ScalarEnumerationTraits<lld::DefinedAtom::SectionChoice> {
304 static void enumeration(IO &io, lld::DefinedAtom::SectionChoice &value) {
305 io.enumCase(value, "content", lld::DefinedAtom::sectionBasedOnContent);
306 io.enumCase(value, "custom", lld::DefinedAtom::sectionCustomPreferred);
307 io.enumCase(value, "custom-required",
308 lld::DefinedAtom::sectionCustomRequired);
312 template <> struct ScalarEnumerationTraits<lld::DefinedAtom::Interposable> {
313 static void enumeration(IO &io, lld::DefinedAtom::Interposable &value) {
314 io.enumCase(value, "no", DefinedAtom::interposeNo);
315 io.enumCase(value, "yes", DefinedAtom::interposeYes);
316 io.enumCase(value, "yes-and-weak", DefinedAtom::interposeYesAndRuntimeWeak);
320 template <> struct ScalarEnumerationTraits<lld::DefinedAtom::Merge> {
321 static void enumeration(IO &io, lld::DefinedAtom::Merge &value) {
322 io.enumCase(value, "no", lld::DefinedAtom::mergeNo);
323 io.enumCase(value, "as-tentative", lld::DefinedAtom::mergeAsTentative);
324 io.enumCase(value, "as-weak", lld::DefinedAtom::mergeAsWeak);
325 io.enumCase(value, "as-addressed-weak",
326 lld::DefinedAtom::mergeAsWeakAndAddressUsed);
327 io.enumCase(value, "by-content", lld::DefinedAtom::mergeByContent);
328 io.enumCase(value, "same-name-and-size",
329 lld::DefinedAtom::mergeSameNameAndSize);
330 io.enumCase(value, "largest", lld::DefinedAtom::mergeByLargestSection);
334 template <> struct ScalarEnumerationTraits<lld::DefinedAtom::DeadStripKind> {
335 static void enumeration(IO &io, lld::DefinedAtom::DeadStripKind &value) {
336 io.enumCase(value, "normal", lld::DefinedAtom::deadStripNormal);
337 io.enumCase(value, "never", lld::DefinedAtom::deadStripNever);
338 io.enumCase(value, "always", lld::DefinedAtom::deadStripAlways);
342 template <> struct ScalarEnumerationTraits<lld::DefinedAtom::DynamicExport> {
343 static void enumeration(IO &io, lld::DefinedAtom::DynamicExport &value) {
344 io.enumCase(value, "normal", lld::DefinedAtom::dynamicExportNormal);
345 io.enumCase(value, "always", lld::DefinedAtom::dynamicExportAlways);
349 template <> struct ScalarEnumerationTraits<lld::DefinedAtom::CodeModel> {
350 static void enumeration(IO &io, lld::DefinedAtom::CodeModel &value) {
351 io.enumCase(value, "none", lld::DefinedAtom::codeNA);
352 io.enumCase(value, "mips-pic", lld::DefinedAtom::codeMipsPIC);
353 io.enumCase(value, "mips-micro", lld::DefinedAtom::codeMipsMicro);
354 io.enumCase(value, "mips-micro-pic", lld::DefinedAtom::codeMipsMicroPIC);
355 io.enumCase(value, "mips-16", lld::DefinedAtom::codeMips16);
356 io.enumCase(value, "arm-thumb", lld::DefinedAtom::codeARMThumb);
357 io.enumCase(value, "arm-a", lld::DefinedAtom::codeARM_a);
358 io.enumCase(value, "arm-d", lld::DefinedAtom::codeARM_d);
359 io.enumCase(value, "arm-t", lld::DefinedAtom::codeARM_t);
364 struct ScalarEnumerationTraits<lld::DefinedAtom::ContentPermissions> {
365 static void enumeration(IO &io, lld::DefinedAtom::ContentPermissions &value) {
366 io.enumCase(value, "---", lld::DefinedAtom::perm___);
367 io.enumCase(value, "r--", lld::DefinedAtom::permR__);
368 io.enumCase(value, "r-x", lld::DefinedAtom::permR_X);
369 io.enumCase(value, "rw-", lld::DefinedAtom::permRW_);
370 io.enumCase(value, "rwx", lld::DefinedAtom::permRWX);
371 io.enumCase(value, "rw-l", lld::DefinedAtom::permRW_L);
372 io.enumCase(value, "unknown", lld::DefinedAtom::permUnknown);
376 template <> struct ScalarEnumerationTraits<lld::DefinedAtom::ContentType> {
377 static void enumeration(IO &io, lld::DefinedAtom::ContentType &value) {
378 io.enumCase(value, "unknown", DefinedAtom::typeUnknown);
379 io.enumCase(value, "code", DefinedAtom::typeCode);
380 io.enumCase(value, "stub", DefinedAtom::typeStub);
381 io.enumCase(value, "constant", DefinedAtom::typeConstant);
382 io.enumCase(value, "data", DefinedAtom::typeData);
383 io.enumCase(value, "quick-data", DefinedAtom::typeDataFast);
384 io.enumCase(value, "zero-fill", DefinedAtom::typeZeroFill);
385 io.enumCase(value, "zero-fill-quick", DefinedAtom::typeZeroFillFast);
386 io.enumCase(value, "const-data", DefinedAtom::typeConstData);
387 io.enumCase(value, "got", DefinedAtom::typeGOT);
388 io.enumCase(value, "resolver", DefinedAtom::typeResolver);
389 io.enumCase(value, "branch-island", DefinedAtom::typeBranchIsland);
390 io.enumCase(value, "branch-shim", DefinedAtom::typeBranchShim);
391 io.enumCase(value, "stub-helper", DefinedAtom::typeStubHelper);
392 io.enumCase(value, "c-string", DefinedAtom::typeCString);
393 io.enumCase(value, "utf16-string", DefinedAtom::typeUTF16String);
394 io.enumCase(value, "unwind-cfi", DefinedAtom::typeCFI);
395 io.enumCase(value, "unwind-lsda", DefinedAtom::typeLSDA);
396 io.enumCase(value, "const-4-byte", DefinedAtom::typeLiteral4);
397 io.enumCase(value, "const-8-byte", DefinedAtom::typeLiteral8);
398 io.enumCase(value, "const-16-byte", DefinedAtom::typeLiteral16);
399 io.enumCase(value, "lazy-pointer", DefinedAtom::typeLazyPointer);
400 io.enumCase(value, "lazy-dylib-pointer",
401 DefinedAtom::typeLazyDylibPointer);
402 io.enumCase(value, "cfstring", DefinedAtom::typeCFString);
403 io.enumCase(value, "initializer-pointer",
404 DefinedAtom::typeInitializerPtr);
405 io.enumCase(value, "terminator-pointer",
406 DefinedAtom::typeTerminatorPtr);
407 io.enumCase(value, "c-string-pointer",DefinedAtom::typeCStringPtr);
408 io.enumCase(value, "objc-class-pointer",
409 DefinedAtom::typeObjCClassPtr);
410 io.enumCase(value, "objc-category-list",
411 DefinedAtom::typeObjC2CategoryList);
412 io.enumCase(value, "objc-image-info",
413 DefinedAtom::typeObjCImageInfo);
414 io.enumCase(value, "objc-method-list",
415 DefinedAtom::typeObjCMethodList);
416 io.enumCase(value, "objc-class1", DefinedAtom::typeObjC1Class);
417 io.enumCase(value, "dtraceDOF", DefinedAtom::typeDTraceDOF);
418 io.enumCase(value, "interposing-tuples",
419 DefinedAtom::typeInterposingTuples);
420 io.enumCase(value, "lto-temp", DefinedAtom::typeTempLTO);
421 io.enumCase(value, "compact-unwind", DefinedAtom::typeCompactUnwindInfo);
422 io.enumCase(value, "unwind-info", DefinedAtom::typeProcessedUnwindInfo);
423 io.enumCase(value, "tlv-thunk", DefinedAtom::typeThunkTLV);
424 io.enumCase(value, "tlv-data", DefinedAtom::typeTLVInitialData);
425 io.enumCase(value, "tlv-zero-fill", DefinedAtom::typeTLVInitialZeroFill);
426 io.enumCase(value, "tlv-initializer-ptr",
427 DefinedAtom::typeTLVInitializerPtr);
428 io.enumCase(value, "mach_header", DefinedAtom::typeMachHeader);
429 io.enumCase(value, "dso_handle", DefinedAtom::typeDSOHandle);
430 io.enumCase(value, "sectcreate", DefinedAtom::typeSectCreate);
434 template <> struct ScalarEnumerationTraits<lld::UndefinedAtom::CanBeNull> {
435 static void enumeration(IO &io, lld::UndefinedAtom::CanBeNull &value) {
436 io.enumCase(value, "never", lld::UndefinedAtom::canBeNullNever);
437 io.enumCase(value, "at-runtime", lld::UndefinedAtom::canBeNullAtRuntime);
438 io.enumCase(value, "at-buildtime",lld::UndefinedAtom::canBeNullAtBuildtime);
442 template <> struct ScalarEnumerationTraits<ShlibCanBeNull> {
443 static void enumeration(IO &io, ShlibCanBeNull &value) {
444 io.enumCase(value, "never", false);
445 io.enumCase(value, "at-runtime", true);
450 struct ScalarEnumerationTraits<lld::SharedLibraryAtom::Type> {
451 static void enumeration(IO &io, lld::SharedLibraryAtom::Type &value) {
452 io.enumCase(value, "code", lld::SharedLibraryAtom::Type::Code);
453 io.enumCase(value, "data", lld::SharedLibraryAtom::Type::Data);
454 io.enumCase(value, "unknown", lld::SharedLibraryAtom::Type::Unknown);
458 /// This is a custom formatter for lld::DefinedAtom::Alignment. Values look
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,
465 if (value.modulus == 0) {
466 out << llvm::format("%d", value.value);
468 out << llvm::format("%d mod %d", value.modulus, value.value);
472 static StringRef input(StringRef scalar, void *ctxt,
473 lld::DefinedAtom::Alignment &value) {
475 size_t modStart = scalar.find("mod");
476 if (modStart != StringRef::npos) {
477 StringRef modStr = scalar.slice(0, modStart);
478 modStr = modStr.rtrim();
479 unsigned int modulus;
480 if (modStr.getAsInteger(0, modulus)) {
481 return "malformed alignment modulus";
483 value.modulus = modulus;
484 scalar = scalar.drop_front(modStart + 3);
485 scalar = scalar.ltrim();
488 if (scalar.getAsInteger(0, power)) {
489 return "malformed alignment power";
492 if (value.modulus >= power) {
493 return "malformed alignment, modulus too large for power";
495 return StringRef(); // returning empty string means success
498 static QuotingType mustQuote(StringRef) { return QuotingType::None; }
501 template <> struct ScalarEnumerationTraits<FileKinds> {
502 static void enumeration(IO &io, FileKinds &value) {
503 io.enumCase(value, "object", fileKindObjectAtoms);
504 io.enumCase(value, "archive", fileKindArchive);
505 io.enumCase(value, "object-mach-o", fileKindObjectMachO);
509 template <> struct MappingTraits<ArchMember> {
510 static void mapping(IO &io, ArchMember &member) {
511 io.mapOptional("kind", member._kind, fileKindObjectAtoms);
512 io.mapOptional("name", member._name);
513 io.mapRequired("content", member._content);
517 // Declare that an AtomList is a yaml sequence.
518 template <typename T> struct SequenceTraits<AtomList<T> > {
519 static size_t size(IO &io, AtomList<T> &seq) { return seq._atoms.size(); }
520 static T *&element(IO &io, AtomList<T> &seq, size_t index) {
521 if (index >= seq._atoms.size())
522 seq._atoms.resize(index + 1);
523 return seq._atoms[index].get();
527 // Declare that an AtomRange is a yaml sequence.
528 template <typename T> struct SequenceTraits<File::AtomRange<T> > {
529 static size_t size(IO &io, File::AtomRange<T> &seq) { return seq.size(); }
530 static T *&element(IO &io, File::AtomRange<T> &seq, size_t index) {
531 assert(io.outputting() && "AtomRange only used when outputting");
532 assert(index < seq.size() && "Out of range access");
533 return seq[index].get();
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 static void output(const ImplicitHex8 &val, void *, raw_ostream &out) {
542 out << llvm::format("%02X", num);
545 static StringRef input(StringRef str, void *, ImplicitHex8 &val) {
546 unsigned long long n;
547 if (getAsUnsignedInteger(str, 16, n))
548 return "invalid two-digit-hex number";
550 return "out of range two-digit-hex number";
552 return StringRef(); // returning empty string means success
555 static QuotingType mustQuote(StringRef) { return QuotingType::None; }
558 // YAML conversion for std::vector<const lld::File*>
559 template <> struct DocumentListTraits<std::vector<const lld::File *> > {
560 static size_t size(IO &io, std::vector<const lld::File *> &seq) {
563 static const lld::File *&element(IO &io, std::vector<const lld::File *> &seq,
565 if (index >= seq.size())
566 seq.resize(index + 1);
571 // YAML conversion for const lld::File*
572 template <> struct MappingTraits<const lld::File *> {
573 class NormArchiveFile : public lld::ArchiveLibraryFile {
575 NormArchiveFile(IO &io) : ArchiveLibraryFile("") {}
577 NormArchiveFile(IO &io, const lld::File *file)
578 : ArchiveLibraryFile(file->path()), _path(file->path()) {
579 // If we want to support writing archives, this constructor would
580 // need to populate _members.
583 const lld::File *denormalize(IO &io) { return this; }
585 const AtomRange<lld::DefinedAtom> defined() const override {
586 return _noDefinedAtoms;
589 const AtomRange<lld::UndefinedAtom> undefined() const override {
590 return _noUndefinedAtoms;
593 const AtomRange<lld::SharedLibraryAtom> sharedLibrary() const override {
594 return _noSharedLibraryAtoms;
597 const AtomRange<lld::AbsoluteAtom> absolute() const override {
598 return _noAbsoluteAtoms;
601 void clearAtoms() override {
602 _noDefinedAtoms.clear();
603 _noUndefinedAtoms.clear();
604 _noSharedLibraryAtoms.clear();
605 _noAbsoluteAtoms.clear();
608 File *find(StringRef name) override {
609 for (const ArchMember &member : _members)
610 for (const lld::DefinedAtom *atom : member._content->defined())
611 if (name == atom->name())
612 return const_cast<File *>(member._content);
617 parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
618 return std::error_code();
622 std::vector<ArchMember> _members;
625 class NormalizedFile : public lld::File {
627 NormalizedFile(IO &io)
628 : File("", kindNormalizedObject), _io(io), _rnb(nullptr),
629 _definedAtomsRef(_definedAtoms._atoms),
630 _undefinedAtomsRef(_undefinedAtoms._atoms),
631 _sharedLibraryAtomsRef(_sharedLibraryAtoms._atoms),
632 _absoluteAtomsRef(_absoluteAtoms._atoms) {}
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 _absoluteAtomsRef(file->absolute()) {
643 ~NormalizedFile() override {
646 const lld::File *denormalize(IO &io);
648 const AtomRange<lld::DefinedAtom> defined() const override {
649 return _definedAtomsRef;
652 const AtomRange<lld::UndefinedAtom> undefined() const override {
653 return _undefinedAtomsRef;
656 const AtomRange<lld::SharedLibraryAtom> sharedLibrary() const override {
657 return _sharedLibraryAtomsRef;
660 const AtomRange<lld::AbsoluteAtom> absolute() const override {
661 return _absoluteAtomsRef;
664 void clearAtoms() override {
665 _definedAtoms._atoms.clear();
666 _undefinedAtoms._atoms.clear();
667 _sharedLibraryAtoms._atoms.clear();
668 _absoluteAtoms._atoms.clear();
671 // Allocate a new copy of this string in _storage, so the strings
672 // can be freed when File is destroyed.
673 StringRef copyString(StringRef str) {
674 char *s = _storage.Allocate<char>(str.size());
675 memcpy(s, str.data(), str.size());
676 return StringRef(s, str.size());
680 std::unique_ptr<RefNameBuilder> _rnb;
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;
693 static void mapping(IO &io, const lld::File *&file) {
694 YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
695 assert(info != nullptr);
696 // Let any register tag handler process this.
697 if (info->_registry && info->_registry->handleTaggedDoc(io, file))
699 // If no registered handler claims this tag and there is no tag,
700 // grandfather in as "!native".
701 if (io.mapTag("!native", true) || io.mapTag("tag:yaml.org,2002:map"))
702 mappingAtoms(io, file);
705 static void mappingAtoms(IO &io, const lld::File *&file) {
706 YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
707 MappingNormalizationHeap<NormalizedFile, const lld::File *>
708 keys(io, file, nullptr);
709 assert(info != nullptr);
710 info->_file = keys.operator->();
712 io.mapOptional("path", keys->_path);
714 if (io.outputting()) {
715 io.mapOptional("defined-atoms", keys->_definedAtomsRef);
716 io.mapOptional("undefined-atoms", keys->_undefinedAtomsRef);
717 io.mapOptional("shared-library-atoms", keys->_sharedLibraryAtomsRef);
718 io.mapOptional("absolute-atoms", keys->_absoluteAtomsRef);
720 io.mapOptional("defined-atoms", keys->_definedAtoms);
721 io.mapOptional("undefined-atoms", keys->_undefinedAtoms);
722 io.mapOptional("shared-library-atoms", keys->_sharedLibraryAtoms);
723 io.mapOptional("absolute-atoms", keys->_absoluteAtoms);
727 static void mappingArchive(IO &io, const lld::File *&file) {
728 YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
729 MappingNormalizationHeap<NormArchiveFile, const lld::File *>
730 keys(io, file, &info->_file->allocator());
732 io.mapOptional("path", keys->_path);
733 io.mapOptional("members", keys->_members);
737 // YAML conversion for const lld::Reference*
738 template <> struct MappingTraits<const lld::Reference *> {
739 class NormalizedReference : public lld::Reference {
741 NormalizedReference(IO &io)
742 : lld::Reference(lld::Reference::KindNamespace::all,
743 lld::Reference::KindArch::all, 0),
744 _target(nullptr), _offset(0), _addend(0), _tag(0) {}
746 NormalizedReference(IO &io, const lld::Reference *ref)
747 : lld::Reference(ref->kindNamespace(), ref->kindArch(),
749 _target(nullptr), _targetName(targetName(io, ref)),
750 _offset(ref->offsetInAtom()), _addend(ref->addend()),
752 _mappedKind.ns = ref->kindNamespace();
753 _mappedKind.arch = ref->kindArch();
754 _mappedKind.value = ref->kindValue();
757 const lld::Reference *denormalize(IO &io) {
758 YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
759 assert(info != nullptr);
760 typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
761 NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
762 if (!_targetName.empty())
763 _targetName = f->copyString(_targetName);
764 DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
765 << "created Reference to name: '"
766 << _targetName << "' ("
767 << (const void *)_targetName.data()
768 << ", " << _targetName.size() << ")\n");
769 setKindNamespace(_mappedKind.ns);
770 setKindArch(_mappedKind.arch);
771 setKindValue(_mappedKind.value);
775 void bind(const RefNameResolver &);
776 static StringRef targetName(IO &io, const lld::Reference *ref);
778 uint64_t offsetInAtom() const override { return _offset; }
779 const lld::Atom *target() const override { return _target; }
780 Addend addend() const override { return _addend; }
781 void setAddend(Addend a) override { _addend = a; }
782 void setTarget(const lld::Atom *a) override { _target = a; }
784 const lld::Atom *_target;
785 StringRef _targetName;
792 static void mapping(IO &io, const lld::Reference *&ref) {
793 YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
794 MappingNormalizationHeap<NormalizedReference, const lld::Reference *> keys(
795 io, ref, &info->_file->allocator());
797 io.mapRequired("kind", keys->_mappedKind);
798 io.mapOptional("offset", keys->_offset);
799 io.mapOptional("target", keys->_targetName);
800 io.mapOptional("addend", keys->_addend, (lld::Reference::Addend)0);
801 io.mapOptional("tag", keys->_tag, 0u);
805 // YAML conversion for const lld::DefinedAtom*
806 template <> struct MappingTraits<const lld::DefinedAtom *> {
808 class NormalizedAtom : public lld::DefinedAtom {
810 NormalizedAtom(IO &io)
811 : _file(fileFromContext(io)), _contentType(), _alignment(1) {
812 static uint32_t ordinalCounter = 1;
813 _ordinal = ordinalCounter++;
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 _sectionSize(atom->sectionSize()) {
826 for (const lld::Reference *r : *atom)
827 _references.push_back(r);
828 if (!atom->occupiesDiskSpace())
830 ArrayRef<uint8_t> cont = atom->rawContent();
831 _content.reserve(cont.size());
832 for (uint8_t x : cont)
833 _content.push_back(x);
836 ~NormalizedAtom() override = default;
838 const lld::DefinedAtom *denormalize(IO &io) {
839 YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
840 assert(info != nullptr);
841 typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
842 NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
844 _name = f->copyString(_name);
845 if (!_refName.empty())
846 _refName = f->copyString(_refName);
847 if (!_sectionName.empty())
848 _sectionName = f->copyString(_sectionName);
849 DEBUG_WITH_TYPE("WriterYAML",
850 llvm::dbgs() << "created DefinedAtom named: '" << _name
851 << "' (" << (const void *)_name.data()
852 << ", " << _name.size() << ")\n");
856 void bind(const RefNameResolver &);
858 // Extract current File object from YAML I/O parsing context
859 const lld::File &fileFromContext(IO &io) {
860 YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
861 assert(info != nullptr);
862 assert(info->_file != nullptr);
866 const lld::File &file() const override { return _file; }
867 StringRef name() const override { return _name; }
868 uint64_t size() const override { return _size; }
869 Scope scope() const override { return _scope; }
870 Interposable interposable() const override { return _interpose; }
871 Merge merge() const override { return _merge; }
872 ContentType contentType() const override { return _contentType; }
873 Alignment alignment() const override { return _alignment; }
874 SectionChoice sectionChoice() const override { return _sectionChoice; }
875 StringRef customSectionName() const override { return _sectionName; }
876 uint64_t sectionSize() const override { return _sectionSize; }
877 DeadStripKind deadStrip() const override { return _deadStrip; }
878 DynamicExport dynamicExport() const override { return _dynamicExport; }
879 CodeModel codeModel() const override { return _codeModel; }
880 ContentPermissions permissions() const override { return _permissions; }
881 ArrayRef<uint8_t> rawContent() const override {
882 if (!occupiesDiskSpace())
883 return ArrayRef<uint8_t>();
884 return ArrayRef<uint8_t>(
885 reinterpret_cast<const uint8_t *>(_content.data()), _content.size());
888 uint64_t ordinal() const override { return _ordinal; }
890 reference_iterator begin() const override {
892 const void *it = reinterpret_cast<const void *>(index);
893 return reference_iterator(*this, it);
895 reference_iterator end() const override {
896 uintptr_t index = _references.size();
897 const void *it = reinterpret_cast<const void *>(index);
898 return reference_iterator(*this, it);
900 const lld::Reference *derefIterator(const void *it) const override {
901 uintptr_t index = reinterpret_cast<uintptr_t>(it);
902 assert(index < _references.size());
903 return _references[index];
905 void incrementIterator(const void *&it) const override {
906 uintptr_t index = reinterpret_cast<uintptr_t>(it);
908 it = reinterpret_cast<const void *>(index);
911 void addReference(Reference::KindNamespace ns,
912 Reference::KindArch arch,
913 Reference::KindValue kindValue, uint64_t off,
914 const Atom *target, Reference::Addend a) override {
915 assert(target && "trying to create reference to nothing");
916 auto node = new (file().allocator()) SimpleReference(ns, arch, kindValue,
918 _references.push_back(node);
921 const lld::File &_file;
925 Interposable _interpose;
927 ContentType _contentType;
928 Alignment _alignment;
929 SectionChoice _sectionChoice;
930 DeadStripKind _deadStrip;
931 DynamicExport _dynamicExport;
932 CodeModel _codeModel;
933 ContentPermissions _permissions;
935 std::vector<ImplicitHex8> _content;
937 StringRef _sectionName;
938 uint64_t _sectionSize;
939 std::vector<const lld::Reference *> _references;
942 static void mapping(IO &io, const lld::DefinedAtom *&atom) {
943 YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
944 MappingNormalizationHeap<NormalizedAtom, const lld::DefinedAtom *> keys(
945 io, atom, &info->_file->allocator());
946 if (io.outputting()) {
947 // If writing YAML, check if atom needs a ref-name.
948 typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
949 assert(info != nullptr);
950 NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
953 if (f->_rnb->hasRefName(atom)) {
954 keys->_refName = f->_rnb->refName(atom);
958 io.mapOptional("name", keys->_name, StringRef());
959 io.mapOptional("ref-name", keys->_refName, StringRef());
960 io.mapOptional("scope", keys->_scope,
961 DefinedAtom::scopeTranslationUnit);
962 io.mapOptional("type", keys->_contentType,
963 DefinedAtom::typeCode);
964 io.mapOptional("content", keys->_content);
965 io.mapOptional("size", keys->_size, (uint64_t)keys->_content.size());
966 io.mapOptional("interposable", keys->_interpose,
967 DefinedAtom::interposeNo);
968 io.mapOptional("merge", keys->_merge, DefinedAtom::mergeNo);
969 io.mapOptional("alignment", keys->_alignment,
970 DefinedAtom::Alignment(1));
971 io.mapOptional("section-choice", keys->_sectionChoice,
972 DefinedAtom::sectionBasedOnContent);
973 io.mapOptional("section-name", keys->_sectionName, StringRef());
974 io.mapOptional("section-size", keys->_sectionSize, (uint64_t)0);
975 io.mapOptional("dead-strip", keys->_deadStrip,
976 DefinedAtom::deadStripNormal);
977 io.mapOptional("dynamic-export", keys->_dynamicExport,
978 DefinedAtom::dynamicExportNormal);
979 io.mapOptional("code-model", keys->_codeModel, DefinedAtom::codeNA);
980 // default permissions based on content type
981 io.mapOptional("permissions", keys->_permissions,
982 DefinedAtom::permissions(
983 keys->_contentType));
984 io.mapOptional("references", keys->_references);
988 template <> struct MappingTraits<lld::DefinedAtom *> {
989 static void mapping(IO &io, lld::DefinedAtom *&atom) {
990 const lld::DefinedAtom *atomPtr = atom;
991 MappingTraits<const lld::DefinedAtom *>::mapping(io, atomPtr);
992 atom = const_cast<lld::DefinedAtom *>(atomPtr);
996 // YAML conversion for const lld::UndefinedAtom*
997 template <> struct MappingTraits<const lld::UndefinedAtom *> {
998 class NormalizedAtom : public lld::UndefinedAtom {
1000 NormalizedAtom(IO &io)
1001 : _file(fileFromContext(io)), _canBeNull(canBeNullNever) {}
1003 NormalizedAtom(IO &io, const lld::UndefinedAtom *atom)
1004 : _file(fileFromContext(io)), _name(atom->name()),
1005 _canBeNull(atom->canBeNull()) {}
1007 ~NormalizedAtom() override = default;
1009 const lld::UndefinedAtom *denormalize(IO &io) {
1010 YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
1011 assert(info != nullptr);
1012 typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
1013 NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
1015 _name = f->copyString(_name);
1017 DEBUG_WITH_TYPE("WriterYAML",
1018 llvm::dbgs() << "created UndefinedAtom named: '" << _name
1019 << "' (" << (const void *)_name.data() << ", "
1020 << _name.size() << ")\n");
1024 // Extract current File object from YAML I/O parsing context
1025 const lld::File &fileFromContext(IO &io) {
1026 YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
1027 assert(info != nullptr);
1028 assert(info->_file != nullptr);
1029 return *info->_file;
1032 const lld::File &file() const override { return _file; }
1033 StringRef name() const override { return _name; }
1034 CanBeNull canBeNull() const override { return _canBeNull; }
1036 const lld::File &_file;
1038 CanBeNull _canBeNull;
1041 static void mapping(IO &io, const lld::UndefinedAtom *&atom) {
1042 YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
1043 MappingNormalizationHeap<NormalizedAtom, const lld::UndefinedAtom *> keys(
1044 io, atom, &info->_file->allocator());
1046 io.mapRequired("name", keys->_name);
1047 io.mapOptional("can-be-null", keys->_canBeNull,
1048 lld::UndefinedAtom::canBeNullNever);
1052 template <> struct MappingTraits<lld::UndefinedAtom *> {
1053 static void mapping(IO &io, lld::UndefinedAtom *&atom) {
1054 const lld::UndefinedAtom *atomPtr = atom;
1055 MappingTraits<const lld::UndefinedAtom *>::mapping(io, atomPtr);
1056 atom = const_cast<lld::UndefinedAtom *>(atomPtr);
1060 // YAML conversion for const lld::SharedLibraryAtom*
1061 template <> struct MappingTraits<const lld::SharedLibraryAtom *> {
1062 class NormalizedAtom : public lld::SharedLibraryAtom {
1064 NormalizedAtom(IO &io)
1065 : _file(fileFromContext(io)), _canBeNull(false),
1066 _type(Type::Unknown), _size(0) {}
1068 NormalizedAtom(IO &io, const lld::SharedLibraryAtom *atom)
1069 : _file(fileFromContext(io)), _name(atom->name()),
1070 _loadName(atom->loadName()), _canBeNull(atom->canBeNullAtRuntime()),
1071 _type(atom->type()), _size(atom->size()) {}
1073 ~NormalizedAtom() override = default;
1075 const lld::SharedLibraryAtom *denormalize(IO &io) {
1076 YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
1077 assert(info != nullptr);
1078 typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
1079 NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
1081 _name = f->copyString(_name);
1082 if (!_loadName.empty())
1083 _loadName = f->copyString(_loadName);
1085 DEBUG_WITH_TYPE("WriterYAML",
1086 llvm::dbgs() << "created SharedLibraryAtom named: '"
1088 << (const void *)_name.data()
1089 << ", " << _name.size() << ")\n");
1093 // Extract current File object from YAML I/O parsing context
1094 const lld::File &fileFromContext(IO &io) {
1095 YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
1096 assert(info != nullptr);
1097 assert(info->_file != nullptr);
1098 return *info->_file;
1101 const lld::File &file() const override { return _file; }
1102 StringRef name() const override { return _name; }
1103 StringRef loadName() const override { return _loadName; }
1104 bool canBeNullAtRuntime() const override { return _canBeNull; }
1105 Type type() const override { return _type; }
1106 uint64_t size() const override { return _size; }
1108 const lld::File &_file;
1110 StringRef _loadName;
1111 ShlibCanBeNull _canBeNull;
1116 static void mapping(IO &io, const lld::SharedLibraryAtom *&atom) {
1118 YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
1119 MappingNormalizationHeap<NormalizedAtom, const lld::SharedLibraryAtom *>
1120 keys(io, atom, &info->_file->allocator());
1122 io.mapRequired("name", keys->_name);
1123 io.mapOptional("load-name", keys->_loadName);
1124 io.mapOptional("can-be-null", keys->_canBeNull, (ShlibCanBeNull) false);
1125 io.mapOptional("type", keys->_type, SharedLibraryAtom::Type::Code);
1126 io.mapOptional("size", keys->_size, uint64_t(0));
1130 template <> struct MappingTraits<lld::SharedLibraryAtom *> {
1131 static void mapping(IO &io, lld::SharedLibraryAtom *&atom) {
1132 const lld::SharedLibraryAtom *atomPtr = atom;
1133 MappingTraits<const lld::SharedLibraryAtom *>::mapping(io, atomPtr);
1134 atom = const_cast<lld::SharedLibraryAtom *>(atomPtr);
1138 // YAML conversion for const lld::AbsoluteAtom*
1139 template <> struct MappingTraits<const lld::AbsoluteAtom *> {
1140 class NormalizedAtom : public lld::AbsoluteAtom {
1142 NormalizedAtom(IO &io)
1143 : _file(fileFromContext(io)), _scope(), _value(0) {}
1145 NormalizedAtom(IO &io, const lld::AbsoluteAtom *atom)
1146 : _file(fileFromContext(io)), _name(atom->name()),
1147 _scope(atom->scope()), _value(atom->value()) {}
1149 ~NormalizedAtom() override = default;
1151 const lld::AbsoluteAtom *denormalize(IO &io) {
1152 YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
1153 assert(info != nullptr);
1154 typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
1155 NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
1157 _name = f->copyString(_name);
1159 DEBUG_WITH_TYPE("WriterYAML",
1160 llvm::dbgs() << "created AbsoluteAtom named: '" << _name
1161 << "' (" << (const void *)_name.data()
1162 << ", " << _name.size() << ")\n");
1166 // Extract current File object from YAML I/O parsing context
1167 const lld::File &fileFromContext(IO &io) {
1168 YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
1169 assert(info != nullptr);
1170 assert(info->_file != nullptr);
1171 return *info->_file;
1174 const lld::File &file() const override { return _file; }
1175 StringRef name() const override { return _name; }
1176 uint64_t value() const override { return _value; }
1177 Scope scope() const override { return _scope; }
1179 const lld::File &_file;
1186 static void mapping(IO &io, const lld::AbsoluteAtom *&atom) {
1187 YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
1188 MappingNormalizationHeap<NormalizedAtom, const lld::AbsoluteAtom *> keys(
1189 io, atom, &info->_file->allocator());
1191 if (io.outputting()) {
1192 typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
1193 YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
1194 assert(info != nullptr);
1195 NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
1198 if (f->_rnb->hasRefName(atom)) {
1199 keys->_refName = f->_rnb->refName(atom);
1203 io.mapRequired("name", keys->_name);
1204 io.mapOptional("ref-name", keys->_refName, StringRef());
1205 io.mapOptional("scope", keys->_scope);
1206 io.mapRequired("value", keys->_value);
1210 template <> struct MappingTraits<lld::AbsoluteAtom *> {
1211 static void mapping(IO &io, lld::AbsoluteAtom *&atom) {
1212 const lld::AbsoluteAtom *atomPtr = atom;
1213 MappingTraits<const lld::AbsoluteAtom *>::mapping(io, atomPtr);
1214 atom = const_cast<lld::AbsoluteAtom *>(atomPtr);
1218 } // end namespace llvm
1219 } // end namespace yaml
1221 RefNameResolver::RefNameResolver(const lld::File *file, IO &io) : _io(io) {
1222 typedef MappingTraits<const lld::DefinedAtom *>::NormalizedAtom
1224 for (const lld::DefinedAtom *a : file->defined()) {
1225 const auto *na = (const NormalizedAtom *)a;
1226 if (!na->_refName.empty())
1227 add(na->_refName, a);
1228 else if (!na->_name.empty())
1232 for (const lld::UndefinedAtom *a : file->undefined())
1235 for (const lld::SharedLibraryAtom *a : file->sharedLibrary())
1238 typedef MappingTraits<const lld::AbsoluteAtom *>::NormalizedAtom NormAbsAtom;
1239 for (const lld::AbsoluteAtom *a : file->absolute()) {
1240 const auto *na = (const NormAbsAtom *)a;
1241 if (na->_refName.empty())
1244 add(na->_refName, a);
1248 inline const lld::File *
1249 MappingTraits<const lld::File *>::NormalizedFile::denormalize(IO &io) {
1250 typedef MappingTraits<const lld::DefinedAtom *>::NormalizedAtom
1253 RefNameResolver nameResolver(this, io);
1254 // Now that all atoms are parsed, references can be bound.
1255 for (const lld::DefinedAtom *a : this->defined()) {
1256 auto *normAtom = (NormalizedAtom *)const_cast<DefinedAtom *>(a);
1257 normAtom->bind(nameResolver);
1263 inline void MappingTraits<const lld::DefinedAtom *>::NormalizedAtom::bind(
1264 const RefNameResolver &resolver) {
1265 typedef MappingTraits<const lld::Reference *>::NormalizedReference
1266 NormalizedReference;
1267 for (const lld::Reference *ref : _references) {
1268 auto *normRef = (NormalizedReference *)const_cast<Reference *>(ref);
1269 normRef->bind(resolver);
1273 inline void MappingTraits<const lld::Reference *>::NormalizedReference::bind(
1274 const RefNameResolver &resolver) {
1275 _target = resolver.lookup(_targetName);
1279 MappingTraits<const lld::Reference *>::NormalizedReference::targetName(
1280 IO &io, const lld::Reference *ref) {
1281 if (ref->target() == nullptr)
1283 YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
1284 assert(info != nullptr);
1285 typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
1286 NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
1287 RefNameBuilder &rnb = *f->_rnb;
1288 if (rnb.hasRefName(ref->target()))
1289 return rnb.refName(ref->target());
1290 return ref->target()->name();
1296 class Writer : public lld::Writer {
1298 Writer(const LinkingContext &context) : _ctx(context) {}
1300 llvm::Error writeFile(const lld::File &file, StringRef outPath) override {
1301 // Create stream to path.
1303 llvm::raw_fd_ostream out(outPath, ec, llvm::sys::fs::F_Text);
1305 return llvm::errorCodeToError(ec);
1307 // Create yaml Output writer, using yaml options for context.
1308 YamlContext yamlContext;
1309 yamlContext._ctx = &_ctx;
1310 yamlContext._registry = &_ctx.registry();
1311 llvm::yaml::Output yout(out, &yamlContext);
1313 // Write yaml output.
1314 const lld::File *fileRef = &file;
1317 return llvm::Error::success();
1321 const LinkingContext &_ctx;
1324 } // end namespace yaml
1328 /// Handles !native tagged yaml documents.
1329 class NativeYamlIOTaggedDocumentHandler : public YamlIOTaggedDocumentHandler {
1330 bool handledDocTag(llvm::yaml::IO &io, const lld::File *&file) const override {
1331 if (io.mapTag("!native")) {
1332 MappingTraits<const lld::File *>::mappingAtoms(io, file);
1339 /// Handles !archive tagged yaml documents.
1340 class ArchiveYamlIOTaggedDocumentHandler : public YamlIOTaggedDocumentHandler {
1341 bool handledDocTag(llvm::yaml::IO &io, const lld::File *&file) const override {
1342 if (io.mapTag("!archive")) {
1343 MappingTraits<const lld::File *>::mappingArchive(io, file);
1350 class YAMLReader : public Reader {
1352 YAMLReader(const Registry ®istry) : _registry(registry) {}
1354 bool canParse(file_magic magic, MemoryBufferRef mb) const override {
1355 StringRef name = mb.getBufferIdentifier();
1356 return name.endswith(".objtxt") || name.endswith(".yaml");
1359 ErrorOr<std::unique_ptr<File>>
1360 loadFile(std::unique_ptr<MemoryBuffer> mb,
1361 const class Registry &) const override {
1362 // Create YAML Input Reader.
1363 YamlContext yamlContext;
1364 yamlContext._registry = &_registry;
1365 yamlContext._path = mb->getBufferIdentifier();
1366 llvm::yaml::Input yin(mb->getBuffer(), &yamlContext);
1368 // Fill vector with File objects created by parsing yaml.
1369 std::vector<const lld::File *> createdFiles;
1370 yin >> createdFiles;
1371 assert(createdFiles.size() == 1);
1373 // Error out now if there were parsing errors.
1375 return make_error_code(lld::YamlReaderError::illegal_value);
1377 std::shared_ptr<MemoryBuffer> smb(mb.release());
1378 const File *file = createdFiles[0];
1379 // Note: loadFile() should return vector of *const* File
1380 File *f = const_cast<File *>(file);
1381 f->setLastError(std::error_code());
1382 f->setSharedMemoryBuffer(smb);
1383 return std::unique_ptr<File>(f);
1387 const Registry &_registry;
1390 } // end anonymous namespace
1392 void Registry::addSupportYamlFiles() {
1393 add(std::unique_ptr<Reader>(new YAMLReader(*this)));
1394 add(std::unique_ptr<YamlIOTaggedDocumentHandler>(
1395 new NativeYamlIOTaggedDocumentHandler()));
1396 add(std::unique_ptr<YamlIOTaggedDocumentHandler>(
1397 new ArchiveYamlIOTaggedDocumentHandler()));
1400 std::unique_ptr<Writer> createWriterYAML(const LinkingContext &context) {
1401 return std::unique_ptr<Writer>(new lld::yaml::Writer(context));
1404 } // end namespace lld