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