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