summaryrefslogtreecommitdiffstats
path: root/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp')
-rw-r--r--lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp1357
1 files changed, 1357 insertions, 0 deletions
diff --git a/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp b/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
new file mode 100644
index 00000000000..cadd2637e08
--- /dev/null
+++ b/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
@@ -0,0 +1,1357 @@
+//===- lib/ReaderWriter/YAML/ReaderWriterYAML.cpp -------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Reference.h"
+#include "lld/ReaderWriter/ReaderYAML.h"
+#include "lld/ReaderWriter/WriterYAML.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/system_error.h"
+#include "llvm/Support/YAMLTraits.h"
+
+#include <string>
+
+using llvm::yaml::MappingTraits;
+using llvm::yaml::ScalarEnumerationTraits;
+using llvm::yaml::ScalarTraits;
+using llvm::yaml::IO;
+using llvm::yaml::SequenceTraits;
+using llvm::yaml::DocumentListTraits;
+
+
+/// The conversion of Atoms to and from YAML uses LLVM's YAML I/O. This
+/// file just defines template specializations on the lld types which control
+/// how the mapping is done to and from YAML.
+
+
+namespace {
+/// Most of the traits are context-free and always do the same transformation.
+/// But, there are some traits that need some contextual information to properly
+/// do their transform. This struct is available via io.getContext() and
+/// supplies contextual information.
+class ContextInfo {
+public:
+ ContextInfo(const lld::ReaderOptionsYAML &ro)
+ : _currentFile(nullptr), _readerOptions(&ro), _writerOptions(nullptr) { }
+ ContextInfo(const lld::WriterOptionsYAML &wo)
+ : _currentFile(nullptr), _readerOptions(nullptr), _writerOptions(&wo) { }
+
+ lld::File *_currentFile;
+ const lld::ReaderOptionsYAML *_readerOptions;
+ const lld::WriterOptionsYAML *_writerOptions;
+};
+
+
+/// Used when writing yaml files.
+/// In most cases, atoms names are unambiguous, so references can just
+/// use the atom name as the target (e.g. target: foo). But in a few
+/// cases that does not work, so ref-names are added. These are labels
+/// used only in yaml. The labels do not exist in the Atom model.
+///
+/// One need for ref-names are when atoms have no user supplied name
+/// (e.g. c-string literal). Another case is when two object files with
+/// identically named static functions are merged (ld -r) into one object file.
+/// In that case referencing the function by name is ambiguous, so a unique
+/// ref-name is added.
+class RefNameBuilder {
+public:
+ RefNameBuilder(const lld::File &file)
+ : _collisionCount(0), _unnamedCounter(0) {
+ if (&file == nullptr)
+ return;
+ // visit all atoms
+ for (const lld::DefinedAtom *atom : file.defined()) {
+ // Build map of atoms names to detect duplicates
+ if (!atom->name().empty())
+ buildDuplicateNameMap(*atom);
+
+ // Find references to unnamed atoms and create ref-names for them.
+ for (const lld::Reference *ref : *atom) {
+ // create refname for any unnamed reference target
+ const lld::Atom *target = ref->target();
+ if ((target != nullptr) && target->name().empty()) {
+ std::string storage;
+ llvm::raw_string_ostream buffer(storage);
+ buffer << llvm::format("L%03d", _unnamedCounter++);
+ llvm::StringRef newName = copyString(buffer.str());
+ _refNames[target] = newName;
+ DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
+ << "unnamed atom: creating ref-name: '" << newName
+ << "' (" << (void*)newName.data() << ", "
+ << newName.size() << ")\n");
+ }
+ }
+ }
+ for (const lld::UndefinedAtom *undefAtom : file.undefined()) {
+ buildDuplicateNameMap(*undefAtom);
+ }
+ for (const lld::SharedLibraryAtom *shlibAtom : file.sharedLibrary()) {
+ buildDuplicateNameMap(*shlibAtom);
+ }
+ for (const lld::AbsoluteAtom *absAtom : file.absolute()) {
+ buildDuplicateNameMap(*absAtom);
+ }
+ }
+
+ void buildDuplicateNameMap(const lld::Atom &atom) {
+ assert(!atom.name().empty());
+ NameToAtom::iterator pos = _nameMap.find(atom.name());
+ if ( pos != _nameMap.end() ) {
+ // Found name collision, give each a unique ref-name.
+ std::string Storage;
+ llvm::raw_string_ostream buffer(Storage);
+ buffer << atom.name() << llvm::format(".%03d", ++_collisionCount);
+ llvm::StringRef newName = copyString(buffer.str());
+ _refNames[&atom] = newName;
+ DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
+ << "name collsion: creating ref-name: '" << newName
+ << "' (" << (void*)newName.data() << ", "
+ << newName.size() << ")\n");
+ const lld::Atom *prevAtom = pos->second;
+ AtomToRefName::iterator pos2 = _refNames.find(prevAtom);
+ if ( pos2 == _refNames.end() ) {
+ // Only create ref-name for previous if none already created.
+ std::string Storage2;
+ llvm::raw_string_ostream buffer2(Storage2);
+ buffer2 << prevAtom->name() << llvm::format(".%03d", ++_collisionCount);
+ llvm::StringRef newName2 = copyString(buffer2.str());
+ _refNames[prevAtom] = newName2;
+ DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
+ << "name collsion: creating ref-name: '" << newName2
+ << "' (" << (void*)newName2.data() << ", "
+ << newName2.size() << ")\n");
+ }
+ }
+ else {
+ // First time we've seen this name, just add it to map.
+ _nameMap[atom.name()] = &atom;
+ DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
+ << "atom name seen for first time: '" << atom.name()
+ << "' (" << (void*)atom.name().data() << ", "
+ << atom.name().size() << ")\n");
+ }
+ }
+
+ bool hasRefName(const lld::Atom *atom) {
+ return _refNames.count(atom);
+ }
+
+ llvm::StringRef refName(const lld::Atom *atom) {
+ return _refNames.find(atom)->second;
+ }
+
+private:
+ typedef llvm::StringMap<const lld::Atom*> NameToAtom;
+ typedef llvm::DenseMap<const lld::Atom*, std::string> AtomToRefName;
+
+ // Allocate a new copy of this string and keep track of allocations
+ // in _stringCopies, so they can be freed when RefNameBuilder is destroyed.
+ llvm::StringRef copyString(llvm::StringRef str) {
+ // We want _stringCopies to own the string memory so it is deallocated
+ // when the File object is destroyed. But we need a StringRef that
+ // points into that memory.
+ std::unique_ptr<char> s = std::unique_ptr<char>(new char[str.size()]);
+ memcpy(s.get(), str.data(), str.size());
+ llvm::StringRef r = llvm::StringRef(s.get(), str.size());
+ _stringCopies.push_back(std::move(s));
+ return r;
+ }
+
+ unsigned int _collisionCount;
+ unsigned int _unnamedCounter;
+ NameToAtom _nameMap;
+ AtomToRefName _refNames;
+ std::vector<std::unique_ptr<char>> _stringCopies;
+};
+
+
+/// Used when reading yaml files to find the target of a reference
+/// that could be a name or ref-name.
+class RefNameResolver {
+public:
+ RefNameResolver(const lld::File *file, IO &io);
+
+ const lld::Atom *lookup(llvm::StringRef name) const {
+ NameToAtom::const_iterator pos = _nameMap.find(name);
+ if (pos != _nameMap.end()) {
+ return pos->second;
+ }
+ else {
+ _io.setError(llvm::Twine("no such atom name: ") + name);
+ return nullptr;
+ }
+ }
+
+private:
+ typedef llvm::StringMap<const lld::Atom*> NameToAtom;
+
+ void add(llvm::StringRef name, const lld::Atom *atom) {
+ if (_nameMap.count(name)) {
+ _io.setError(llvm::Twine("duplicate atom name: ") + name);
+ }
+ else {
+ _nameMap[name] = atom;
+ }
+ }
+
+ IO &_io;
+ NameToAtom _nameMap;
+};
+
+
+// Used in NormalizedFile to hold the atoms lists.
+template <typename T>
+class AtomList : public lld::File::atom_collection<T> {
+public:
+ virtual lld::File::atom_iterator<T> begin() const {
+ return lld::File::atom_iterator<T>(*this, reinterpret_cast<const void*>
+ (_atoms.data()));
+ }
+ virtual lld::File::atom_iterator<T> end() const{
+ return lld::File::atom_iterator<T>(*this, reinterpret_cast<const void*>
+ (_atoms.data() + _atoms.size()));
+ }
+ virtual const T *deref(const void *it) const {
+ return *reinterpret_cast<const T *const*>(it);
+ }
+ virtual void next(const void *&it) const {
+ const T *const *p = reinterpret_cast<const T *const *>(it);
+ ++p;
+ it = reinterpret_cast<const void*>(p);
+ }
+ virtual void push_back(const T *element) {
+ _atoms.push_back(element);
+ }
+ std::vector<const T*> _atoms;
+};
+
+/// Mapping of kind: field in yaml files.
+enum FileKinds {
+ fileKindObjectAtoms, // atom based object file encoded in yaml
+ fileKindArchive, // static archive library encoded in yaml
+ fileKindObjectELF, // ELF object files encoded in yaml
+ fileKindObjectMachO // mach-o object files encoded in yaml
+};
+
+struct ArchMember {
+ FileKinds _kind;
+ llvm::StringRef _name;
+ const lld::File *_content;
+};
+
+// The content bytes in a DefinedAtom are just uint8_t but we want
+// special formatting, so define a strong type.
+LLVM_YAML_STRONG_TYPEDEF(uint8_t, ImplicitHex8);
+
+// SharedLibraryAtoms have a bool canBeNull() method which we'd like to be
+// more readable than just true/false.
+LLVM_YAML_STRONG_TYPEDEF(bool, ShlibCanBeNull);
+
+// lld::Reference::Kind is a typedef of int32. We need a stronger
+// type to make template matching work, so invent RefKind.
+LLVM_YAML_STRONG_TYPEDEF(lld::Reference::Kind, RefKind);
+
+
+} // namespace anon
+
+
+// This is a custom formatter for RefKind
+template<>
+struct ScalarTraits<RefKind> {
+ static void output(const RefKind &value, void *ctxt,
+ llvm::raw_ostream &out) {
+ assert(ctxt != nullptr);
+ ContextInfo *info = reinterpret_cast<ContextInfo*>(ctxt);
+ out << info->_writerOptions->kindToString(value);
+ }
+
+ static StringRef input(StringRef scalar, void *ctxt, RefKind &value) {
+ assert(ctxt != nullptr);
+ ContextInfo *info = reinterpret_cast<ContextInfo*>(ctxt);
+ value = info->_readerOptions->kindFromString(scalar);
+ return StringRef();
+ }
+};
+
+
+template <>
+struct ScalarEnumerationTraits<lld::File::Kind> {
+ static void enumeration(IO &io, lld::File::Kind &value) {
+ io.enumCase(value, "object", lld::File::kindObject);
+ io.enumCase(value, "shared-library", lld::File::kindSharedLibrary);
+ io.enumCase(value, "static-library", lld::File::kindArchiveLibrary);
+ }
+};
+
+template <>
+struct ScalarEnumerationTraits<lld::Atom::Scope> {
+ static void enumeration(IO &io, lld::Atom::Scope &value) {
+ io.enumCase(value, "global", lld::Atom::scopeGlobal);
+ io.enumCase(value, "hidden", lld::Atom::scopeLinkageUnit);
+ io.enumCase(value, "static", lld::Atom::scopeTranslationUnit);
+ }
+};
+
+template <>
+struct ScalarEnumerationTraits<lld::DefinedAtom::SectionChoice> {
+ static void enumeration(IO &io, lld::DefinedAtom::SectionChoice &value) {
+ io.enumCase(value, "content", lld::DefinedAtom::sectionBasedOnContent);
+ io.enumCase(value, "custom", lld::DefinedAtom::sectionCustomPreferred);
+ io.enumCase(value, "custom-required",
+ lld::DefinedAtom::sectionCustomRequired);
+ }
+};
+
+template <>
+struct ScalarEnumerationTraits<lld::DefinedAtom::Interposable> {
+ static void enumeration(IO &io, lld::DefinedAtom::Interposable &value) {
+ io.enumCase(value, "no", lld::DefinedAtom::interposeNo);
+ io.enumCase(value, "yes", lld::DefinedAtom::interposeYes);
+ io.enumCase(value, "yes-and-weak",
+ lld::DefinedAtom::interposeYesAndRuntimeWeak);
+ }
+};
+
+template <>
+struct ScalarEnumerationTraits<lld::DefinedAtom::Merge> {
+ static void enumeration(IO &io, lld::DefinedAtom::Merge &value) {
+ io.enumCase(value, "no", lld::DefinedAtom::mergeNo);
+ io.enumCase(value, "as-tentative", lld::DefinedAtom::mergeAsTentative);
+ io.enumCase(value, "as-weak", lld::DefinedAtom::mergeAsWeak);
+ io.enumCase(value, "as-addressed-weak",
+ lld::DefinedAtom::mergeAsWeakAndAddressUsed);
+ }
+};
+
+template <>
+struct ScalarEnumerationTraits<lld::DefinedAtom::DeadStripKind> {
+ static void enumeration(IO &io, lld::DefinedAtom::DeadStripKind &value) {
+ io.enumCase(value, "normal", lld::DefinedAtom::deadStripNormal);
+ io.enumCase(value, "never", lld::DefinedAtom::deadStripNever);
+ io.enumCase(value, "always", lld::DefinedAtom::deadStripAlways);
+ }
+};
+
+template <>
+struct ScalarEnumerationTraits<lld::DefinedAtom::ContentPermissions> {
+ static void enumeration(IO &io, lld::DefinedAtom::ContentPermissions &value) {
+ io.enumCase(value, "---", lld::DefinedAtom::perm___);
+ io.enumCase(value, "r--", lld::DefinedAtom::permR__);
+ io.enumCase(value, "r-x", lld::DefinedAtom::permR_X);
+ io.enumCase(value, "rw-", lld::DefinedAtom::permRW_);
+ io.enumCase(value, "rwx", lld::DefinedAtom::permRWX);
+ io.enumCase(value, "rw-l", lld::DefinedAtom::permRW_L);
+ }
+};
+
+template <>
+struct ScalarEnumerationTraits<lld::DefinedAtom::ContentType> {
+ static void enumeration(IO &io, lld::DefinedAtom::ContentType &value) {
+ io.enumCase(value, "unknown",
+ lld::DefinedAtom::typeUnknown);
+ io.enumCase(value, "code",
+ lld::DefinedAtom::typeCode);
+ io.enumCase(value, "stub",
+ lld::DefinedAtom::typeStub);
+ io.enumCase(value, "constant",
+ lld::DefinedAtom::typeConstant);
+ io.enumCase(value, "data",
+ lld::DefinedAtom::typeData);
+ io.enumCase(value, "zero-fill",
+ lld::DefinedAtom::typeZeroFill);
+ io.enumCase(value, "got",
+ lld::DefinedAtom::typeGOT);
+ io.enumCase(value, "resolver",
+ lld::DefinedAtom::typeResolver);
+ io.enumCase(value, "branch-island",
+ lld::DefinedAtom::typeBranchIsland);
+ io.enumCase(value, "branch-shim",
+ lld::DefinedAtom::typeBranchShim);
+ io.enumCase(value, "stub-helper",
+ lld::DefinedAtom::typeStubHelper);
+ io.enumCase(value, "c-string",
+ lld::DefinedAtom::typeCString);
+ io.enumCase(value, "utf16-string",
+ lld::DefinedAtom::typeUTF16String);
+ io.enumCase(value, "unwind-cfi",
+ lld::DefinedAtom::typeCFI);
+ io.enumCase(value, "unwind-lsda",
+ lld::DefinedAtom::typeLSDA);
+ io.enumCase(value, "const-4-byte",
+ lld::DefinedAtom::typeLiteral4);
+ io.enumCase(value, "const-8-byte",
+ lld::DefinedAtom::typeLiteral8);
+ io.enumCase(value, "const-16-byte",
+ lld::DefinedAtom::typeLiteral16);
+ io.enumCase(value, "lazy-pointer",
+ lld::DefinedAtom::typeLazyPointer);
+ io.enumCase(value, "lazy-dylib-pointer",
+ lld::DefinedAtom::typeLazyDylibPointer);
+ io.enumCase(value, "cfstring",
+ lld::DefinedAtom::typeCFString);
+ io.enumCase(value, "initializer-pointer",
+ lld::DefinedAtom::typeInitializerPtr);
+ io.enumCase(value, "terminator-pointer",
+ lld::DefinedAtom::typeTerminatorPtr);
+ io.enumCase(value, "c-string-pointer",
+ lld::DefinedAtom::typeCStringPtr);
+ io.enumCase(value, "objc-class-pointer",
+ lld::DefinedAtom::typeObjCClassPtr);
+ io.enumCase(value, "objc-category-list",
+ lld::DefinedAtom::typeObjC2CategoryList);
+ io.enumCase(value, "objc-class1",
+ lld::DefinedAtom::typeObjC1Class);
+ io.enumCase(value, "dtraceDOF",
+ lld::DefinedAtom::typeDTraceDOF);
+ io.enumCase(value, "lto-temp",
+ lld::DefinedAtom::typeTempLTO);
+ io.enumCase(value, "compact-unwind",
+ lld::DefinedAtom::typeCompactUnwindInfo);
+ io.enumCase(value, "tlv-thunk",
+ lld::DefinedAtom::typeThunkTLV);
+ io.enumCase(value, "tlv-data",
+ lld::DefinedAtom::typeTLVInitialData);
+ io.enumCase(value, "tlv-zero-fill",
+ lld::DefinedAtom::typeTLVInitialZeroFill);
+ io.enumCase(value, "tlv-initializer-ptr",
+ lld::DefinedAtom::typeTLVInitializerPtr);
+ io.enumCase(value, "first-in-section",
+ lld::DefinedAtom::typeFirstInSection);
+ io.enumCase(value, "last-in-section",
+ lld::DefinedAtom::typeLastInSection);
+ }
+};
+
+template <>
+struct ScalarEnumerationTraits<lld::UndefinedAtom::CanBeNull> {
+ static void enumeration(IO &io, lld::UndefinedAtom::CanBeNull &value) {
+ io.enumCase(value, "never", lld::UndefinedAtom::canBeNullNever);
+ io.enumCase(value, "at-runtime", lld::UndefinedAtom::canBeNullAtRuntime);
+ io.enumCase(value, "at-buildtime", lld::UndefinedAtom::canBeNullAtBuildtime);
+ }
+};
+
+
+template <>
+struct ScalarEnumerationTraits<ShlibCanBeNull> {
+ static void enumeration(IO &io, ShlibCanBeNull &value) {
+ io.enumCase(value, "never", false);
+ io.enumCase(value, "at-runtime", true);
+ }
+};
+
+
+
+/// This is a custom formatter for lld::DefinedAtom::Alignment. Values look
+/// like:
+/// 2^3 # 8-byte aligned
+/// 7 mod 2^4 # 16-byte aligned plus 7 bytes
+template<>
+struct ScalarTraits<lld::DefinedAtom::Alignment> {
+ static void output(const lld::DefinedAtom::Alignment &value, void *ctxt,
+ llvm::raw_ostream &out) {
+ if (value.modulus == 0) {
+ out << llvm::format("2^%d", value.powerOf2);
+ }
+ else {
+ out << llvm::format("%d mod 2^%d", value.modulus, value.powerOf2);
+ }
+ }
+
+ static StringRef input(StringRef scalar, void *ctxt,
+ lld::DefinedAtom::Alignment &value) {
+ value.modulus = 0;
+ size_t modStart = scalar.find("mod");
+ if (modStart != StringRef::npos) {
+ StringRef modStr = scalar.slice(0, modStart);
+ modStr = modStr.rtrim();
+ unsigned int modulus;
+ if (modStr.getAsInteger(0, modulus)) {
+ return "malformed alignment modulus";
+ }
+ value.modulus = modulus;
+ scalar = scalar.drop_front(modStart+3);
+ scalar = scalar.ltrim();
+ }
+ if (!scalar.startswith("2^")) {
+ return "malformed alignment";
+ }
+ StringRef powerStr = scalar.drop_front(2);
+ unsigned int power;
+ if (powerStr.getAsInteger(0, power)) {
+ return "malformed alignment power";
+ }
+ value.powerOf2 = power;
+ if (value.modulus > (1<<value.powerOf2)) {
+ return "malformed alignment, modulus too large for power";
+ }
+ return StringRef(); // returning empty string means success
+ }
+};
+
+
+
+
+template <>
+struct ScalarEnumerationTraits<FileKinds> {
+ static void enumeration(IO &io, FileKinds &value) {
+ io.enumCase(value, "object", fileKindObjectAtoms);
+ io.enumCase(value, "archive", fileKindArchive);
+ io.enumCase(value, "object-elf", fileKindObjectELF);
+ io.enumCase(value, "object-mach-o", fileKindObjectMachO);
+ }
+};
+
+template <>
+struct MappingTraits<ArchMember> {
+ static void mapping(IO &io, ArchMember &member) {
+ io.mapOptional("kind", member._kind, fileKindObjectAtoms);
+ io.mapOptional("name", member._name);
+ io.mapRequired("content", member._content);
+ }
+};
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(ArchMember);
+
+
+// Declare that an AtomList is a yaml sequence.
+template<typename T>
+struct SequenceTraits<AtomList<T>> {
+ static size_t size(IO &io, AtomList<T> &seq) {
+ return seq._atoms.size();
+ }
+ static const T *&element(IO &io, AtomList<T> &seq, size_t index) {
+ if (index >= seq._atoms.size())
+ seq._atoms.resize(index+1);
+ return seq._atoms[index];
+ }
+};
+
+// Used to allow DefinedAtom content bytes to be a flow sequence of
+// two-digit hex numbers without the leading 0x (e.g. FF, 04, 0A)
+template<>
+struct ScalarTraits<ImplicitHex8> {
+ static void output(const ImplicitHex8 &val, void*, llvm::raw_ostream &out) {
+ uint8_t num = val;
+ out << llvm::format("%02X", num);
+ }
+
+ static llvm::StringRef input(llvm::StringRef str, void*, ImplicitHex8 &val) {
+ unsigned long long n;
+ if (getAsUnsignedInteger(str, 16, n))
+ return "invalid two-digit-hex number";
+ if (n > 0xFF)
+ return "out of range two-digit-hex number";
+ val = n;
+ return StringRef(); // returning empty string means success
+ }
+};
+
+// Always write DefinedAtoms content bytes as a flow sequence.
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(ImplicitHex8);
+
+
+// YAML conversion for std::vector<const lld::File*>
+template<>
+struct DocumentListTraits< std::vector<const lld::File*> > {
+ static size_t size(IO &io, std::vector<const lld::File*> &seq) {
+ return seq.size();
+ }
+ static const lld::File *&element(IO &io, std::vector<const lld::File*> &seq,
+ size_t index) {
+ if (index >= seq.size())
+ seq.resize(index+1);
+ return seq[index];
+ }
+};
+
+
+// YAML conversion for const lld::File*
+template <>
+struct MappingTraits<const lld::File*> {
+
+ class NormArchiveFile : public lld::ArchiveLibraryFile {
+ public:
+ NormArchiveFile(IO &io) : ArchiveLibraryFile(""), _path() {
+ }
+ NormArchiveFile(IO &io, const lld::File *file)
+ : ArchiveLibraryFile(file->path()),
+ _path(file->path()) {
+ // If we want to support writing archives, this constructor would
+ // need to populate _members.
+ }
+
+ const lld::File *denormalize(IO &io) {
+ return this;
+ }
+
+ virtual void addAtom(const lld::Atom&) {
+ llvm_unreachable("cannot add atoms to yaml .o files");
+ }
+ virtual const atom_collection<lld::DefinedAtom> &defined() const {
+ return _noDefinedAtoms;
+ }
+ virtual const atom_collection<lld::UndefinedAtom> &undefined() const {
+ return _noUndefinedAtoms;
+ }
+ virtual const atom_collection<lld::SharedLibraryAtom> &sharedLibrary()const{
+ return _noSharedLibaryAtoms;
+ }
+ virtual const atom_collection<lld::AbsoluteAtom> &absolute() const {
+ return _noAbsoluteAtoms;
+ }
+ virtual const File *find(StringRef name, bool dataSymbolOnly) const {
+ for (const ArchMember &member : _members) {
+ for (const lld::DefinedAtom *atom : member._content->defined() ) {
+ if (name == atom->name()) {
+ if (!dataSymbolOnly)
+ return member._content;
+ switch (atom->contentType()) {
+ case lld::DefinedAtom::typeData:
+ case lld::DefinedAtom::typeZeroFill:
+ return member._content;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ return nullptr;
+ }
+
+ StringRef _path;
+ std::vector<ArchMember> _members;
+ };
+
+
+ class NormalizedFile : public lld::File {
+ public:
+ NormalizedFile(IO &io) : File(""), _rnb(nullptr) {
+ }
+ NormalizedFile(IO &io, const lld::File *file)
+ : File(file->path()),
+ _rnb(new RefNameBuilder(*file)),
+ _path(file->path()) {
+ for (const lld::DefinedAtom *a : file->defined())
+ _definedAtoms.push_back(a);
+ for (const lld::UndefinedAtom *a : file->undefined())
+ _undefinedAtoms.push_back(a);
+ for (const lld::SharedLibraryAtom *a : file->sharedLibrary())
+ _sharedLibraryAtoms.push_back(a);
+ for (const lld::AbsoluteAtom *a : file->absolute())
+ _absoluteAtoms.push_back(a);
+ }
+ const lld::File *denormalize(IO &io);
+
+
+ virtual void addAtom(const lld::Atom&) {
+ llvm_unreachable("cannot add atoms to yaml .o files");
+ }
+ virtual const atom_collection<lld::DefinedAtom> &defined() const {
+ return _definedAtoms;
+ }
+ virtual const atom_collection<lld::UndefinedAtom> &undefined() const {
+ return _undefinedAtoms;
+ }
+ virtual const atom_collection<lld::SharedLibraryAtom> &sharedLibrary()const{
+ return _sharedLibraryAtoms;
+ }
+ virtual const atom_collection<lld::AbsoluteAtom> &absolute() const {
+ return _absoluteAtoms;
+ }
+
+ // Allocate a new copy of this string and keep track of allocations
+ // in _stringCopies, so they can be freed when File is destroyed.
+ StringRef copyString(StringRef str) {
+ // We want _stringCopies to own the string memory so it is deallocated
+ // when the File object is destroyed. But we need a StringRef that
+ // points into that memory.
+ std::unique_ptr<char> s = std::unique_ptr<char>(new char[str.size()]);
+ memcpy(s.get(), str.data(), str.size());
+ llvm::StringRef r = llvm::StringRef(s.get(), str.size());
+ _stringCopies.push_back(std::move(s));
+ return r;
+ }
+
+ RefNameBuilder *_rnb;
+ StringRef _path;
+ AtomList<lld::DefinedAtom> _definedAtoms;
+ AtomList<lld::UndefinedAtom> _undefinedAtoms;
+ AtomList<lld::SharedLibraryAtom> _sharedLibraryAtoms;
+ AtomList<lld::AbsoluteAtom> _absoluteAtoms;
+ std::vector<std::unique_ptr<char>> _stringCopies;
+ };
+
+
+ static void mapping(IO &io, const lld::File *&file) {
+ // We only support writing atom based YAML
+ FileKinds kind = fileKindObjectAtoms;
+ // If reading, peek ahead to see what kind of file this is.
+ io.mapOptional("kind", kind, fileKindObjectAtoms);
+ //
+ switch (kind) {
+ case fileKindObjectAtoms:
+ mappingAtoms(io, file);
+ break;
+ case fileKindArchive:
+ mappingArchive(io, file);
+ break;
+ case fileKindObjectELF:
+ case fileKindObjectMachO:
+ // Eventually we will have an external function to call, similar
+ // to mappingAtoms() and mappingArchive() but implememented
+ // with coresponding file format code.
+ default:
+ llvm_unreachable("section based YAML not supported yet");
+ }
+ }
+
+ static void mappingAtoms(IO &io, const lld::File *&file) {
+ MappingNormalizationHeap<NormalizedFile, const lld::File*> keys(io, file);
+ ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
+ assert(info != nullptr);
+ info->_currentFile = keys.operator->();
+
+ io.mapOptional("path", keys->_path);
+ io.mapOptional("defined-atoms", keys->_definedAtoms);
+ io.mapOptional("undefined-atoms", keys->_undefinedAtoms);
+ io.mapOptional("shared-library-atoms", keys->_sharedLibraryAtoms);
+ io.mapOptional("absolute-atoms", keys->_absoluteAtoms);
+ }
+
+ static void mappingArchive(IO &io, const lld::File *&file) {
+ MappingNormalizationHeap<NormArchiveFile, const lld::File*> keys(io, file);
+
+ io.mapOptional("path", keys->_path);
+ io.mapOptional("members", keys->_members);
+ }
+
+};
+
+
+
+// YAML conversion for const lld::Reference*
+template <>
+struct MappingTraits<const lld::Reference*> {
+
+ class NormalizedReference : public lld::Reference {
+ public:
+ NormalizedReference(IO &io)
+ : _target(nullptr), _targetName(), _offset(0), _addend(0) , _kind(0) {
+ }
+ NormalizedReference(IO &io, const lld::Reference *ref)
+ : _target(nullptr),
+ _targetName(targetName(io, ref)),
+ _offset(ref->offsetInAtom()),
+ _addend(ref->addend()),
+ _kind(ref->kind()) {
+ }
+ const lld::Reference *denormalize(IO &io) {
+ ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
+ assert(info != nullptr);
+ typedef MappingTraits<const lld::File*>::NormalizedFile NormalizedFile;
+ NormalizedFile *f = reinterpret_cast<NormalizedFile*>(info->_currentFile);
+ if (!_targetName.empty())
+ _targetName = f->copyString(_targetName);
+ DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
+ << "created Reference to name: '" << _targetName
+ << "' (" << (void*)_targetName.data() << ", "
+ << _targetName.size() << ")\n");
+ return this;
+ }
+ void bind(const RefNameResolver&);
+ static StringRef targetName(IO &io, const lld::Reference *ref);
+
+ virtual uint64_t offsetInAtom() const { return _offset; }
+ virtual Kind kind() const { return _kind; }
+ virtual const lld::Atom *target() const { return _target; }
+ virtual Addend addend() const { return _addend; }
+ virtual void setKind(Kind k) { _kind = k; }
+ virtual void setAddend(Addend a) { _addend = a; }
+ virtual void setTarget(const lld::Atom *a) { _target = a; }
+
+ const lld::Atom *_target;
+ StringRef _targetName;
+ uint32_t _offset;
+ Addend _addend;
+ RefKind _kind;
+ };
+
+
+ static void mapping(IO &io, const lld::Reference *&ref) {
+ MappingNormalizationHeap<NormalizedReference,
+ const lld::Reference*> keys(io, ref);
+
+ io.mapRequired("kind", keys->_kind);
+ io.mapOptional("offset", keys->_offset);
+ io.mapOptional("target", keys->_targetName);
+ io.mapOptional("addend", keys->_addend, (lld::Reference::Addend)0);
+ }
+};
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(const lld::Reference*)
+
+
+// YAML conversion for const lld::DefinedAtom*
+template <>
+struct MappingTraits<const lld::DefinedAtom*> {
+
+ class NormalizedAtom : public lld::DefinedAtom {
+ public:
+ NormalizedAtom(IO &io)
+ : _file(fileFromContext(io)), _name(), _refName(),
+ _alignment(0), _content(), _references() {
+ }
+ NormalizedAtom(IO &io, const lld::DefinedAtom *atom)
+ : _file(fileFromContext(io)),
+ _name(atom->name()),
+ _refName(),
+ _scope(atom->scope()),
+ _interpose(atom->interposable()),
+ _merge(atom->merge()),
+ _contentType(atom->contentType()),
+ _alignment(atom->alignment()),
+ _sectionChoice(atom->sectionChoice()),
+ _deadStrip(atom->deadStrip()),
+ _permissions(atom->permissions()),
+ _size(atom->size()),
+ _sectionName(atom->customSectionName()) {
+ for ( const lld::Reference *r : *atom )
+ _references.push_back(r);
+ ArrayRef<uint8_t> cont = atom->rawContent();
+ _content.reserve(cont.size());
+ for (uint8_t x : cont)
+ _content.push_back(x);
+ }
+ const lld::DefinedAtom *denormalize(IO &io) {
+ ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
+ assert(info != nullptr);
+ typedef MappingTraits<const lld::File*>::NormalizedFile NormalizedFile;
+ NormalizedFile *f = reinterpret_cast<NormalizedFile*>(info->_currentFile);
+ if ( !_name.empty() )
+ _name = f->copyString(_name);
+ if ( !_refName.empty() )
+ _refName = f->copyString(_refName);
+ if ( !_sectionName.empty() )
+ _sectionName = f->copyString(_sectionName);
+ DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
+ << "created DefinedAtom named: '" << _name
+ << "' (" << (void*)_name.data() << ", "
+ << _name.size() << ")\n");
+ return this;
+ }
+ void bind(const RefNameResolver&);
+ // Extract current File object from YAML I/O parsing context
+ const lld::File &fileFromContext(IO &io) {
+ ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
+ assert(info != nullptr);
+ assert(info->_currentFile != nullptr);
+ return *info->_currentFile;
+ }
+
+ virtual const lld::File &file() const { return _file; }
+ virtual StringRef name() const { return _name; }
+ virtual uint64_t size() const { return _size; }
+ virtual Scope scope() const { return _scope; }
+ virtual Interposable interposable() const { return _interpose; }
+ virtual Merge merge() const { return _merge; }
+ virtual ContentType contentType() const { return _contentType; }
+ virtual Alignment alignment() const { return _alignment; }
+ virtual SectionChoice sectionChoice() const { return _sectionChoice; }
+ virtual StringRef customSectionName() const { return _sectionName;}
+ virtual DeadStripKind deadStrip() const { return _deadStrip; }
+ virtual ContentPermissions permissions() const { return _permissions; }
+ virtual bool isThumb() const { return false; }
+ virtual bool isAlias() const { return false; }
+ ArrayRef<uint8_t> rawContent() const {
+ return ArrayRef<uint8_t>((uint8_t*)&_content.operator[](0),
+ _content.size()); }
+ virtual uint64_t ordinal() const { return 0; }
+
+ reference_iterator begin() const {
+ uintptr_t index = 0;
+ const void *it = reinterpret_cast<const void*>(index);
+ return reference_iterator(*this, it);
+ }
+ reference_iterator end() const {
+ uintptr_t index = _references.size();
+ const void *it = reinterpret_cast<const void*>(index);
+ return reference_iterator(*this, it);
+ }
+ const lld::Reference *derefIterator(const void *it) const {
+ uintptr_t index = reinterpret_cast<uintptr_t>(it);
+ assert(index < _references.size());
+ return _references[index];
+ }
+ void incrementIterator(const void *&it) const {
+ uintptr_t index = reinterpret_cast<uintptr_t>(it);
+ ++index;
+ it = reinterpret_cast<const void*>(index);
+ }
+
+ const lld::File &_file;
+ StringRef _name;
+ StringRef _refName;
+ Scope _scope;
+ Interposable _interpose;
+ Merge _merge;
+ ContentType _contentType;
+ Alignment _alignment;
+ SectionChoice _sectionChoice;
+ DeadStripKind _deadStrip;
+ ContentPermissions _permissions;
+ std::vector<ImplicitHex8> _content;
+ uint64_t _size;
+ StringRef _sectionName;
+ std::vector<const lld::Reference*> _references;
+ };
+
+ static void mapping(IO &io, const lld::DefinedAtom *&atom) {
+ MappingNormalizationHeap<NormalizedAtom,
+ const lld::DefinedAtom*> keys(io, atom);
+ if ( io.outputting() ) {
+ // If writing YAML, check if atom needs a ref-name.
+ typedef MappingTraits<const lld::File*>::NormalizedFile NormalizedFile;
+ ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
+ assert(info != nullptr);
+ NormalizedFile *f = reinterpret_cast<NormalizedFile*>(info->_currentFile);
+ assert(f);
+ assert(f->_rnb);
+ if ( f->_rnb->hasRefName(atom) ) {
+ keys->_refName = f->_rnb->refName(atom);
+ }
+ }
+
+ io.mapOptional("name", keys->_name,
+ StringRef());
+ io.mapOptional("ref-name", keys->_refName,
+ StringRef());
+ io.mapOptional("scope", keys->_scope,
+ lld::DefinedAtom::scopeTranslationUnit);
+ io.mapOptional("type", keys->_contentType,
+ lld::DefinedAtom::typeCode);
+ io.mapOptional("content", keys->_content);
+ io.mapOptional("size", keys->_size,
+ (uint64_t)keys->_content.size());
+ io.mapOptional("interposable", keys->_interpose,
+ lld::DefinedAtom::interposeNo);
+ io.mapOptional("merge", keys->_merge,
+ lld::DefinedAtom::mergeNo);
+ io.mapOptional("alignment", keys->_alignment,
+ lld::DefinedAtom::Alignment(0));
+ io.mapOptional("section-choice", keys->_sectionChoice,
+ lld::DefinedAtom::sectionBasedOnContent);
+ io.mapOptional("section-name", keys->_sectionName,
+ StringRef());
+ io.mapOptional("dead-strip", keys->_deadStrip,
+ lld::DefinedAtom::deadStripNormal);
+ io.mapOptional("permissions", keys->_permissions,
+ lld::DefinedAtom::permR_X);
+ io.mapOptional("fixups", keys->_references);
+ }
+};
+
+
+
+
+inline
+const lld::File*
+MappingTraits<const lld::File*>::NormalizedFile::denormalize(IO &io) {
+ typedef MappingTraits<const lld::DefinedAtom*>::NormalizedAtom NormalizedAtom;
+
+ RefNameResolver nameResolver(this, io);
+ // Now that all atoms are parsed, references can be bound.
+ for (const lld::DefinedAtom *a : this->defined() ) {
+ NormalizedAtom *normAtom = (NormalizedAtom*)a;
+ normAtom->bind(nameResolver);
+ }
+ return this;
+}
+
+inline
+void MappingTraits<const lld::DefinedAtom*>::
+ NormalizedAtom::bind(const RefNameResolver &resolver) {
+ typedef MappingTraits<const lld::Reference*>::NormalizedReference
+ NormalizedReference;
+ for (const lld::Reference *ref : _references) {
+ NormalizedReference *normRef = (NormalizedReference*)ref;
+ normRef->bind(resolver);
+ }
+}
+
+inline
+void MappingTraits<const lld::Reference*>::
+ NormalizedReference::bind(const RefNameResolver &resolver) {
+ _target = resolver.lookup(_targetName);
+}
+
+
+
+// YAML conversion for const lld::UndefinedAtom*
+template <>
+struct MappingTraits<const lld::UndefinedAtom*> {
+
+ class NormalizedAtom : public lld::UndefinedAtom {
+ public:
+ NormalizedAtom(IO &io)
+ : _file(fileFromContext(io)), _name(), _canBeNull(canBeNullNever) {
+ }
+ NormalizedAtom(IO &io, const lld::UndefinedAtom *atom)
+ : _file(fileFromContext(io)),
+ _name(atom->name()),
+ _canBeNull(atom->canBeNull()) {
+ }
+ const lld::UndefinedAtom *denormalize(IO &io) {
+ ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
+ assert(info != nullptr);
+ typedef MappingTraits<const lld::File*>::NormalizedFile NormalizedFile;
+ NormalizedFile *f = reinterpret_cast<NormalizedFile*>(info->_currentFile);
+ if ( !_name.empty() )
+ _name = f->copyString(_name);
+
+ DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
+ << "created UndefinedAtom named: '" << _name
+ << "' (" << (void*)_name.data() << ", "
+ << _name.size() << ")\n");
+ return this;
+ }
+ // Extract current File object from YAML I/O parsing context
+ const lld::File &fileFromContext(IO &io) {
+ ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
+ assert(info != nullptr);
+ assert(info->_currentFile != nullptr);
+ return *info->_currentFile;
+ }
+
+ virtual const lld::File &file() const { return _file; }
+ virtual StringRef name() const { return _name; }
+ virtual CanBeNull canBeNull() const { return _canBeNull; }
+
+ const lld::File &_file;
+ StringRef _name;
+ CanBeNull _canBeNull;
+ };
+
+
+ static void mapping(IO &io, const lld::UndefinedAtom* &atom) {
+ MappingNormalizationHeap<NormalizedAtom,
+ const lld::UndefinedAtom*> keys(io, atom);
+
+ io.mapRequired("name", keys->_name);
+ io.mapOptional("can-be-null", keys->_canBeNull,
+ lld::UndefinedAtom::canBeNullNever);
+ }
+};
+
+
+// YAML conversion for const lld::SharedLibraryAtom*
+template <>
+struct MappingTraits<const lld::SharedLibraryAtom*> {
+
+ class NormalizedAtom : public lld::SharedLibraryAtom {
+ public:
+ NormalizedAtom(IO &io)
+ : _file(fileFromContext(io)), _name(), _loadName(), _canBeNull(false) {
+ }
+ NormalizedAtom(IO &io, const lld::SharedLibraryAtom *atom)
+ : _file(fileFromContext(io)),
+ _name(atom->name()),
+ _loadName(atom->loadName()),
+ _canBeNull(atom->canBeNullAtRuntime()) {
+ }
+ const lld::SharedLibraryAtom *denormalize(IO &io) {
+ ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
+ assert(info != nullptr);
+ typedef MappingTraits<const lld::File*>::NormalizedFile NormalizedFile;
+ NormalizedFile *f = reinterpret_cast<NormalizedFile*>(info->_currentFile);
+ if ( !_name.empty() )
+ _name = f->copyString(_name);
+ if ( !_loadName.empty() )
+ _loadName = f->copyString(_loadName);
+
+ DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
+ << "created SharedLibraryAtom named: '" << _name
+ << "' (" << (void*)_name.data() << ", "
+ << _name.size() << ")\n");
+ return this;
+ }
+ // Extract current File object from YAML I/O parsing context
+ const lld::File &fileFromContext(IO &io) {
+ ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
+ assert(info != nullptr);
+ assert(info->_currentFile != nullptr);
+ return *info->_currentFile;
+ }
+
+ virtual const lld::File &file() const { return _file; }
+ virtual StringRef name() const { return _name; }
+ virtual StringRef loadName() const { return _loadName;}
+ virtual bool canBeNullAtRuntime() const { return _canBeNull; }
+
+ const lld::File &_file;
+ StringRef _name;
+ StringRef _loadName;
+ ShlibCanBeNull _canBeNull;
+ };
+
+
+ static void mapping(IO &io, const lld::SharedLibraryAtom *&atom) {
+
+ MappingNormalizationHeap<NormalizedAtom,
+ const lld::SharedLibraryAtom*> keys(io, atom);
+
+ io.mapRequired("name", keys->_name);
+ io.mapOptional("load-name", keys->_loadName);
+ io.mapOptional("can-be-null", keys->_canBeNull,
+ (ShlibCanBeNull)false);
+ }
+};
+
+
+// YAML conversion for const lld::AbsoluteAtom*
+template <>
+struct MappingTraits<const lld::AbsoluteAtom*> {
+
+ class NormalizedAtom : public lld::AbsoluteAtom {
+ public:
+ NormalizedAtom(IO &io)
+ : _file(fileFromContext(io)), _name(), _scope(), _value(0) {
+ }
+ NormalizedAtom(IO &io, const lld::AbsoluteAtom *atom)
+ : _file(fileFromContext(io)),
+ _name(atom->name()),
+ _scope(atom->scope()),
+ _value(atom->value()) {
+ }
+ const lld::AbsoluteAtom *denormalize(IO &io) {
+ ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
+ assert(info != nullptr);
+ typedef MappingTraits<const lld::File*>::NormalizedFile NormalizedFile;
+ NormalizedFile *f = reinterpret_cast<NormalizedFile*>(info->_currentFile);
+ if ( !_name.empty() )
+ _name = f->copyString(_name);
+
+ DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
+ << "created AbsoluteAtom named: '" << _name
+ << "' (" << (void*)_name.data() << ", "
+ << _name.size() << ")\n");
+ return this;
+ }
+ // Extract current File object from YAML I/O parsing context
+ const lld::File &fileFromContext(IO &io) {
+ ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
+ assert(info != nullptr);
+ assert(info->_currentFile != nullptr);
+ return *info->_currentFile;
+ }
+
+ virtual const lld::File &file() const { return _file; }
+ virtual StringRef name() const { return _name; }
+ virtual uint64_t value() const { return _value; }
+ virtual Scope scope() const { return _scope; }
+
+ const lld::File &_file;
+ StringRef _name;
+ StringRef _refName;
+ Scope _scope;
+ Hex64 _value;
+ };
+
+
+ static void mapping(IO &io, const lld::AbsoluteAtom *&atom) {
+ MappingNormalizationHeap<NormalizedAtom,
+ const lld::AbsoluteAtom*> keys(io, atom);
+
+ if ( io.outputting() ) {
+ typedef MappingTraits<const lld::File*>::NormalizedFile NormalizedFile;
+ ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
+ assert(info != nullptr);
+ NormalizedFile *f = reinterpret_cast<NormalizedFile*>(info->_currentFile);
+ assert(f);
+ assert(f->_rnb);
+ if ( f->_rnb->hasRefName(atom) ) {
+ keys->_refName = f->_rnb->refName(atom);
+ }
+ }
+
+ io.mapRequired("name", keys->_name);
+ io.mapOptional("ref-name", keys->_refName, StringRef());
+ io.mapOptional("scope", keys->_scope);
+ io.mapRequired("value", keys->_value);
+ }
+};
+
+
+RefNameResolver::RefNameResolver(const lld::File *file, IO &io) : _io(io) {
+ typedef MappingTraits<const lld::DefinedAtom*>::NormalizedAtom NormalizedAtom;
+ for (const lld::DefinedAtom *a : file->defined() ) {
+ NormalizedAtom *na = (NormalizedAtom*)a;
+ if ( na->_refName.empty() )
+ add(na->_name, a);
+ else
+ add(na->_refName, a);
+ }
+
+ for (const lld::UndefinedAtom *a : file->undefined() )
+ add(a->name(), a);
+
+ for (const lld::SharedLibraryAtom *a : file->sharedLibrary() )
+ add(a->name(), a);
+
+ typedef MappingTraits<const lld::AbsoluteAtom*>::NormalizedAtom NormAbsAtom;
+ for (const lld::AbsoluteAtom *a : file->absolute() ) {
+ NormAbsAtom *na = (NormAbsAtom*)a;
+ if ( na->_refName.empty() )
+ add(na->_name, a);
+ else
+ add(na->_refName, a);
+ }
+}
+
+
+inline
+llvm::StringRef MappingTraits<const lld::Reference*>::NormalizedReference::
+ targetName(IO &io, const lld::Reference *ref) {
+ if ( ref->target() == nullptr )
+ return llvm::StringRef();
+ ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
+ assert(info != nullptr);
+ typedef MappingTraits<const lld::File*>::NormalizedFile NormalizedFile;
+ NormalizedFile *f = reinterpret_cast<NormalizedFile*>(info->_currentFile);
+ RefNameBuilder *rnb = f->_rnb;
+ if ( rnb->hasRefName(ref->target()) )
+ return rnb->refName(ref->target());
+ return ref->target()->name();
+}
+
+
+
+namespace lld {
+namespace yaml {
+
+class Writer : public lld::Writer {
+public:
+ Writer(const WriterOptionsYAML &options) : _options(options) {
+ }
+
+ virtual error_code writeFile(const lld::File &file, StringRef outPath) {
+ // Create stream to path.
+ std::string errorInfo;
+ llvm::raw_fd_ostream out(outPath.data(), errorInfo);
+ if (!errorInfo.empty())
+ return llvm::make_error_code(llvm::errc::no_such_file_or_directory);
+
+ // Create yaml Output writer, using yaml options for context.
+ ContextInfo context(_options);
+ llvm::yaml::Output yout(out, &context);
+
+ // Write yaml output.
+ const lld::File *fileRef = &file;
+ yout << fileRef;
+
+ return error_code::success();
+ }
+
+ virtual StubsPass *stubPass() {
+ return _options.stubPass();
+ }
+
+ virtual GOTPass *gotPass() {
+ return _options.gotPass();
+ }
+
+
+private:
+ const WriterOptionsYAML &_options;
+};
+
+
+
+class ReaderYAML : public Reader {
+public:
+ ReaderYAML(const ReaderOptionsYAML &options) : _options(options) {
+ }
+
+ error_code parseFile(std::unique_ptr<MemoryBuffer> mb,
+ std::vector<std::unique_ptr<File>> &result) {
+ // Note: we do not take ownership of the MemoryBuffer. That is
+ // because yaml may produce multiple File objects, so there is no
+ // *one* File to take ownership. Therefore, the yaml File objects
+ // produced must make copies of all strings that come from YAML I/O.
+ // Otherwise the strings will become invalid when this MemoryBuffer
+ // is deallocated.
+
+ // Create YAML Input parser.
+ ContextInfo context(_options);
+ llvm::yaml::Input yin(mb->getBuffer(), &context);
+
+ // Fill vector with File objects created by parsing yaml.
+ std::vector<const lld::File*> createdFiles;
+ yin >> createdFiles;
+
+ // Quit now if there were parsing errors.
+ if ( yin.error() )
+ return make_error_code(lld::yaml_reader_error::illegal_value);
+
+ for (const File *file : createdFiles) {
+ // Note: parseFile() should return vector of *const* File
+ File *f = const_cast<File*>(file);
+ result.emplace_back(f);
+ }
+ return make_error_code(lld::yaml_reader_error::success);
+ }
+
+private:
+ const ReaderOptionsYAML &_options;
+};
+
+
+
+} // namespace yaml
+
+
+Writer *createWriterYAML(const WriterOptionsYAML &options) {
+ return new lld::yaml::Writer(options);
+}
+
+WriterOptionsYAML::WriterOptionsYAML() {
+}
+
+WriterOptionsYAML::~WriterOptionsYAML() {
+}
+
+
+
+Reader *createReaderYAML(const ReaderOptionsYAML &options) {
+ return new lld::yaml::ReaderYAML(options);
+}
+
+ReaderOptionsYAML::ReaderOptionsYAML() {
+}
+
+ReaderOptionsYAML::~ReaderOptionsYAML() {
+}
+
+
+} // namespace lld
+
OpenPOWER on IntegriCloud