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