1 //===- lib/ReaderWriter/YAML/ReaderWriterYAML.cpp -------------------------===// 2 // 3 // The LLVM Linker 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "lld/Core/AbsoluteAtom.h" 11 #include "lld/Core/ArchiveLibraryFile.h" 12 #include "lld/Core/Atom.h" 13 #include "lld/Core/DefinedAtom.h" 14 #include "lld/Core/Error.h" 15 #include "lld/Core/File.h" 16 #include "lld/Core/LinkingContext.h" 17 #include "lld/Core/Reader.h" 18 #include "lld/Core/Reference.h" 19 #include "lld/Core/SharedLibraryAtom.h" 20 #include "lld/Core/Simple.h" 21 #include "lld/Core/UndefinedAtom.h" 22 #include "lld/Core/Writer.h" 23 #include "lld/ReaderWriter/YamlContext.h" 24 #include "llvm/ADT/ArrayRef.h" 25 #include "llvm/ADT/DenseMap.h" 26 #include "llvm/ADT/StringMap.h" 27 #include "llvm/ADT/StringRef.h" 28 #include "llvm/ADT/Twine.h" 29 #include "llvm/BinaryFormat/Magic.h" 30 #include "llvm/Support/Allocator.h" 31 #include "llvm/Support/Debug.h" 32 #include "llvm/Support/Error.h" 33 #include "llvm/Support/ErrorOr.h" 34 #include "llvm/Support/FileSystem.h" 35 #include "llvm/Support/Format.h" 36 #include "llvm/Support/MemoryBuffer.h" 37 #include "llvm/Support/YAMLTraits.h" 38 #include "llvm/Support/raw_ostream.h" 39 #include <cassert> 40 #include <cstdint> 41 #include <cstring> 42 #include <memory> 43 #include <string> 44 #include <system_error> 45 #include <vector> 46 47 using llvm::file_magic; 48 using llvm::yaml::MappingTraits; 49 using llvm::yaml::ScalarEnumerationTraits; 50 using llvm::yaml::ScalarTraits; 51 using llvm::yaml::IO; 52 using llvm::yaml::SequenceTraits; 53 using llvm::yaml::DocumentListTraits; 54 55 using namespace lld; 56 57 /// The conversion of Atoms to and from YAML uses LLVM's YAML I/O. This 58 /// file just defines template specializations on the lld types which control 59 /// how the mapping is done to and from YAML. 60 61 namespace { 62 63 /// Used when writing yaml files. 64 /// In most cases, atoms names are unambiguous, so references can just 65 /// use the atom name as the target (e.g. target: foo). But in a few 66 /// cases that does not work, so ref-names are added. These are labels 67 /// used only in yaml. The labels do not exist in the Atom model. 68 /// 69 /// One need for ref-names are when atoms have no user supplied name 70 /// (e.g. c-string literal). Another case is when two object files with 71 /// identically named static functions are merged (ld -r) into one object file. 72 /// In that case referencing the function by name is ambiguous, so a unique 73 /// ref-name is added. 74 class RefNameBuilder { 75 public: 76 RefNameBuilder(const lld::File &file) 77 : _collisionCount(0), _unnamedCounter(0) { 78 // visit all atoms 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); 83 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()) { 89 std::string storage; 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: '" 96 << newName << "' (" 97 << (const void *)newName.data() << ", " 98 << newName.size() << ")\n"); 99 } 100 } 101 } 102 for (const lld::UndefinedAtom *undefAtom : file.undefined()) { 103 buildDuplicateNameMap(*undefAtom); 104 } 105 for (const lld::SharedLibraryAtom *shlibAtom : file.sharedLibrary()) { 106 buildDuplicateNameMap(*shlibAtom); 107 } 108 for (const lld::AbsoluteAtom *absAtom : file.absolute()) { 109 if (!absAtom->name().empty()) 110 buildDuplicateNameMap(*absAtom); 111 } 112 } 113 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. 119 std::string Storage; 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: '" 126 << newName << "' (" 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: '" 140 << newName2 << "' (" 141 << (const void *)newName2.data() << ", " 142 << newName2.size() << ")\n"); 143 } 144 } else { 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"); 152 } 153 } 154 155 bool hasRefName(const lld::Atom *atom) { return _refNames.count(atom); } 156 157 StringRef refName(const lld::Atom *atom) { 158 return _refNames.find(atom)->second; 159 } 160 161 private: 162 typedef llvm::StringMap<const lld::Atom *> NameToAtom; 163 typedef llvm::DenseMap<const lld::Atom *, std::string> AtomToRefName; 164 165 // Allocate a new copy of this string in _storage, so the strings 166 // can be freed when RefNameBuilder is destroyed. 167 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()); 171 } 172 173 unsigned int _collisionCount; 174 unsigned int _unnamedCounter; 175 NameToAtom _nameMap; 176 AtomToRefName _refNames; 177 llvm::BumpPtrAllocator _storage; 178 }; 179 180 /// Used when reading yaml files to find the target of a reference 181 /// that could be a name or ref-name. 182 class RefNameResolver { 183 public: 184 RefNameResolver(const lld::File *file, IO &io); 185 186 const lld::Atom *lookup(StringRef name) const { 187 NameToAtom::const_iterator pos = _nameMap.find(name); 188 if (pos != _nameMap.end()) 189 return pos->second; 190 _io.setError(Twine("no such atom name: ") + name); 191 return nullptr; 192 } 193 194 private: 195 typedef llvm::StringMap<const lld::Atom *> NameToAtom; 196 197 void add(StringRef name, const lld::Atom *atom) { 198 if (_nameMap.count(name)) { 199 _io.setError(Twine("duplicate atom name: ") + name); 200 } else { 201 _nameMap[name] = atom; 202 } 203 } 204 205 IO &_io; 206 NameToAtom _nameMap; 207 }; 208 209 /// Mapping of Atoms. 210 template <typename T> class AtomList { 211 using Ty = std::vector<OwningAtomPtr<T>>; 212 213 public: 214 typename Ty::iterator begin() { return _atoms.begin(); } 215 typename Ty::iterator end() { return _atoms.end(); } 216 Ty _atoms; 217 }; 218 219 /// Mapping of kind: field in yaml files. 220 enum FileKinds { 221 fileKindObjectAtoms, // atom based object file encoded in yaml 222 fileKindArchive, // static archive library encoded in yaml 223 fileKindObjectMachO // mach-o object files encoded in yaml 224 }; 225 226 struct ArchMember { 227 FileKinds _kind; 228 StringRef _name; 229 const lld::File *_content; 230 }; 231 232 // The content bytes in a DefinedAtom are just uint8_t but we want 233 // special formatting, so define a strong type. 234 LLVM_YAML_STRONG_TYPEDEF(uint8_t, ImplicitHex8) 235 236 // SharedLibraryAtoms have a bool canBeNull() method which we'd like to be 237 // more readable than just true/false. 238 LLVM_YAML_STRONG_TYPEDEF(bool, ShlibCanBeNull) 239 240 // lld::Reference::Kind is a tuple of <namespace, arch, value>. 241 // For yaml, we just want one string that encapsulates the tuple. 242 struct RefKind { 243 Reference::KindNamespace ns; 244 Reference::KindArch arch; 245 Reference::KindValue value; 246 }; 247 248 } // end anonymous namespace 249 250 LLVM_YAML_IS_SEQUENCE_VECTOR(ArchMember) 251 LLVM_YAML_IS_SEQUENCE_VECTOR(const lld::Reference *) 252 // Always write DefinedAtoms content bytes as a flow sequence. 253 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(ImplicitHex8) 254 255 // for compatibility with gcc-4.7 in C++11 mode, add extra namespace 256 namespace llvm { 257 namespace yaml { 258 259 // This is a custom formatter for RefKind 260 template <> struct ScalarTraits<RefKind> { 261 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); 265 StringRef str; 266 if (info->_registry->referenceKindToString(kind.ns, kind.arch, kind.value, 267 str)) 268 out << str; 269 else 270 out << (int)(kind.ns) << "-" << (int)(kind.arch) << "-" << kind.value; 271 } 272 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, 278 kind.value)) 279 return StringRef(); 280 return StringRef("unknown reference kind"); 281 } 282 283 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 284 }; 285 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); 292 } 293 }; 294 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); 300 } 301 }; 302 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); 309 } 310 }; 311 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); 317 } 318 }; 319 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); 331 } 332 }; 333 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); 339 } 340 }; 341 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); 346 } 347 }; 348 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); 360 } 361 }; 362 363 template <> 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); 373 } 374 }; 375 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); 431 } 432 }; 433 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); 439 } 440 }; 441 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); 446 } 447 }; 448 449 template <> 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); 455 } 456 }; 457 458 /// This is a custom formatter for lld::DefinedAtom::Alignment. Values look 459 /// like: 460 /// 8 # 8-byte aligned 461 /// 7 mod 16 # 16-byte aligned plus 7 bytes 462 template <> struct ScalarTraits<lld::DefinedAtom::Alignment> { 463 static void output(const lld::DefinedAtom::Alignment &value, void *ctxt, 464 raw_ostream &out) { 465 if (value.modulus == 0) { 466 out << llvm::format("%d", value.value); 467 } else { 468 out << llvm::format("%d mod %d", value.modulus, value.value); 469 } 470 } 471 472 static StringRef input(StringRef scalar, void *ctxt, 473 lld::DefinedAtom::Alignment &value) { 474 value.modulus = 0; 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"; 482 } 483 value.modulus = modulus; 484 scalar = scalar.drop_front(modStart + 3); 485 scalar = scalar.ltrim(); 486 } 487 unsigned int power; 488 if (scalar.getAsInteger(0, power)) { 489 return "malformed alignment power"; 490 } 491 value.value = power; 492 if (value.modulus >= power) { 493 return "malformed alignment, modulus too large for power"; 494 } 495 return StringRef(); // returning empty string means success 496 } 497 498 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 499 }; 500 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); 506 } 507 }; 508 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); 514 } 515 }; 516 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(); 524 } 525 }; 526 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(); 534 } 535 }; 536 537 // Used to allow DefinedAtom content bytes to be a flow sequence of 538 // two-digit hex numbers without the leading 0x (e.g. FF, 04, 0A) 539 template <> struct ScalarTraits<ImplicitHex8> { 540 static void output(const ImplicitHex8 &val, void *, raw_ostream &out) { 541 uint8_t num = val; 542 out << llvm::format("%02X", num); 543 } 544 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"; 549 if (n > 0xFF) 550 return "out of range two-digit-hex number"; 551 val = n; 552 return StringRef(); // returning empty string means success 553 } 554 555 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 556 }; 557 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) { 561 return seq.size(); 562 } 563 static const lld::File *&element(IO &io, std::vector<const lld::File *> &seq, 564 size_t index) { 565 if (index >= seq.size()) 566 seq.resize(index + 1); 567 return seq[index]; 568 } 569 }; 570 571 // YAML conversion for const lld::File* 572 template <> struct MappingTraits<const lld::File *> { 573 class NormArchiveFile : public lld::ArchiveLibraryFile { 574 public: 575 NormArchiveFile(IO &io) : ArchiveLibraryFile("") {} 576 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. 581 } 582 583 const lld::File *denormalize(IO &io) { return this; } 584 585 const AtomRange<lld::DefinedAtom> defined() const override { 586 return _noDefinedAtoms; 587 } 588 589 const AtomRange<lld::UndefinedAtom> undefined() const override { 590 return _noUndefinedAtoms; 591 } 592 593 const AtomRange<lld::SharedLibraryAtom> sharedLibrary() const override { 594 return _noSharedLibraryAtoms; 595 } 596 597 const AtomRange<lld::AbsoluteAtom> absolute() const override { 598 return _noAbsoluteAtoms; 599 } 600 601 void clearAtoms() override { 602 _noDefinedAtoms.clear(); 603 _noUndefinedAtoms.clear(); 604 _noSharedLibraryAtoms.clear(); 605 _noAbsoluteAtoms.clear(); 606 } 607 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); 613 return nullptr; 614 } 615 616 std::error_code 617 parseAllMembers(std::vector<std::unique_ptr<File>> &result) override { 618 return std::error_code(); 619 } 620 621 StringRef _path; 622 std::vector<ArchMember> _members; 623 }; 624 625 class NormalizedFile : public lld::File { 626 public: 627 NormalizedFile(IO &io) 628 : File("", kindNormalizedObject), _io(io), _rnb(nullptr), 629 _definedAtomsRef(_definedAtoms._atoms), 630 _undefinedAtomsRef(_undefinedAtoms._atoms), 631 _sharedLibraryAtomsRef(_sharedLibraryAtoms._atoms), 632 _absoluteAtomsRef(_absoluteAtoms._atoms) {} 633 634 NormalizedFile(IO &io, const lld::File *file) 635 : File(file->path(), kindNormalizedObject), _io(io), 636 _rnb(new RefNameBuilder(*file)), _path(file->path()), 637 _definedAtomsRef(file->defined()), 638 _undefinedAtomsRef(file->undefined()), 639 _sharedLibraryAtomsRef(file->sharedLibrary()), 640 _absoluteAtomsRef(file->absolute()) { 641 } 642 643 ~NormalizedFile() override { 644 } 645 646 const lld::File *denormalize(IO &io); 647 648 const AtomRange<lld::DefinedAtom> defined() const override { 649 return _definedAtomsRef; 650 } 651 652 const AtomRange<lld::UndefinedAtom> undefined() const override { 653 return _undefinedAtomsRef; 654 } 655 656 const AtomRange<lld::SharedLibraryAtom> sharedLibrary() const override { 657 return _sharedLibraryAtomsRef; 658 } 659 660 const AtomRange<lld::AbsoluteAtom> absolute() const override { 661 return _absoluteAtomsRef; 662 } 663 664 void clearAtoms() override { 665 _definedAtoms._atoms.clear(); 666 _undefinedAtoms._atoms.clear(); 667 _sharedLibraryAtoms._atoms.clear(); 668 _absoluteAtoms._atoms.clear(); 669 } 670 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()); 677 } 678 679 IO &_io; 680 std::unique_ptr<RefNameBuilder> _rnb; 681 StringRef _path; 682 AtomList<lld::DefinedAtom> _definedAtoms; 683 AtomList<lld::UndefinedAtom> _undefinedAtoms; 684 AtomList<lld::SharedLibraryAtom> _sharedLibraryAtoms; 685 AtomList<lld::AbsoluteAtom> _absoluteAtoms; 686 AtomRange<lld::DefinedAtom> _definedAtomsRef; 687 AtomRange<lld::UndefinedAtom> _undefinedAtomsRef; 688 AtomRange<lld::SharedLibraryAtom> _sharedLibraryAtomsRef; 689 AtomRange<lld::AbsoluteAtom> _absoluteAtomsRef; 690 llvm::BumpPtrAllocator _storage; 691 }; 692 693 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)) 698 return; 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); 703 } 704 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->(); 711 712 io.mapOptional("path", keys->_path); 713 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); 719 } else { 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); 724 } 725 } 726 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()); 731 732 io.mapOptional("path", keys->_path); 733 io.mapOptional("members", keys->_members); 734 } 735 }; 736 737 // YAML conversion for const lld::Reference* 738 template <> struct MappingTraits<const lld::Reference *> { 739 class NormalizedReference : public lld::Reference { 740 public: 741 NormalizedReference(IO &io) 742 : lld::Reference(lld::Reference::KindNamespace::all, 743 lld::Reference::KindArch::all, 0), 744 _target(nullptr), _offset(0), _addend(0), _tag(0) {} 745 746 NormalizedReference(IO &io, const lld::Reference *ref) 747 : lld::Reference(ref->kindNamespace(), ref->kindArch(), 748 ref->kindValue()), 749 _target(nullptr), _targetName(targetName(io, ref)), 750 _offset(ref->offsetInAtom()), _addend(ref->addend()), 751 _tag(ref->tag()) { 752 _mappedKind.ns = ref->kindNamespace(); 753 _mappedKind.arch = ref->kindArch(); 754 _mappedKind.value = ref->kindValue(); 755 } 756 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); 772 return this; 773 } 774 775 void bind(const RefNameResolver &); 776 static StringRef targetName(IO &io, const lld::Reference *ref); 777 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; } 783 784 const lld::Atom *_target; 785 StringRef _targetName; 786 uint32_t _offset; 787 Addend _addend; 788 RefKind _mappedKind; 789 uint32_t _tag; 790 }; 791 792 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()); 796 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); 802 } 803 }; 804 805 // YAML conversion for const lld::DefinedAtom* 806 template <> struct MappingTraits<const lld::DefinedAtom *> { 807 808 class NormalizedAtom : public lld::DefinedAtom { 809 public: 810 NormalizedAtom(IO &io) 811 : _file(fileFromContext(io)), _contentType(), _alignment(1) { 812 static uint32_t ordinalCounter = 1; 813 _ordinal = ordinalCounter++; 814 } 815 816 NormalizedAtom(IO &io, const lld::DefinedAtom *atom) 817 : _file(fileFromContext(io)), _name(atom->name()), 818 _scope(atom->scope()), _interpose(atom->interposable()), 819 _merge(atom->merge()), _contentType(atom->contentType()), 820 _alignment(atom->alignment()), _sectionChoice(atom->sectionChoice()), 821 _deadStrip(atom->deadStrip()), _dynamicExport(atom->dynamicExport()), 822 _codeModel(atom->codeModel()), 823 _permissions(atom->permissions()), _size(atom->size()), 824 _sectionName(atom->customSectionName()), 825 _sectionSize(atom->sectionSize()) { 826 for (const lld::Reference *r : *atom) 827 _references.push_back(r); 828 if (!atom->occupiesDiskSpace()) 829 return; 830 ArrayRef<uint8_t> cont = atom->rawContent(); 831 _content.reserve(cont.size()); 832 for (uint8_t x : cont) 833 _content.push_back(x); 834 } 835 836 ~NormalizedAtom() override = default; 837 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); 843 if (!_name.empty()) 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"); 853 return this; 854 } 855 856 void bind(const RefNameResolver &); 857 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); 863 return *info->_file; 864 } 865 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()); 886 } 887 888 uint64_t ordinal() const override { return _ordinal; } 889 890 reference_iterator begin() const override { 891 uintptr_t index = 0; 892 const void *it = reinterpret_cast<const void *>(index); 893 return reference_iterator(*this, it); 894 } 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); 899 } 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]; 904 } 905 void incrementIterator(const void *&it) const override { 906 uintptr_t index = reinterpret_cast<uintptr_t>(it); 907 ++index; 908 it = reinterpret_cast<const void *>(index); 909 } 910 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, 917 off, target, a); 918 _references.push_back(node); 919 } 920 921 const lld::File &_file; 922 StringRef _name; 923 StringRef _refName; 924 Scope _scope; 925 Interposable _interpose; 926 Merge _merge; 927 ContentType _contentType; 928 Alignment _alignment; 929 SectionChoice _sectionChoice; 930 DeadStripKind _deadStrip; 931 DynamicExport _dynamicExport; 932 CodeModel _codeModel; 933 ContentPermissions _permissions; 934 uint32_t _ordinal; 935 std::vector<ImplicitHex8> _content; 936 uint64_t _size; 937 StringRef _sectionName; 938 uint64_t _sectionSize; 939 std::vector<const lld::Reference *> _references; 940 }; 941 942 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); 951 assert(f); 952 assert(f->_rnb); 953 if (f->_rnb->hasRefName(atom)) { 954 keys->_refName = f->_rnb->refName(atom); 955 } 956 } 957 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); 985 } 986 }; 987 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); 993 } 994 }; 995 996 // YAML conversion for const lld::UndefinedAtom* 997 template <> struct MappingTraits<const lld::UndefinedAtom *> { 998 class NormalizedAtom : public lld::UndefinedAtom { 999 public: 1000 NormalizedAtom(IO &io) 1001 : _file(fileFromContext(io)), _canBeNull(canBeNullNever) {} 1002 1003 NormalizedAtom(IO &io, const lld::UndefinedAtom *atom) 1004 : _file(fileFromContext(io)), _name(atom->name()), 1005 _canBeNull(atom->canBeNull()) {} 1006 1007 ~NormalizedAtom() override = default; 1008 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); 1014 if (!_name.empty()) 1015 _name = f->copyString(_name); 1016 1017 DEBUG_WITH_TYPE("WriterYAML", 1018 llvm::dbgs() << "created UndefinedAtom named: '" << _name 1019 << "' (" << (const void *)_name.data() << ", " 1020 << _name.size() << ")\n"); 1021 return this; 1022 } 1023 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; 1030 } 1031 1032 const lld::File &file() const override { return _file; } 1033 StringRef name() const override { return _name; } 1034 CanBeNull canBeNull() const override { return _canBeNull; } 1035 1036 const lld::File &_file; 1037 StringRef _name; 1038 CanBeNull _canBeNull; 1039 }; 1040 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()); 1045 1046 io.mapRequired("name", keys->_name); 1047 io.mapOptional("can-be-null", keys->_canBeNull, 1048 lld::UndefinedAtom::canBeNullNever); 1049 } 1050 }; 1051 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); 1057 } 1058 }; 1059 1060 // YAML conversion for const lld::SharedLibraryAtom* 1061 template <> struct MappingTraits<const lld::SharedLibraryAtom *> { 1062 class NormalizedAtom : public lld::SharedLibraryAtom { 1063 public: 1064 NormalizedAtom(IO &io) 1065 : _file(fileFromContext(io)), _canBeNull(false), 1066 _type(Type::Unknown), _size(0) {} 1067 1068 NormalizedAtom(IO &io, const lld::SharedLibraryAtom *atom) 1069 : _file(fileFromContext(io)), _name(atom->name()), 1070 _loadName(atom->loadName()), _canBeNull(atom->canBeNullAtRuntime()), 1071 _type(atom->type()), _size(atom->size()) {} 1072 1073 ~NormalizedAtom() override = default; 1074 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); 1080 if (!_name.empty()) 1081 _name = f->copyString(_name); 1082 if (!_loadName.empty()) 1083 _loadName = f->copyString(_loadName); 1084 1085 DEBUG_WITH_TYPE("WriterYAML", 1086 llvm::dbgs() << "created SharedLibraryAtom named: '" 1087 << _name << "' (" 1088 << (const void *)_name.data() 1089 << ", " << _name.size() << ")\n"); 1090 return this; 1091 } 1092 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; 1099 } 1100 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; } 1107 1108 const lld::File &_file; 1109 StringRef _name; 1110 StringRef _loadName; 1111 ShlibCanBeNull _canBeNull; 1112 Type _type; 1113 uint64_t _size; 1114 }; 1115 1116 static void mapping(IO &io, const lld::SharedLibraryAtom *&atom) { 1117 1118 YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext()); 1119 MappingNormalizationHeap<NormalizedAtom, const lld::SharedLibraryAtom *> 1120 keys(io, atom, &info->_file->allocator()); 1121 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)); 1127 } 1128 }; 1129 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); 1135 } 1136 }; 1137 1138 // YAML conversion for const lld::AbsoluteAtom* 1139 template <> struct MappingTraits<const lld::AbsoluteAtom *> { 1140 class NormalizedAtom : public lld::AbsoluteAtom { 1141 public: 1142 NormalizedAtom(IO &io) 1143 : _file(fileFromContext(io)), _scope(), _value(0) {} 1144 1145 NormalizedAtom(IO &io, const lld::AbsoluteAtom *atom) 1146 : _file(fileFromContext(io)), _name(atom->name()), 1147 _scope(atom->scope()), _value(atom->value()) {} 1148 1149 ~NormalizedAtom() override = default; 1150 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); 1156 if (!_name.empty()) 1157 _name = f->copyString(_name); 1158 1159 DEBUG_WITH_TYPE("WriterYAML", 1160 llvm::dbgs() << "created AbsoluteAtom named: '" << _name 1161 << "' (" << (const void *)_name.data() 1162 << ", " << _name.size() << ")\n"); 1163 return this; 1164 } 1165 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; 1172 } 1173 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; } 1178 1179 const lld::File &_file; 1180 StringRef _name; 1181 StringRef _refName; 1182 Scope _scope; 1183 Hex64 _value; 1184 }; 1185 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()); 1190 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); 1196 assert(f); 1197 assert(f->_rnb); 1198 if (f->_rnb->hasRefName(atom)) { 1199 keys->_refName = f->_rnb->refName(atom); 1200 } 1201 } 1202 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); 1207 } 1208 }; 1209 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); 1215 } 1216 }; 1217 1218 } // end namespace llvm 1219 } // end namespace yaml 1220 1221 RefNameResolver::RefNameResolver(const lld::File *file, IO &io) : _io(io) { 1222 typedef MappingTraits<const lld::DefinedAtom *>::NormalizedAtom 1223 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()) 1229 add(na->_name, a); 1230 } 1231 1232 for (const lld::UndefinedAtom *a : file->undefined()) 1233 add(a->name(), a); 1234 1235 for (const lld::SharedLibraryAtom *a : file->sharedLibrary()) 1236 add(a->name(), a); 1237 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()) 1242 add(na->_name, a); 1243 else 1244 add(na->_refName, a); 1245 } 1246 } 1247 1248 inline const lld::File * 1249 MappingTraits<const lld::File *>::NormalizedFile::denormalize(IO &io) { 1250 typedef MappingTraits<const lld::DefinedAtom *>::NormalizedAtom 1251 NormalizedAtom; 1252 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); 1258 } 1259 1260 return this; 1261 } 1262 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); 1270 } 1271 } 1272 1273 inline void MappingTraits<const lld::Reference *>::NormalizedReference::bind( 1274 const RefNameResolver &resolver) { 1275 _target = resolver.lookup(_targetName); 1276 } 1277 1278 inline StringRef 1279 MappingTraits<const lld::Reference *>::NormalizedReference::targetName( 1280 IO &io, const lld::Reference *ref) { 1281 if (ref->target() == nullptr) 1282 return StringRef(); 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(); 1291 } 1292 1293 namespace lld { 1294 namespace yaml { 1295 1296 class Writer : public lld::Writer { 1297 public: 1298 Writer(const LinkingContext &context) : _ctx(context) {} 1299 1300 llvm::Error writeFile(const lld::File &file, StringRef outPath) override { 1301 // Create stream to path. 1302 std::error_code ec; 1303 llvm::raw_fd_ostream out(outPath, ec, llvm::sys::fs::F_Text); 1304 if (ec) 1305 return llvm::errorCodeToError(ec); 1306 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); 1312 1313 // Write yaml output. 1314 const lld::File *fileRef = &file; 1315 yout << fileRef; 1316 1317 return llvm::Error::success(); 1318 } 1319 1320 private: 1321 const LinkingContext &_ctx; 1322 }; 1323 1324 } // end namespace yaml 1325 1326 namespace { 1327 1328 /// Handles !native tagged yaml documents. 1329 class NativeYamlIOTaggedDocumentHandler : public YamlIOTaggedDocumentHandler { 1330 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); 1333 return true; 1334 } 1335 return false; 1336 } 1337 }; 1338 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); 1344 return true; 1345 } 1346 return false; 1347 } 1348 }; 1349 1350 class YAMLReader : public Reader { 1351 public: 1352 YAMLReader(const Registry ®istry) : _registry(registry) {} 1353 1354 bool canParse(file_magic magic, MemoryBufferRef mb) const override { 1355 StringRef name = mb.getBufferIdentifier(); 1356 return name.endswith(".objtxt") || name.endswith(".yaml"); 1357 } 1358 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); 1367 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); 1372 1373 // Error out now if there were parsing errors. 1374 if (yin.error()) 1375 return make_error_code(lld::YamlReaderError::illegal_value); 1376 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); 1384 } 1385 1386 private: 1387 const Registry &_registry; 1388 }; 1389 1390 } // end anonymous namespace 1391 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())); 1398 } 1399 1400 std::unique_ptr<Writer> createWriterYAML(const LinkingContext &context) { 1401 return std::unique_ptr<Writer>(new lld::yaml::Writer(context)); 1402 } 1403 1404 } // end namespace lld 1405