Files
clang-p2996/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
Chandler Carruth 2946cd7010 Update the file headers across all of the LLVM projects in the monorepo
to reflect the new license.

We understand that people may be surprised that we're moving the header
entirely to discuss the new license. We checked this carefully with the
Foundation's lawyer and we believe this is the correct approach.

Essentially, all code in the project is now made available by the LLVM
project under our new license, so you will see that the license headers
include that license only. Some of our contributors have contributed
code under our old license, and accordingly, we have retained a copy of
our old license notice in the top-level files in each project and
repository.

llvm-svn: 351636
2019-01-19 08:50:56 +00:00

1404 lines
54 KiB
C++

//===- lib/ReaderWriter/YAML/ReaderWriterYAML.cpp -------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "lld/Core/AbsoluteAtom.h"
#include "lld/Core/ArchiveLibraryFile.h"
#include "lld/Core/Atom.h"
#include "lld/Core/DefinedAtom.h"
#include "lld/Core/Error.h"
#include "lld/Core/File.h"
#include "lld/Core/LinkingContext.h"
#include "lld/Core/Reader.h"
#include "lld/Core/Reference.h"
#include "lld/Core/SharedLibraryAtom.h"
#include "lld/Core/Simple.h"
#include "lld/Core/UndefinedAtom.h"
#include "lld/Core/Writer.h"
#include "lld/ReaderWriter/YamlContext.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/BinaryFormat/Magic.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <cstdint>
#include <cstring>
#include <memory>
#include <string>
#include <system_error>
#include <vector>
using llvm::file_magic;
using llvm::yaml::MappingTraits;
using llvm::yaml::ScalarEnumerationTraits;
using llvm::yaml::ScalarTraits;
using llvm::yaml::IO;
using llvm::yaml::SequenceTraits;
using llvm::yaml::DocumentListTraits;
using namespace lld;
/// 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 {
/// 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) {
// 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++);
StringRef newName = copyString(buffer.str());
_refNames[target] = newName;
DEBUG_WITH_TYPE("WriterYAML",
llvm::dbgs() << "unnamed atom: creating ref-name: '"
<< newName << "' ("
<< (const 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()) {
if (!absAtom->name().empty())
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);
StringRef newName = copyString(buffer.str());
_refNames[&atom] = newName;
DEBUG_WITH_TYPE("WriterYAML",
llvm::dbgs() << "name collsion: creating ref-name: '"
<< newName << "' ("
<< (const 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);
StringRef newName2 = copyString(buffer2.str());
_refNames[prevAtom] = newName2;
DEBUG_WITH_TYPE("WriterYAML",
llvm::dbgs() << "name collsion: creating ref-name: '"
<< newName2 << "' ("
<< (const 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() << "' ("
<< (const void *)atom.name().data()
<< ", " << atom.name().size() << ")\n");
}
}
bool hasRefName(const lld::Atom *atom) { return _refNames.count(atom); }
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 in _storage, so the strings
// can be freed when RefNameBuilder is destroyed.
StringRef copyString(StringRef str) {
char *s = _storage.Allocate<char>(str.size());
memcpy(s, str.data(), str.size());
return StringRef(s, str.size());
}
unsigned int _collisionCount;
unsigned int _unnamedCounter;
NameToAtom _nameMap;
AtomToRefName _refNames;
llvm::BumpPtrAllocator _storage;
};
/// 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(StringRef name) const {
NameToAtom::const_iterator pos = _nameMap.find(name);
if (pos != _nameMap.end())
return pos->second;
_io.setError(Twine("no such atom name: ") + name);
return nullptr;
}
private:
typedef llvm::StringMap<const lld::Atom *> NameToAtom;
void add(StringRef name, const lld::Atom *atom) {
if (_nameMap.count(name)) {
_io.setError(Twine("duplicate atom name: ") + name);
} else {
_nameMap[name] = atom;
}
}
IO &_io;
NameToAtom _nameMap;
};
/// Mapping of Atoms.
template <typename T> class AtomList {
using Ty = std::vector<OwningAtomPtr<T>>;
public:
typename Ty::iterator begin() { return _atoms.begin(); }
typename Ty::iterator end() { return _atoms.end(); }
Ty _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
fileKindObjectMachO // mach-o object files encoded in yaml
};
struct ArchMember {
FileKinds _kind;
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 tuple of <namespace, arch, value>.
// For yaml, we just want one string that encapsulates the tuple.
struct RefKind {
Reference::KindNamespace ns;
Reference::KindArch arch;
Reference::KindValue value;
};
} // end anonymous namespace
LLVM_YAML_IS_SEQUENCE_VECTOR(ArchMember)
LLVM_YAML_IS_SEQUENCE_VECTOR(const lld::Reference *)
// Always write DefinedAtoms content bytes as a flow sequence.
LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(ImplicitHex8)
// for compatibility with gcc-4.7 in C++11 mode, add extra namespace
namespace llvm {
namespace yaml {
// This is a custom formatter for RefKind
template <> struct ScalarTraits<RefKind> {
static void output(const RefKind &kind, void *ctxt, raw_ostream &out) {
assert(ctxt != nullptr);
YamlContext *info = reinterpret_cast<YamlContext *>(ctxt);
assert(info->_registry);
StringRef str;
if (info->_registry->referenceKindToString(kind.ns, kind.arch, kind.value,
str))
out << str;
else
out << (int)(kind.ns) << "-" << (int)(kind.arch) << "-" << kind.value;
}
static StringRef input(StringRef scalar, void *ctxt, RefKind &kind) {
assert(ctxt != nullptr);
YamlContext *info = reinterpret_cast<YamlContext *>(ctxt);
assert(info->_registry);
if (info->_registry->referenceKindFromString(scalar, kind.ns, kind.arch,
kind.value))
return StringRef();
return StringRef("unknown reference kind");
}
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
template <> struct ScalarEnumerationTraits<lld::File::Kind> {
static void enumeration(IO &io, lld::File::Kind &value) {
io.enumCase(value, "error-object", lld::File::kindErrorObject);
io.enumCase(value, "object", lld::File::kindMachObject);
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", DefinedAtom::interposeNo);
io.enumCase(value, "yes", DefinedAtom::interposeYes);
io.enumCase(value, "yes-and-weak", 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);
io.enumCase(value, "by-content", lld::DefinedAtom::mergeByContent);
io.enumCase(value, "same-name-and-size",
lld::DefinedAtom::mergeSameNameAndSize);
io.enumCase(value, "largest", lld::DefinedAtom::mergeByLargestSection);
}
};
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::DynamicExport> {
static void enumeration(IO &io, lld::DefinedAtom::DynamicExport &value) {
io.enumCase(value, "normal", lld::DefinedAtom::dynamicExportNormal);
io.enumCase(value, "always", lld::DefinedAtom::dynamicExportAlways);
}
};
template <> struct ScalarEnumerationTraits<lld::DefinedAtom::CodeModel> {
static void enumeration(IO &io, lld::DefinedAtom::CodeModel &value) {
io.enumCase(value, "none", lld::DefinedAtom::codeNA);
io.enumCase(value, "mips-pic", lld::DefinedAtom::codeMipsPIC);
io.enumCase(value, "mips-micro", lld::DefinedAtom::codeMipsMicro);
io.enumCase(value, "mips-micro-pic", lld::DefinedAtom::codeMipsMicroPIC);
io.enumCase(value, "mips-16", lld::DefinedAtom::codeMips16);
io.enumCase(value, "arm-thumb", lld::DefinedAtom::codeARMThumb);
io.enumCase(value, "arm-a", lld::DefinedAtom::codeARM_a);
io.enumCase(value, "arm-d", lld::DefinedAtom::codeARM_d);
io.enumCase(value, "arm-t", lld::DefinedAtom::codeARM_t);
}
};
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);
io.enumCase(value, "unknown", lld::DefinedAtom::permUnknown);
}
};
template <> struct ScalarEnumerationTraits<lld::DefinedAtom::ContentType> {
static void enumeration(IO &io, lld::DefinedAtom::ContentType &value) {
io.enumCase(value, "unknown", DefinedAtom::typeUnknown);
io.enumCase(value, "code", DefinedAtom::typeCode);
io.enumCase(value, "stub", DefinedAtom::typeStub);
io.enumCase(value, "constant", DefinedAtom::typeConstant);
io.enumCase(value, "data", DefinedAtom::typeData);
io.enumCase(value, "quick-data", DefinedAtom::typeDataFast);
io.enumCase(value, "zero-fill", DefinedAtom::typeZeroFill);
io.enumCase(value, "zero-fill-quick", DefinedAtom::typeZeroFillFast);
io.enumCase(value, "const-data", DefinedAtom::typeConstData);
io.enumCase(value, "got", DefinedAtom::typeGOT);
io.enumCase(value, "resolver", DefinedAtom::typeResolver);
io.enumCase(value, "branch-island", DefinedAtom::typeBranchIsland);
io.enumCase(value, "branch-shim", DefinedAtom::typeBranchShim);
io.enumCase(value, "stub-helper", DefinedAtom::typeStubHelper);
io.enumCase(value, "c-string", DefinedAtom::typeCString);
io.enumCase(value, "utf16-string", DefinedAtom::typeUTF16String);
io.enumCase(value, "unwind-cfi", DefinedAtom::typeCFI);
io.enumCase(value, "unwind-lsda", DefinedAtom::typeLSDA);
io.enumCase(value, "const-4-byte", DefinedAtom::typeLiteral4);
io.enumCase(value, "const-8-byte", DefinedAtom::typeLiteral8);
io.enumCase(value, "const-16-byte", DefinedAtom::typeLiteral16);
io.enumCase(value, "lazy-pointer", DefinedAtom::typeLazyPointer);
io.enumCase(value, "lazy-dylib-pointer",
DefinedAtom::typeLazyDylibPointer);
io.enumCase(value, "cfstring", DefinedAtom::typeCFString);
io.enumCase(value, "initializer-pointer",
DefinedAtom::typeInitializerPtr);
io.enumCase(value, "terminator-pointer",
DefinedAtom::typeTerminatorPtr);
io.enumCase(value, "c-string-pointer",DefinedAtom::typeCStringPtr);
io.enumCase(value, "objc-class-pointer",
DefinedAtom::typeObjCClassPtr);
io.enumCase(value, "objc-category-list",
DefinedAtom::typeObjC2CategoryList);
io.enumCase(value, "objc-image-info",
DefinedAtom::typeObjCImageInfo);
io.enumCase(value, "objc-method-list",
DefinedAtom::typeObjCMethodList);
io.enumCase(value, "objc-class1", DefinedAtom::typeObjC1Class);
io.enumCase(value, "dtraceDOF", DefinedAtom::typeDTraceDOF);
io.enumCase(value, "interposing-tuples",
DefinedAtom::typeInterposingTuples);
io.enumCase(value, "lto-temp", DefinedAtom::typeTempLTO);
io.enumCase(value, "compact-unwind", DefinedAtom::typeCompactUnwindInfo);
io.enumCase(value, "unwind-info", DefinedAtom::typeProcessedUnwindInfo);
io.enumCase(value, "tlv-thunk", DefinedAtom::typeThunkTLV);
io.enumCase(value, "tlv-data", DefinedAtom::typeTLVInitialData);
io.enumCase(value, "tlv-zero-fill", DefinedAtom::typeTLVInitialZeroFill);
io.enumCase(value, "tlv-initializer-ptr",
DefinedAtom::typeTLVInitializerPtr);
io.enumCase(value, "mach_header", DefinedAtom::typeMachHeader);
io.enumCase(value, "dso_handle", DefinedAtom::typeDSOHandle);
io.enumCase(value, "sectcreate", DefinedAtom::typeSectCreate);
}
};
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);
}
};
template <>
struct ScalarEnumerationTraits<lld::SharedLibraryAtom::Type> {
static void enumeration(IO &io, lld::SharedLibraryAtom::Type &value) {
io.enumCase(value, "code", lld::SharedLibraryAtom::Type::Code);
io.enumCase(value, "data", lld::SharedLibraryAtom::Type::Data);
io.enumCase(value, "unknown", lld::SharedLibraryAtom::Type::Unknown);
}
};
/// This is a custom formatter for lld::DefinedAtom::Alignment. Values look
/// like:
/// 8 # 8-byte aligned
/// 7 mod 16 # 16-byte aligned plus 7 bytes
template <> struct ScalarTraits<lld::DefinedAtom::Alignment> {
static void output(const lld::DefinedAtom::Alignment &value, void *ctxt,
raw_ostream &out) {
if (value.modulus == 0) {
out << llvm::format("%d", value.value);
} else {
out << llvm::format("%d mod %d", value.modulus, value.value);
}
}
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();
}
unsigned int power;
if (scalar.getAsInteger(0, power)) {
return "malformed alignment power";
}
value.value = power;
if (value.modulus >= power) {
return "malformed alignment, modulus too large for power";
}
return StringRef(); // returning empty string means success
}
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
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-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);
}
};
// 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 T *&element(IO &io, AtomList<T> &seq, size_t index) {
if (index >= seq._atoms.size())
seq._atoms.resize(index + 1);
return seq._atoms[index].get();
}
};
// Declare that an AtomRange is a yaml sequence.
template <typename T> struct SequenceTraits<File::AtomRange<T> > {
static size_t size(IO &io, File::AtomRange<T> &seq) { return seq.size(); }
static T *&element(IO &io, File::AtomRange<T> &seq, size_t index) {
assert(io.outputting() && "AtomRange only used when outputting");
assert(index < seq.size() && "Out of range access");
return seq[index].get();
}
};
// 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 *, raw_ostream &out) {
uint8_t num = val;
out << llvm::format("%02X", num);
}
static StringRef input(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
}
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
// 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("") {}
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; }
const AtomRange<lld::DefinedAtom> defined() const override {
return _noDefinedAtoms;
}
const AtomRange<lld::UndefinedAtom> undefined() const override {
return _noUndefinedAtoms;
}
const AtomRange<lld::SharedLibraryAtom> sharedLibrary() const override {
return _noSharedLibraryAtoms;
}
const AtomRange<lld::AbsoluteAtom> absolute() const override {
return _noAbsoluteAtoms;
}
void clearAtoms() override {
_noDefinedAtoms.clear();
_noUndefinedAtoms.clear();
_noSharedLibraryAtoms.clear();
_noAbsoluteAtoms.clear();
}
File *find(StringRef name) override {
for (const ArchMember &member : _members)
for (const lld::DefinedAtom *atom : member._content->defined())
if (name == atom->name())
return const_cast<File *>(member._content);
return nullptr;
}
std::error_code
parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
return std::error_code();
}
StringRef _path;
std::vector<ArchMember> _members;
};
class NormalizedFile : public lld::File {
public:
NormalizedFile(IO &io)
: File("", kindNormalizedObject), _io(io), _rnb(nullptr),
_definedAtomsRef(_definedAtoms._atoms),
_undefinedAtomsRef(_undefinedAtoms._atoms),
_sharedLibraryAtomsRef(_sharedLibraryAtoms._atoms),
_absoluteAtomsRef(_absoluteAtoms._atoms) {}
NormalizedFile(IO &io, const lld::File *file)
: File(file->path(), kindNormalizedObject), _io(io),
_rnb(new RefNameBuilder(*file)), _path(file->path()),
_definedAtomsRef(file->defined()),
_undefinedAtomsRef(file->undefined()),
_sharedLibraryAtomsRef(file->sharedLibrary()),
_absoluteAtomsRef(file->absolute()) {
}
~NormalizedFile() override {
}
const lld::File *denormalize(IO &io);
const AtomRange<lld::DefinedAtom> defined() const override {
return _definedAtomsRef;
}
const AtomRange<lld::UndefinedAtom> undefined() const override {
return _undefinedAtomsRef;
}
const AtomRange<lld::SharedLibraryAtom> sharedLibrary() const override {
return _sharedLibraryAtomsRef;
}
const AtomRange<lld::AbsoluteAtom> absolute() const override {
return _absoluteAtomsRef;
}
void clearAtoms() override {
_definedAtoms._atoms.clear();
_undefinedAtoms._atoms.clear();
_sharedLibraryAtoms._atoms.clear();
_absoluteAtoms._atoms.clear();
}
// Allocate a new copy of this string in _storage, so the strings
// can be freed when File is destroyed.
StringRef copyString(StringRef str) {
char *s = _storage.Allocate<char>(str.size());
memcpy(s, str.data(), str.size());
return StringRef(s, str.size());
}
IO &_io;
std::unique_ptr<RefNameBuilder> _rnb;
StringRef _path;
AtomList<lld::DefinedAtom> _definedAtoms;
AtomList<lld::UndefinedAtom> _undefinedAtoms;
AtomList<lld::SharedLibraryAtom> _sharedLibraryAtoms;
AtomList<lld::AbsoluteAtom> _absoluteAtoms;
AtomRange<lld::DefinedAtom> _definedAtomsRef;
AtomRange<lld::UndefinedAtom> _undefinedAtomsRef;
AtomRange<lld::SharedLibraryAtom> _sharedLibraryAtomsRef;
AtomRange<lld::AbsoluteAtom> _absoluteAtomsRef;
llvm::BumpPtrAllocator _storage;
};
static void mapping(IO &io, const lld::File *&file) {
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
assert(info != nullptr);
// Let any register tag handler process this.
if (info->_registry && info->_registry->handleTaggedDoc(io, file))
return;
// If no registered handler claims this tag and there is no tag,
// grandfather in as "!native".
if (io.mapTag("!native", true) || io.mapTag("tag:yaml.org,2002:map"))
mappingAtoms(io, file);
}
static void mappingAtoms(IO &io, const lld::File *&file) {
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
MappingNormalizationHeap<NormalizedFile, const lld::File *>
keys(io, file, nullptr);
assert(info != nullptr);
info->_file = keys.operator->();
io.mapOptional("path", keys->_path);
if (io.outputting()) {
io.mapOptional("defined-atoms", keys->_definedAtomsRef);
io.mapOptional("undefined-atoms", keys->_undefinedAtomsRef);
io.mapOptional("shared-library-atoms", keys->_sharedLibraryAtomsRef);
io.mapOptional("absolute-atoms", keys->_absoluteAtomsRef);
} else {
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) {
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
MappingNormalizationHeap<NormArchiveFile, const lld::File *>
keys(io, file, &info->_file->allocator());
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)
: lld::Reference(lld::Reference::KindNamespace::all,
lld::Reference::KindArch::all, 0),
_target(nullptr), _offset(0), _addend(0), _tag(0) {}
NormalizedReference(IO &io, const lld::Reference *ref)
: lld::Reference(ref->kindNamespace(), ref->kindArch(),
ref->kindValue()),
_target(nullptr), _targetName(targetName(io, ref)),
_offset(ref->offsetInAtom()), _addend(ref->addend()),
_tag(ref->tag()) {
_mappedKind.ns = ref->kindNamespace();
_mappedKind.arch = ref->kindArch();
_mappedKind.value = ref->kindValue();
}
const lld::Reference *denormalize(IO &io) {
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
assert(info != nullptr);
typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
if (!_targetName.empty())
_targetName = f->copyString(_targetName);
DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
<< "created Reference to name: '"
<< _targetName << "' ("
<< (const void *)_targetName.data()
<< ", " << _targetName.size() << ")\n");
setKindNamespace(_mappedKind.ns);
setKindArch(_mappedKind.arch);
setKindValue(_mappedKind.value);
return this;
}
void bind(const RefNameResolver &);
static StringRef targetName(IO &io, const lld::Reference *ref);
uint64_t offsetInAtom() const override { return _offset; }
const lld::Atom *target() const override { return _target; }
Addend addend() const override { return _addend; }
void setAddend(Addend a) override { _addend = a; }
void setTarget(const lld::Atom *a) override { _target = a; }
const lld::Atom *_target;
StringRef _targetName;
uint32_t _offset;
Addend _addend;
RefKind _mappedKind;
uint32_t _tag;
};
static void mapping(IO &io, const lld::Reference *&ref) {
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
MappingNormalizationHeap<NormalizedReference, const lld::Reference *> keys(
io, ref, &info->_file->allocator());
io.mapRequired("kind", keys->_mappedKind);
io.mapOptional("offset", keys->_offset);
io.mapOptional("target", keys->_targetName);
io.mapOptional("addend", keys->_addend, (lld::Reference::Addend)0);
io.mapOptional("tag", keys->_tag, 0u);
}
};
// YAML conversion for const lld::DefinedAtom*
template <> struct MappingTraits<const lld::DefinedAtom *> {
class NormalizedAtom : public lld::DefinedAtom {
public:
NormalizedAtom(IO &io)
: _file(fileFromContext(io)), _contentType(), _alignment(1) {
static uint32_t ordinalCounter = 1;
_ordinal = ordinalCounter++;
}
NormalizedAtom(IO &io, const lld::DefinedAtom *atom)
: _file(fileFromContext(io)), _name(atom->name()),
_scope(atom->scope()), _interpose(atom->interposable()),
_merge(atom->merge()), _contentType(atom->contentType()),
_alignment(atom->alignment()), _sectionChoice(atom->sectionChoice()),
_deadStrip(atom->deadStrip()), _dynamicExport(atom->dynamicExport()),
_codeModel(atom->codeModel()),
_permissions(atom->permissions()), _size(atom->size()),
_sectionName(atom->customSectionName()),
_sectionSize(atom->sectionSize()) {
for (const lld::Reference *r : *atom)
_references.push_back(r);
if (!atom->occupiesDiskSpace())
return;
ArrayRef<uint8_t> cont = atom->rawContent();
_content.reserve(cont.size());
for (uint8_t x : cont)
_content.push_back(x);
}
~NormalizedAtom() override = default;
const lld::DefinedAtom *denormalize(IO &io) {
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
assert(info != nullptr);
typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
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
<< "' (" << (const 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) {
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
assert(info != nullptr);
assert(info->_file != nullptr);
return *info->_file;
}
const lld::File &file() const override { return _file; }
StringRef name() const override { return _name; }
uint64_t size() const override { return _size; }
Scope scope() const override { return _scope; }
Interposable interposable() const override { return _interpose; }
Merge merge() const override { return _merge; }
ContentType contentType() const override { return _contentType; }
Alignment alignment() const override { return _alignment; }
SectionChoice sectionChoice() const override { return _sectionChoice; }
StringRef customSectionName() const override { return _sectionName; }
uint64_t sectionSize() const override { return _sectionSize; }
DeadStripKind deadStrip() const override { return _deadStrip; }
DynamicExport dynamicExport() const override { return _dynamicExport; }
CodeModel codeModel() const override { return _codeModel; }
ContentPermissions permissions() const override { return _permissions; }
ArrayRef<uint8_t> rawContent() const override {
if (!occupiesDiskSpace())
return ArrayRef<uint8_t>();
return ArrayRef<uint8_t>(
reinterpret_cast<const uint8_t *>(_content.data()), _content.size());
}
uint64_t ordinal() const override { return _ordinal; }
reference_iterator begin() const override {
uintptr_t index = 0;
const void *it = reinterpret_cast<const void *>(index);
return reference_iterator(*this, it);
}
reference_iterator end() const override {
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 override {
uintptr_t index = reinterpret_cast<uintptr_t>(it);
assert(index < _references.size());
return _references[index];
}
void incrementIterator(const void *&it) const override {
uintptr_t index = reinterpret_cast<uintptr_t>(it);
++index;
it = reinterpret_cast<const void *>(index);
}
void addReference(Reference::KindNamespace ns,
Reference::KindArch arch,
Reference::KindValue kindValue, uint64_t off,
const Atom *target, Reference::Addend a) override {
assert(target && "trying to create reference to nothing");
auto node = new (file().allocator()) SimpleReference(ns, arch, kindValue,
off, target, a);
_references.push_back(node);
}
const lld::File &_file;
StringRef _name;
StringRef _refName;
Scope _scope;
Interposable _interpose;
Merge _merge;
ContentType _contentType;
Alignment _alignment;
SectionChoice _sectionChoice;
DeadStripKind _deadStrip;
DynamicExport _dynamicExport;
CodeModel _codeModel;
ContentPermissions _permissions;
uint32_t _ordinal;
std::vector<ImplicitHex8> _content;
uint64_t _size;
StringRef _sectionName;
uint64_t _sectionSize;
std::vector<const lld::Reference *> _references;
};
static void mapping(IO &io, const lld::DefinedAtom *&atom) {
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
MappingNormalizationHeap<NormalizedAtom, const lld::DefinedAtom *> keys(
io, atom, &info->_file->allocator());
if (io.outputting()) {
// If writing YAML, check if atom needs a ref-name.
typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
assert(info != nullptr);
NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
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,
DefinedAtom::scopeTranslationUnit);
io.mapOptional("type", keys->_contentType,
DefinedAtom::typeCode);
io.mapOptional("content", keys->_content);
io.mapOptional("size", keys->_size, (uint64_t)keys->_content.size());
io.mapOptional("interposable", keys->_interpose,
DefinedAtom::interposeNo);
io.mapOptional("merge", keys->_merge, DefinedAtom::mergeNo);
io.mapOptional("alignment", keys->_alignment,
DefinedAtom::Alignment(1));
io.mapOptional("section-choice", keys->_sectionChoice,
DefinedAtom::sectionBasedOnContent);
io.mapOptional("section-name", keys->_sectionName, StringRef());
io.mapOptional("section-size", keys->_sectionSize, (uint64_t)0);
io.mapOptional("dead-strip", keys->_deadStrip,
DefinedAtom::deadStripNormal);
io.mapOptional("dynamic-export", keys->_dynamicExport,
DefinedAtom::dynamicExportNormal);
io.mapOptional("code-model", keys->_codeModel, DefinedAtom::codeNA);
// default permissions based on content type
io.mapOptional("permissions", keys->_permissions,
DefinedAtom::permissions(
keys->_contentType));
io.mapOptional("references", keys->_references);
}
};
template <> struct MappingTraits<lld::DefinedAtom *> {
static void mapping(IO &io, lld::DefinedAtom *&atom) {
const lld::DefinedAtom *atomPtr = atom;
MappingTraits<const lld::DefinedAtom *>::mapping(io, atomPtr);
atom = const_cast<lld::DefinedAtom *>(atomPtr);
}
};
// YAML conversion for const lld::UndefinedAtom*
template <> struct MappingTraits<const lld::UndefinedAtom *> {
class NormalizedAtom : public lld::UndefinedAtom {
public:
NormalizedAtom(IO &io)
: _file(fileFromContext(io)), _canBeNull(canBeNullNever) {}
NormalizedAtom(IO &io, const lld::UndefinedAtom *atom)
: _file(fileFromContext(io)), _name(atom->name()),
_canBeNull(atom->canBeNull()) {}
~NormalizedAtom() override = default;
const lld::UndefinedAtom *denormalize(IO &io) {
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
assert(info != nullptr);
typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
if (!_name.empty())
_name = f->copyString(_name);
DEBUG_WITH_TYPE("WriterYAML",
llvm::dbgs() << "created UndefinedAtom named: '" << _name
<< "' (" << (const void *)_name.data() << ", "
<< _name.size() << ")\n");
return this;
}
// Extract current File object from YAML I/O parsing context
const lld::File &fileFromContext(IO &io) {
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
assert(info != nullptr);
assert(info->_file != nullptr);
return *info->_file;
}
const lld::File &file() const override { return _file; }
StringRef name() const override { return _name; }
CanBeNull canBeNull() const override { return _canBeNull; }
const lld::File &_file;
StringRef _name;
CanBeNull _canBeNull;
};
static void mapping(IO &io, const lld::UndefinedAtom *&atom) {
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
MappingNormalizationHeap<NormalizedAtom, const lld::UndefinedAtom *> keys(
io, atom, &info->_file->allocator());
io.mapRequired("name", keys->_name);
io.mapOptional("can-be-null", keys->_canBeNull,
lld::UndefinedAtom::canBeNullNever);
}
};
template <> struct MappingTraits<lld::UndefinedAtom *> {
static void mapping(IO &io, lld::UndefinedAtom *&atom) {
const lld::UndefinedAtom *atomPtr = atom;
MappingTraits<const lld::UndefinedAtom *>::mapping(io, atomPtr);
atom = const_cast<lld::UndefinedAtom *>(atomPtr);
}
};
// YAML conversion for const lld::SharedLibraryAtom*
template <> struct MappingTraits<const lld::SharedLibraryAtom *> {
class NormalizedAtom : public lld::SharedLibraryAtom {
public:
NormalizedAtom(IO &io)
: _file(fileFromContext(io)), _canBeNull(false),
_type(Type::Unknown), _size(0) {}
NormalizedAtom(IO &io, const lld::SharedLibraryAtom *atom)
: _file(fileFromContext(io)), _name(atom->name()),
_loadName(atom->loadName()), _canBeNull(atom->canBeNullAtRuntime()),
_type(atom->type()), _size(atom->size()) {}
~NormalizedAtom() override = default;
const lld::SharedLibraryAtom *denormalize(IO &io) {
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
assert(info != nullptr);
typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
if (!_name.empty())
_name = f->copyString(_name);
if (!_loadName.empty())
_loadName = f->copyString(_loadName);
DEBUG_WITH_TYPE("WriterYAML",
llvm::dbgs() << "created SharedLibraryAtom named: '"
<< _name << "' ("
<< (const void *)_name.data()
<< ", " << _name.size() << ")\n");
return this;
}
// Extract current File object from YAML I/O parsing context
const lld::File &fileFromContext(IO &io) {
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
assert(info != nullptr);
assert(info->_file != nullptr);
return *info->_file;
}
const lld::File &file() const override { return _file; }
StringRef name() const override { return _name; }
StringRef loadName() const override { return _loadName; }
bool canBeNullAtRuntime() const override { return _canBeNull; }
Type type() const override { return _type; }
uint64_t size() const override { return _size; }
const lld::File &_file;
StringRef _name;
StringRef _loadName;
ShlibCanBeNull _canBeNull;
Type _type;
uint64_t _size;
};
static void mapping(IO &io, const lld::SharedLibraryAtom *&atom) {
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
MappingNormalizationHeap<NormalizedAtom, const lld::SharedLibraryAtom *>
keys(io, atom, &info->_file->allocator());
io.mapRequired("name", keys->_name);
io.mapOptional("load-name", keys->_loadName);
io.mapOptional("can-be-null", keys->_canBeNull, (ShlibCanBeNull) false);
io.mapOptional("type", keys->_type, SharedLibraryAtom::Type::Code);
io.mapOptional("size", keys->_size, uint64_t(0));
}
};
template <> struct MappingTraits<lld::SharedLibraryAtom *> {
static void mapping(IO &io, lld::SharedLibraryAtom *&atom) {
const lld::SharedLibraryAtom *atomPtr = atom;
MappingTraits<const lld::SharedLibraryAtom *>::mapping(io, atomPtr);
atom = const_cast<lld::SharedLibraryAtom *>(atomPtr);
}
};
// YAML conversion for const lld::AbsoluteAtom*
template <> struct MappingTraits<const lld::AbsoluteAtom *> {
class NormalizedAtom : public lld::AbsoluteAtom {
public:
NormalizedAtom(IO &io)
: _file(fileFromContext(io)), _scope(), _value(0) {}
NormalizedAtom(IO &io, const lld::AbsoluteAtom *atom)
: _file(fileFromContext(io)), _name(atom->name()),
_scope(atom->scope()), _value(atom->value()) {}
~NormalizedAtom() override = default;
const lld::AbsoluteAtom *denormalize(IO &io) {
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
assert(info != nullptr);
typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
if (!_name.empty())
_name = f->copyString(_name);
DEBUG_WITH_TYPE("WriterYAML",
llvm::dbgs() << "created AbsoluteAtom named: '" << _name
<< "' (" << (const void *)_name.data()
<< ", " << _name.size() << ")\n");
return this;
}
// Extract current File object from YAML I/O parsing context
const lld::File &fileFromContext(IO &io) {
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
assert(info != nullptr);
assert(info->_file != nullptr);
return *info->_file;
}
const lld::File &file() const override { return _file; }
StringRef name() const override { return _name; }
uint64_t value() const override { return _value; }
Scope scope() const override { return _scope; }
const lld::File &_file;
StringRef _name;
StringRef _refName;
Scope _scope;
Hex64 _value;
};
static void mapping(IO &io, const lld::AbsoluteAtom *&atom) {
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
MappingNormalizationHeap<NormalizedAtom, const lld::AbsoluteAtom *> keys(
io, atom, &info->_file->allocator());
if (io.outputting()) {
typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
assert(info != nullptr);
NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
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);
}
};
template <> struct MappingTraits<lld::AbsoluteAtom *> {
static void mapping(IO &io, lld::AbsoluteAtom *&atom) {
const lld::AbsoluteAtom *atomPtr = atom;
MappingTraits<const lld::AbsoluteAtom *>::mapping(io, atomPtr);
atom = const_cast<lld::AbsoluteAtom *>(atomPtr);
}
};
} // end namespace llvm
} // end namespace yaml
RefNameResolver::RefNameResolver(const lld::File *file, IO &io) : _io(io) {
typedef MappingTraits<const lld::DefinedAtom *>::NormalizedAtom
NormalizedAtom;
for (const lld::DefinedAtom *a : file->defined()) {
const auto *na = (const NormalizedAtom *)a;
if (!na->_refName.empty())
add(na->_refName, a);
else if (!na->_name.empty())
add(na->_name, 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()) {
const auto *na = (const NormAbsAtom *)a;
if (na->_refName.empty())
add(na->_name, a);
else
add(na->_refName, a);
}
}
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()) {
auto *normAtom = (NormalizedAtom *)const_cast<DefinedAtom *>(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) {
auto *normRef = (NormalizedReference *)const_cast<Reference *>(ref);
normRef->bind(resolver);
}
}
inline void MappingTraits<const lld::Reference *>::NormalizedReference::bind(
const RefNameResolver &resolver) {
_target = resolver.lookup(_targetName);
}
inline StringRef
MappingTraits<const lld::Reference *>::NormalizedReference::targetName(
IO &io, const lld::Reference *ref) {
if (ref->target() == nullptr)
return StringRef();
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
assert(info != nullptr);
typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
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 LinkingContext &context) : _ctx(context) {}
llvm::Error writeFile(const lld::File &file, StringRef outPath) override {
// Create stream to path.
std::error_code ec;
llvm::raw_fd_ostream out(outPath, ec, llvm::sys::fs::F_Text);
if (ec)
return llvm::errorCodeToError(ec);
// Create yaml Output writer, using yaml options for context.
YamlContext yamlContext;
yamlContext._ctx = &_ctx;
yamlContext._registry = &_ctx.registry();
llvm::yaml::Output yout(out, &yamlContext);
// Write yaml output.
const lld::File *fileRef = &file;
yout << fileRef;
return llvm::Error::success();
}
private:
const LinkingContext &_ctx;
};
} // end namespace yaml
namespace {
/// Handles !native tagged yaml documents.
class NativeYamlIOTaggedDocumentHandler : public YamlIOTaggedDocumentHandler {
bool handledDocTag(llvm::yaml::IO &io, const lld::File *&file) const override {
if (io.mapTag("!native")) {
MappingTraits<const lld::File *>::mappingAtoms(io, file);
return true;
}
return false;
}
};
/// Handles !archive tagged yaml documents.
class ArchiveYamlIOTaggedDocumentHandler : public YamlIOTaggedDocumentHandler {
bool handledDocTag(llvm::yaml::IO &io, const lld::File *&file) const override {
if (io.mapTag("!archive")) {
MappingTraits<const lld::File *>::mappingArchive(io, file);
return true;
}
return false;
}
};
class YAMLReader : public Reader {
public:
YAMLReader(const Registry &registry) : _registry(registry) {}
bool canParse(file_magic magic, MemoryBufferRef mb) const override {
StringRef name = mb.getBufferIdentifier();
return name.endswith(".objtxt") || name.endswith(".yaml");
}
ErrorOr<std::unique_ptr<File>>
loadFile(std::unique_ptr<MemoryBuffer> mb,
const class Registry &) const override {
// Create YAML Input Reader.
YamlContext yamlContext;
yamlContext._registry = &_registry;
yamlContext._path = mb->getBufferIdentifier();
llvm::yaml::Input yin(mb->getBuffer(), &yamlContext);
// Fill vector with File objects created by parsing yaml.
std::vector<const lld::File *> createdFiles;
yin >> createdFiles;
assert(createdFiles.size() == 1);
// Error out now if there were parsing errors.
if (yin.error())
return make_error_code(lld::YamlReaderError::illegal_value);
std::shared_ptr<MemoryBuffer> smb(mb.release());
const File *file = createdFiles[0];
// Note: loadFile() should return vector of *const* File
File *f = const_cast<File *>(file);
f->setLastError(std::error_code());
f->setSharedMemoryBuffer(smb);
return std::unique_ptr<File>(f);
}
private:
const Registry &_registry;
};
} // end anonymous namespace
void Registry::addSupportYamlFiles() {
add(std::unique_ptr<Reader>(new YAMLReader(*this)));
add(std::unique_ptr<YamlIOTaggedDocumentHandler>(
new NativeYamlIOTaggedDocumentHandler()));
add(std::unique_ptr<YamlIOTaggedDocumentHandler>(
new ArchiveYamlIOTaggedDocumentHandler()));
}
std::unique_ptr<Writer> createWriterYAML(const LinkingContext &context) {
return std::unique_ptr<Writer>(new lld::yaml::Writer(context));
}
} // end namespace lld