summaryrefslogtreecommitdiffstats
path: root/lld/lib/ReaderWriter/YAML/ReaderYAML.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lld/lib/ReaderWriter/YAML/ReaderYAML.cpp')
-rw-r--r--lld/lib/ReaderWriter/YAML/ReaderYAML.cpp1264
1 files changed, 1264 insertions, 0 deletions
diff --git a/lld/lib/ReaderWriter/YAML/ReaderYAML.cpp b/lld/lib/ReaderWriter/YAML/ReaderYAML.cpp
new file mode 100644
index 00000000000..8da77713698
--- /dev/null
+++ b/lld/lib/ReaderWriter/YAML/ReaderYAML.cpp
@@ -0,0 +1,1264 @@
+//===- lib/ReaderWriter/YAML/ReaderYAML.cpp - Reads YAML object files -----===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/ReaderWriter/ReaderYAML.h"
+
+#include "lld/Core/AbsoluteAtom.h"
+#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/Atom.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/SharedLibraryAtom.h"
+#include "lld/Core/UndefinedAtom.h"
+
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/system_error.h"
+#include "llvm/Support/YAMLParser.h"
+
+#include <cstring>
+#include <vector>
+
+#include "YamlKeyValues.h"
+
+
+namespace lld {
+namespace yaml {
+
+
+///
+/// Concrete instance of lld::Reference created parsing YAML object files
+///
+class YAMLReference : public Reference {
+public:
+ YAMLReference()
+ : _target(nullptr)
+ , _targetNameNode(nullptr)
+ , _offsetInAtom(0)
+ , _addend(0)
+ , _kind(0)
+ {}
+
+ virtual uint64_t offsetInAtom() const {
+ return _offsetInAtom;
+ }
+
+ virtual Kind kind() const {
+ return _kind;
+ }
+
+ virtual void setKind(Kind k) {
+ _kind = k;
+ }
+
+ virtual const Atom *target() const {
+ return _target;
+ }
+
+ virtual Addend addend() const {
+ return _addend;
+ }
+
+ virtual void setAddend(Addend a) {
+ _addend = a;
+ }
+
+ virtual void setTarget(const Atom *newAtom) {
+ _target = newAtom;
+ }
+
+ typedef llvm::yaml::ScalarNode ScalarNode;
+
+ const Atom *_target;
+ ScalarNode * _targetNameNode;
+ uint64_t _offsetInAtom;
+ Addend _addend;
+ Kind _kind;
+};
+
+
+///
+/// Concrete instance of lld::File created parsing YAML object files.
+///
+class YAMLFile : public ArchiveLibraryFile {
+public:
+ YAMLFile()
+ : ArchiveLibraryFile("<anonymous>")
+ , _lastRefIndex(0)
+ , _kind(File::kindObject) {
+ }
+
+ ~YAMLFile();
+
+ // Depending on the YAML description, this file can be either an
+ // lld::ArchiveLibraryFile or lld::File.
+ virtual File::Kind kind() const {
+ return _kind;
+ }
+
+ virtual const atom_collection<DefinedAtom> &defined() const {
+ return _definedAtoms;
+ }
+ virtual const atom_collection<UndefinedAtom> &undefined() const {
+ return _undefinedAtoms;
+ }
+ virtual const atom_collection<SharedLibraryAtom> &sharedLibrary() const {
+ return _sharedLibraryAtoms;
+ }
+ virtual const atom_collection<AbsoluteAtom> &absolute() const {
+ return _absoluteAtoms;
+ }
+
+ virtual void addAtom(const Atom&) {
+ assert(0 && "cannot add atoms to YAML files");
+ }
+
+ // Standard way that archives are searched.
+ virtual const File *find(StringRef name, bool dataSymbolOnly) const;
+
+ error_code bindTargetReferences(llvm::yaml::Stream &stream);
+
+ void addDefinedAtom(class YAMLDefinedAtom *atom, StringRef refName);
+ void addUndefinedAtom(UndefinedAtom *atom);
+ void addSharedLibraryAtom(SharedLibraryAtom *atom);
+ void addAbsoluteAtom(AbsoluteAtom *atom);
+ Atom *findAtom(StringRef name);
+ void addMember(StringRef);
+ void setName(StringRef);
+
+ StringRef copyString(StringRef);
+
+ struct NameAtomPair {
+ NameAtomPair(StringRef n, Atom *a) : name(n), atom(a) {}
+ StringRef name;
+ Atom *atom;
+ };
+
+ atom_collection_vector<DefinedAtom> _definedAtoms;
+ atom_collection_vector<UndefinedAtom> _undefinedAtoms;
+ atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
+ atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
+ std::vector<YAMLReference> _references;
+ std::vector<NameAtomPair> _nameToAtomMapping;
+ std::vector<std::unique_ptr<YAMLFile>> _memberFiles;
+ std::vector<char*> _stringCopies;
+ unsigned int _lastRefIndex;
+ File::Kind _kind;
+};
+
+
+
+///
+/// Concrete instance of lld::DefinedAtom created parsing YAML object files.
+///
+class YAMLDefinedAtom : public DefinedAtom {
+public:
+ YAMLDefinedAtom( uint32_t ord
+ , YAMLFile &file
+ , DefinedAtom::Scope scope
+ , DefinedAtom::ContentType type
+ , DefinedAtom::SectionChoice sectionChoice
+ , DefinedAtom::Interposable interpose
+ , DefinedAtom::Merge merge
+ , DefinedAtom::DeadStripKind deadStrip
+ , DefinedAtom::ContentPermissions perms
+ , bool isThumb
+ , bool isAlias
+ , DefinedAtom::Alignment alignment
+ , StringRef name
+ , StringRef sectionName
+ , uint64_t size
+ , std::vector<uint8_t>& content)
+ : _file(file)
+ , _name(name)
+ , _sectionName(sectionName)
+ , _size(size)
+ , _ord(ord)
+ , _content(content)
+ , _alignment(alignment)
+ , _scope(scope)
+ , _type(type)
+ , _sectionChoice(sectionChoice)
+ , _interpose(interpose)
+ , _merge(merge)
+ , _deadStrip(deadStrip)
+ , _permissions(perms)
+ , _isThumb(isThumb)
+ , _isAlias(isAlias)
+ , _refStartIndex(file._lastRefIndex)
+ , _refEndIndex(file._references.size()) {
+ file._lastRefIndex = _refEndIndex;
+ }
+
+ virtual const class File &file() const {
+ return _file;
+ }
+
+ virtual StringRef name() const {
+ return _name;
+ }
+
+ virtual uint64_t size() const {
+ return _content.empty() ? _size : _content.size();
+ }
+
+ virtual DefinedAtom::Scope scope() const {
+ return _scope;
+ }
+
+ virtual DefinedAtom::Interposable interposable() const {
+ return _interpose;
+ }
+
+ virtual DefinedAtom::Merge merge() const {
+ return _merge;
+ }
+
+ virtual DefinedAtom::ContentType contentType() const {
+ return _type;
+ }
+
+ virtual DefinedAtom::Alignment alignment() const {
+ return _alignment;
+ }
+
+ virtual DefinedAtom::SectionChoice sectionChoice() const {
+ return _sectionChoice;
+ }
+
+ virtual StringRef customSectionName() const {
+ return _sectionName;
+ }
+
+ virtual DefinedAtom::DeadStripKind deadStrip() const {
+ return _deadStrip;
+ }
+
+ virtual DefinedAtom::ContentPermissions permissions() const {
+ return _permissions;
+ }
+
+ virtual bool isThumb() const {
+ return _isThumb;
+ }
+
+ virtual bool isAlias() const {
+ return _isAlias;
+ }
+
+ ArrayRef<uint8_t> rawContent() const {
+ return ArrayRef<uint8_t>(_content);
+ }
+
+ virtual uint64_t ordinal() const {
+ return _ord;
+ }
+
+ DefinedAtom::reference_iterator begin() const {
+ uintptr_t index = _refStartIndex;
+ const void* it = reinterpret_cast<const void*>(index);
+ return reference_iterator(*this, it);
+ }
+
+ DefinedAtom::reference_iterator end() const {
+ uintptr_t index = _refEndIndex;
+ const void* it = reinterpret_cast<const void*>(index);
+ return reference_iterator(*this, it);
+ }
+
+ const Reference* derefIterator(const void* it) const {
+ uintptr_t index = reinterpret_cast<uintptr_t>(it);
+ assert(index >= _refStartIndex);
+ assert(index < _refEndIndex);
+ assert(index < _file._references.size());
+ return &_file._references[index];
+ }
+
+ void incrementIterator(const void*& it) const {
+ uintptr_t index = reinterpret_cast<uintptr_t>(it);
+ ++index;
+ it = reinterpret_cast<const void*>(index);
+ }
+
+ // Convert each target name to a pointer to an atom object
+ error_code bindTargetReferences(llvm::yaml::Stream &stream) const {
+ for (unsigned int i=_refStartIndex; i < _refEndIndex; ++i) {
+ llvm::SmallString<32> storage;
+ llvm::yaml::ScalarNode *node = _file._references[i]._targetNameNode;
+ StringRef name = node->getValue(storage);
+ Atom *targetAtom = _file.findAtom(name);
+ if ( targetAtom ) {
+ _file._references[i]._target = targetAtom;
+ }
+ else {
+ stream.printError(node, "Fixup has target '" + name
+ + "' which does not exist");
+ return make_error_code(yaml_reader_error::illegal_value);
+ }
+ }
+ return make_error_code(yaml_reader_error::success);
+ }
+
+private:
+ YAMLFile &_file;
+ StringRef _name;
+ StringRef _sectionName;
+ unsigned long _size;
+ uint32_t _ord;
+ std::vector<uint8_t> _content;
+ DefinedAtom::Alignment _alignment;
+ DefinedAtom::Scope _scope;
+ DefinedAtom::ContentType _type;
+ DefinedAtom::SectionChoice _sectionChoice;
+ DefinedAtom::Interposable _interpose;
+ DefinedAtom::Merge _merge;
+ DefinedAtom::DeadStripKind _deadStrip;
+ DefinedAtom::ContentPermissions _permissions;
+ bool _isThumb;
+ bool _isAlias;
+ unsigned int _refStartIndex;
+ unsigned int _refEndIndex;
+};
+
+
+
+///
+/// Concrete instance of lld::UndefinedAtom created parsing YAML object files.
+///
+class YAMLUndefinedAtom : public UndefinedAtom {
+public:
+ YAMLUndefinedAtom( YAMLFile &f
+ , int32_t ord
+ , StringRef name
+ , UndefinedAtom::CanBeNull cbn)
+ : _file(f)
+ , _name(name)
+ , _ordinal(ord)
+ , _canBeNull(cbn) {
+ }
+
+ virtual const class File &file() const {
+ return _file;
+ }
+
+ virtual StringRef name() const {
+ return _name;
+ }
+
+ virtual CanBeNull canBeNull() const {
+ return _canBeNull;
+ }
+
+private:
+ YAMLFile &_file;
+ StringRef _name;
+ uint32_t _ordinal;
+ UndefinedAtom::CanBeNull _canBeNull;
+};
+
+
+
+///
+/// Concrete instance of lld::SharedLibraryAtom created parsing YAML files.
+///
+class YAMLSharedLibraryAtom : public SharedLibraryAtom {
+public:
+ YAMLSharedLibraryAtom( YAMLFile &f
+ , int32_t ord
+ , StringRef name
+ , StringRef loadName
+ , bool cbn)
+ : _file(f)
+ , _name(name)
+ , _ordinal(ord)
+ , _loadName(loadName)
+ , _canBeNull(cbn) {
+ }
+
+ virtual const class File &file() const {
+ return _file;
+ }
+
+ virtual StringRef name() const {
+ return _name;
+ }
+
+ virtual StringRef loadName() const {
+ return _loadName;
+ }
+
+ virtual bool canBeNullAtRuntime() const {
+ return _canBeNull;
+ }
+
+private:
+ YAMLFile &_file;
+ StringRef _name;
+ uint32_t _ordinal;
+ StringRef _loadName;
+ bool _canBeNull;
+};
+
+
+
+///
+/// Concrete instance of lld::AbsoluteAtom created parsing YAML object files.
+///
+class YAMLAbsoluteAtom : public AbsoluteAtom {
+public:
+ YAMLAbsoluteAtom(YAMLFile &f, int32_t ord, StringRef name, uint64_t v)
+ : _file(f)
+ , _name(name)
+ , _ordinal(ord)
+ , _value(v) {
+ }
+
+ virtual const class File &file() const {
+ return _file;
+ }
+
+ virtual StringRef name() const {
+ return _name;
+ }
+
+ virtual uint64_t value() const {
+ return _value;
+ }
+
+private:
+ YAMLFile &_file;
+ StringRef _name;
+ uint32_t _ordinal;
+ uint64_t _value;
+};
+
+
+
+
+//===----------------------------------------------------------------------===//
+// YAMLFile methods
+//===----------------------------------------------------------------------===//
+
+YAMLFile::~YAMLFile() {
+ for (char *s : _stringCopies) {
+ delete [] s;
+ }
+}
+
+
+error_code YAMLFile::bindTargetReferences(llvm::yaml::Stream &stream) {
+ error_code ec;
+ for (const DefinedAtom *defAtom : _definedAtoms) {
+ const YAMLDefinedAtom *atom =
+ reinterpret_cast<const YAMLDefinedAtom*>(defAtom);
+ ec = atom->bindTargetReferences(stream);
+ if ( ec )
+ return ec;
+ }
+ return ec;
+}
+
+Atom *YAMLFile::findAtom(StringRef name) {
+ for (auto &ci : _nameToAtomMapping) {
+ if (ci.name == name)
+ return ci.atom;
+ }
+ return nullptr;
+}
+
+void YAMLFile::addDefinedAtom(YAMLDefinedAtom *atom, StringRef refName) {
+ _definedAtoms._atoms.push_back(atom);
+ _nameToAtomMapping.push_back(NameAtomPair(refName, atom));
+}
+
+void YAMLFile::addUndefinedAtom(UndefinedAtom *atom) {
+ _undefinedAtoms._atoms.push_back(atom);
+ _nameToAtomMapping.push_back(NameAtomPair(atom->name(), atom));
+}
+
+void YAMLFile::addSharedLibraryAtom(SharedLibraryAtom *atom) {
+ _sharedLibraryAtoms._atoms.push_back(atom);
+ _nameToAtomMapping.push_back(NameAtomPair(atom->name(), atom));
+}
+
+void YAMLFile::addAbsoluteAtom(AbsoluteAtom *atom) {
+ _absoluteAtoms._atoms.push_back(atom);
+ _nameToAtomMapping.push_back(NameAtomPair(atom->name(), atom));
+}
+
+void YAMLFile::setName(StringRef name) {
+ _path = StringRef(name);
+}
+
+
+// Allocate a new copy of this string and keep track of allocations
+// in _stringCopies, so they can be freed when YAMLFile is destroyed.
+StringRef YAMLFile::copyString(StringRef str) {
+ char* s = new char[str.size()];
+ memcpy(s, str.data(), str.size());
+ _stringCopies.push_back(s);
+ return StringRef(s, str.size());
+}
+
+const File *YAMLFile::find(StringRef name, bool dataSymbolOnly) const {
+ for (auto &file : _memberFiles) {
+ for (const DefinedAtom *atom : file->defined() ) {
+ if (name == atom->name())
+ return file.get();
+ }
+ }
+ return nullptr;
+}
+
+
+
+///
+/// The state machine that drives the YAMLParser stream and instantiates
+/// Files and Atoms. This class also buffers all the attribures for the
+/// current atom and current fixup. Once all attributes are accumulated,
+/// a new atom or fixup instance is instantiated.
+///
+class YAMLState {
+public:
+ YAMLState(const ReaderOptionsYAML &opts, llvm::yaml::Stream *s, YAMLFile *f);
+
+ void parse(llvm::yaml::Node *node, StringRef keyword,
+ llvm::yaml::Node *keywordNode=nullptr);
+ error_code error() { return _error; }
+
+private:
+ typedef llvm::yaml::Node Node;
+ typedef llvm::yaml::ScalarNode ScalarNode;
+ typedef llvm::yaml::SequenceNode SequenceNode;
+ typedef llvm::yaml::MappingNode MappingNode;
+ typedef llvm::yaml::Stream Stream;
+
+ void resetState();
+ void setAlign2(StringRef n);
+
+ void makeReference();
+ void makeAtom(Node *node);
+ void makeDefinedAtom(Node *node);
+ void makeUndefinedAtom(Node *node);
+ void makeSharedLibraryAtom(Node *node);
+ void makeAbsoluteAtom(Node *node);
+
+ void parseMemberName(ScalarNode *node);
+ void parseAtomName(ScalarNode *node);
+ void parseAtomRefName(ScalarNode *node);
+ void parseAtomType(ScalarNode *node);
+ void parseAtomScope(ScalarNode *node);
+ void parseAtomDefinition(ScalarNode *node);
+ void parseAtomDeadStrip(ScalarNode *node);
+ void parseAtomSectionChoice(ScalarNode *node);
+ void parseAtomInterposable(ScalarNode *node);
+ void parseAtomMerge(ScalarNode *node);
+ void parseAtomIsThumb(ScalarNode *node);
+ void parseAtomIsAlias(ScalarNode *node);
+ void parseAtomSectionName(ScalarNode *node);
+ void parseAtomSize(ScalarNode *node);
+ void parseAtomPermissions(ScalarNode *node);
+ void parseAtomCanBeNull(ScalarNode *node);
+ void parseFixUpOffset(ScalarNode *node);
+ void parseFixUpKind(ScalarNode *node);
+ void parseFixUpTarget(ScalarNode *node);
+ void parseFixUpAddend(ScalarNode *node);
+ void parseAtomContentByte(ScalarNode *node);
+ void parseAtomLoadName(ScalarNode *node);
+ void parseAtomValue(ScalarNode *node);
+
+ StringRef extractString(ScalarNode *node);
+
+ typedef void (YAMLState:: *ParseScalar)(ScalarNode *node);
+ typedef void (YAMLState:: *ParseSeq)(SequenceNode *node);
+ typedef void (YAMLState:: *ParseMap)(MappingNode *node);
+
+ enum State { inError, inTop, inDoc, inArch, inMemb,
+ inAtoms, inAtom, inFixUps, inFixUp, inBytes };
+ struct Transistion {
+ State state;
+ const char* keyword;
+ State newState;
+ ParseScalar customAction;
+ };
+
+ static const char* stateName(State);
+
+ void moveToState(State s);
+ void returnToState(State s, Node *node);
+
+ static const Transistion _s_transistions[];
+
+ const ReaderOptionsYAML &_options;
+ error_code _error;
+ llvm::yaml::Stream *_stream;
+ YAMLFile *_file;
+ YAMLFile *_archiveFile;
+ State _state;
+ StringRef _name;
+ StringRef _refName;
+ StringRef _sectionName;
+ StringRef _loadName;
+ StringRef _memberName;
+ unsigned long long _size;
+ uint64_t _value;
+ uint32_t _ordinal;
+ std::vector<uint8_t> _content;
+ DefinedAtom::Alignment _alignment;
+ Atom::Definition _definition;
+ DefinedAtom::Scope _scope;
+ DefinedAtom::ContentType _type;
+ DefinedAtom::SectionChoice _sectionChoice;
+ DefinedAtom::Interposable _interpose;
+ DefinedAtom::Merge _merge;
+ DefinedAtom::DeadStripKind _deadStrip;
+ DefinedAtom::ContentPermissions _permissions;
+ bool _isThumb;
+ bool _isAlias;
+ UndefinedAtom::CanBeNull _canBeNull;
+ YAMLReference _ref;
+ bool _hasDefinedAtomAttributes;
+ bool _hasUndefinedAtomAttributes;
+ bool _hasSharedLibraryAtomAttributes;
+ bool _hasAbsoluteAtomAttributes;
+};
+
+
+//
+// This transition table is the heart of the state machine.
+// The table is read left-to-right columns A,B,C,D as:
+// If the state is A and key B is seen switch to state C then
+// if D is not nullptr call that method with the key's value,
+// if D is nullptr, recursively parse in the new state.
+//
+const YAMLState::Transistion YAMLState::_s_transistions[] = {
+ { inTop, "<root>", inDoc, nullptr },
+ { inDoc, "archive", inArch, nullptr },
+ { inArch, "<any-seq-item>", inMemb, nullptr },
+ { inMemb, "atoms", inAtoms, nullptr },
+ { inMemb, "name", inMemb, &YAMLState::parseMemberName },
+ { inDoc, "atoms", inAtoms, nullptr },
+ { inAtoms, "<any-seq-item>", inAtom, nullptr },
+ { inAtom, "name", inAtom, &YAMLState::parseAtomName },
+ { inAtom, "ref-name", inAtom, &YAMLState::parseAtomRefName },
+ { inAtom, "type", inAtom, &YAMLState::parseAtomType },
+ { inAtom, "scope", inAtom, &YAMLState::parseAtomScope },
+ { inAtom, "definition", inAtom, &YAMLState::parseAtomDefinition },
+ { inAtom, "dead-strip", inAtom, &YAMLState::parseAtomDeadStrip },
+ { inAtom, "section-choice", inAtom, &YAMLState::parseAtomSectionChoice },
+ { inAtom, "interposable", inAtom, &YAMLState::parseAtomInterposable },
+ { inAtom, "merge", inAtom, &YAMLState::parseAtomMerge },
+ { inAtom, "is-thumb", inAtom, &YAMLState::parseAtomIsThumb },
+ { inAtom, "is-alias", inAtom, &YAMLState::parseAtomIsAlias },
+ { inAtom, "section-name", inAtom, &YAMLState::parseAtomSectionName },
+ { inAtom, "size", inAtom, &YAMLState::parseAtomSize },
+ { inAtom, "permissions", inAtom, &YAMLState::parseAtomPermissions },
+ { inAtom, "can-be-null", inAtom, &YAMLState::parseAtomCanBeNull },
+ { inAtom, "content", inBytes, nullptr },
+ { inAtom, "fixups", inFixUps,nullptr },
+ { inBytes, "<any-seq-item>", inBytes, &YAMLState::parseAtomContentByte },
+ { inFixUps,"<any-seq-item>", inFixUp, nullptr },
+ { inFixUp, "offset", inFixUp, &YAMLState::parseFixUpOffset },
+ { inFixUp, "kind", inFixUp, &YAMLState::parseFixUpKind },
+ { inFixUp, "target", inFixUp, &YAMLState::parseFixUpTarget },
+ { inFixUp, "addend", inFixUp, &YAMLState::parseFixUpAddend },
+ { inAtom, "load-name", inAtom, &YAMLState::parseAtomLoadName },
+ { inAtom, "value", inAtom, &YAMLState::parseAtomValue },
+ { inError, nullptr, inAtom, nullptr },
+};
+
+
+
+YAMLState::YAMLState(const ReaderOptionsYAML &opts, Stream *stream,
+ YAMLFile *file)
+ : _options(opts)
+ , _error(make_error_code(yaml_reader_error::success))
+ , _stream(stream)
+ , _file(file)
+ , _archiveFile(nullptr)
+ , _state(inTop)
+ , _alignment(0, 0) {
+ this->resetState();
+}
+
+void YAMLState::makeAtom(Node *node) {
+ switch (_definition ) {
+ case Atom::definitionRegular:
+ this->makeDefinedAtom(node);
+ break;
+ case Atom::definitionUndefined:
+ this->makeUndefinedAtom(node);
+ break;
+ case Atom::definitionSharedLibrary:
+ this->makeSharedLibraryAtom(node);
+ break;
+ case Atom::definitionAbsolute:
+ this->makeAbsoluteAtom(node);
+ break;
+ }
+ ++_ordinal;
+
+ // reset state for next atom
+ this->resetState();
+}
+
+void YAMLState::makeDefinedAtom(Node *node) {
+ if ( _hasAbsoluteAtomAttributes ) {
+ _stream->printError(node, "Defined atom '" + _name
+ + "' has attributes only allowed on absolute atoms");
+ _error = make_error_code(yaml_reader_error::illegal_value);
+ }
+ if ( _hasSharedLibraryAtomAttributes ) {
+ _stream->printError(node, "Defined atom '" + _name
+ + "' has attributes only allowed on shared library atoms");
+ _error = make_error_code(yaml_reader_error::illegal_value);
+ }
+
+ YAMLDefinedAtom *a = new YAMLDefinedAtom(_ordinal, *_file, _scope, _type
+ , _sectionChoice, _interpose, _merge, _deadStrip
+ , _permissions, _isThumb, _isAlias, _alignment
+ , _name, _sectionName, _size, _content);
+ _file->addDefinedAtom(a, !_refName.empty() ? _refName : _name);
+}
+
+void YAMLState::makeUndefinedAtom(Node *node) {
+ if ( _hasDefinedAtomAttributes ) {
+ _stream->printError(node, "Undefined atom '" + _name
+ + "' has attributes only allowed on defined atoms");
+ _error = make_error_code(yaml_reader_error::illegal_value);
+ }
+ if ( _hasAbsoluteAtomAttributes ) {
+ _stream->printError(node, "Defined atom '" + _name
+ + "' has attributes only allowed on absolute atoms");
+ _error = make_error_code(yaml_reader_error::illegal_value);
+ }
+ UndefinedAtom *a = new YAMLUndefinedAtom(*_file, _ordinal, _name, _canBeNull);
+ _file->addUndefinedAtom(a);
+}
+
+void YAMLState::makeSharedLibraryAtom(Node *node) {
+ if ( _hasDefinedAtomAttributes ) {
+ _stream->printError(node, "SharedLibrary atom '" + _name
+ + "' has attributes only allowed on defined atoms");
+ _error = make_error_code(yaml_reader_error::illegal_value);
+ }
+ if ( _hasAbsoluteAtomAttributes ) {
+ _stream->printError(node, "Defined atom '" + _name
+ + "' has attributes only allowed on absolute atoms");
+ _error = make_error_code(yaml_reader_error::illegal_value);
+ }
+ bool nullable = (_canBeNull == UndefinedAtom::canBeNullAtRuntime);
+ SharedLibraryAtom *a = new YAMLSharedLibraryAtom(*_file, _ordinal, _name,
+ _loadName, nullable);
+ _file->addSharedLibraryAtom(a);
+}
+
+void YAMLState::makeAbsoluteAtom(Node *node) {
+ if ( _hasDefinedAtomAttributes ) {
+ _stream->printError(node, "Absolute atom '" + _name
+ + "' has attributes only allowed on defined atoms");
+ _error = make_error_code(yaml_reader_error::illegal_value);
+ }
+ if ( _hasSharedLibraryAtomAttributes ) {
+ _stream->printError(node, "Absolute atom '" + _name
+ + "' has attributes only allowed on shared library atoms");
+ _error = make_error_code(yaml_reader_error::illegal_value);
+ }
+ AbsoluteAtom *a = new YAMLAbsoluteAtom(*_file, _ordinal, _name, _value);
+ _file->addAbsoluteAtom(a);
+}
+
+
+
+void YAMLState::resetState() {
+ _name = StringRef();
+ _refName = StringRef();
+ _sectionName = StringRef();
+ _loadName = StringRef();
+ _memberName = StringRef();
+ _size = 0;
+ _value = 0;
+ _ordinal = 0;
+ _content.clear();
+ _alignment.powerOf2 = 0;
+ _alignment.modulus = 0;
+ _definition = KeyValues::definitionDefault;
+ _scope = KeyValues::scopeDefault;
+ _type = KeyValues::contentTypeDefault;
+ _sectionChoice = KeyValues::sectionChoiceDefault;
+ _interpose = KeyValues::interposableDefault;
+ _merge = KeyValues::mergeDefault;
+ _deadStrip = KeyValues::deadStripKindDefault;
+ _permissions = KeyValues::permissionsDefault;
+ _isThumb = KeyValues::isThumbDefault;
+ _isAlias = KeyValues::isAliasDefault;
+ _canBeNull = KeyValues::canBeNullDefault;
+ _ref._target = nullptr;
+ _ref._targetNameNode= nullptr;
+ _ref._addend = 0;
+ _ref._offsetInAtom = 0;
+ _ref._kind = 0;
+
+ _hasDefinedAtomAttributes = false;
+ _hasUndefinedAtomAttributes = false;
+ _hasSharedLibraryAtomAttributes = false;
+ _hasAbsoluteAtomAttributes = false;
+}
+
+
+void YAMLState::makeReference() {
+ _file->_references.push_back(_ref);
+ // clear for next ref
+ _ref._target = nullptr;
+ _ref._targetNameNode= nullptr;
+ _ref._addend = 0;
+ _ref._offsetInAtom = 0;
+ _ref._kind = 0;
+}
+
+
+
+void YAMLState::setAlign2(StringRef s) {
+ if (StringRef(s).getAsInteger(10, _alignment.powerOf2))
+ _alignment.powerOf2 = 1;
+}
+
+
+// For debug logging
+const char* YAMLState::stateName(State s) {
+ switch ( s ) {
+ case inError:
+ return "inError";
+ case inTop:
+ return "inTop";
+ case inDoc:
+ return "inDoc";
+ case inArch:
+ return "inArch";
+ case inMemb:
+ return "inMemb";
+ case inAtoms:
+ return "inAtoms";
+ case inAtom:
+ return "inAtom";
+ case inFixUps:
+ return "inFixUps";
+ case inFixUp:
+ return "inFixUp";
+ case inBytes:
+ return "inBytes";
+ }
+ return "unknown case";
+}
+
+// Called by parse() when recursing and switching to a new state.
+void YAMLState::moveToState(State newState) {
+ if ( newState == _state )
+ return;
+ DEBUG_WITH_TYPE("objtxt", llvm::dbgs() << "moveToState(" << stateName(newState)
+ << "), _state=" << stateName(_state) << "\n");
+
+ if ( newState == inArch ) {
+ // Seen "archive:", repurpose existing YAMLFile to be archive file
+ _file->_kind = File::kindArchiveLibrary;
+ _archiveFile = _file;
+ _file = nullptr;
+ }
+
+ if ( newState == inMemb ) {
+ assert(_state == inArch);
+ // Make new YAMLFile for this member
+ std::unique_ptr<YAMLFile> memberFile(new YAMLFile);
+ _file = memberFile.get();
+ assert(_archiveFile != nullptr);
+ _archiveFile->_memberFiles.emplace_back(memberFile.release());
+ }
+
+ _state = newState;
+}
+
+// Called by parse() when returning from recursion and restoring the old state.
+void YAMLState::returnToState(State prevState, Node *node) {
+ if ( prevState == _state )
+ return;
+ DEBUG_WITH_TYPE("objtxt", llvm::dbgs()
+ << "returnToState(" << stateName(prevState)
+ << "), _state=" << stateName(_state) << "\n");
+ // If done with an atom, instantiate an object for it.
+ if ( (_state == inAtom) && (prevState == inAtoms) )
+ this->makeAtom(node);
+ // If done wit a fixup, instantiate an object for it.
+ if ( (_state == inFixUp) && (prevState == inFixUps) )
+ this->makeReference();
+ _state = prevState;
+}
+
+// If a string in the yaml document is quoted in a way that there is no
+// contiguous range of bytes that a StringRef can point to, then we make
+// a copy of the string and have the StringRef point to that.
+StringRef YAMLState::extractString(ScalarNode *node) {
+ llvm::SmallString<32> storage;
+ StringRef str = node->getValue(storage);
+ //if ( str.data() == storage.begin() ) {
+ str = _file->copyString(str);
+ //}
+ return str;
+}
+
+
+void YAMLState::parseMemberName(ScalarNode *node) {
+ _memberName = extractString(node);
+}
+
+void YAMLState::parseAtomName(ScalarNode *node) {
+ _name = extractString(node);
+}
+
+void YAMLState::parseAtomRefName(ScalarNode *node) {
+ _refName = extractString(node);
+}
+
+void YAMLState::parseAtomScope(ScalarNode *node) {
+ llvm::SmallString<32> storage;
+ if ( KeyValues::scope(node->getValue(storage), _scope) ) {
+ _stream->printError(node, "Invalid value for 'scope:'");
+ _error = make_error_code(yaml_reader_error::illegal_value);
+ }
+ _hasDefinedAtomAttributes = true;
+}
+
+void YAMLState::parseAtomDefinition(ScalarNode *node) {
+ llvm::SmallString<32> storage;
+ if ( KeyValues::definition(node->getValue(storage), _definition) ) {
+ _stream->printError(node, "Invalid value for 'definition:'");
+ _error = make_error_code(yaml_reader_error::illegal_value);
+ }
+}
+
+void YAMLState::parseAtomType(ScalarNode *node) {
+ llvm::SmallString<32> storage;
+ if ( KeyValues::contentType(node->getValue(storage), _type) ) {
+ _stream->printError(node, "Invalid value for 'type:'");
+ _error = make_error_code(yaml_reader_error::illegal_value);
+ }
+ _hasDefinedAtomAttributes = true;
+}
+
+void YAMLState::parseAtomDeadStrip(ScalarNode *node) {
+ llvm::SmallString<32> storage;
+ if ( KeyValues::deadStripKind(node->getValue(storage), _deadStrip) ) {
+ _stream->printError(node, "Invalid value for 'dead-strip:'");
+ _error = make_error_code(yaml_reader_error::illegal_value);
+ }
+ _hasDefinedAtomAttributes = true;
+}
+
+void YAMLState::parseAtomSectionChoice(ScalarNode *node) {
+ llvm::SmallString<32> storage;
+ if ( KeyValues::sectionChoice(node->getValue(storage), _sectionChoice) ) {
+ _stream->printError(node, "Invalid value for 'section-choice:'");
+ _error = make_error_code(yaml_reader_error::illegal_value);
+ }
+ _hasDefinedAtomAttributes = true;
+}
+
+void YAMLState::parseAtomInterposable(ScalarNode *node) {
+ llvm::SmallString<32> storage;
+ if ( KeyValues::interposable(node->getValue(storage), _interpose) ) {
+ _stream->printError(node, "Invalid value for 'interposable:'");
+ _error = make_error_code(yaml_reader_error::illegal_value);
+ }
+ _hasDefinedAtomAttributes = true;
+}
+
+void YAMLState::parseAtomMerge(ScalarNode *node) {
+ llvm::SmallString<32> storage;
+ if ( KeyValues::merge(node->getValue(storage), _merge) ) {
+ _stream->printError(node, "Invalid value for 'merge:'");
+ _error = make_error_code(yaml_reader_error::illegal_value);
+ }
+ _hasDefinedAtomAttributes = true;
+}
+
+void YAMLState::parseAtomIsThumb(ScalarNode *node) {
+ llvm::SmallString<32> storage;
+ if ( KeyValues::isThumb(node->getValue(storage), _isThumb) ) {
+ _stream->printError(node, "Invalid value for 'thumb:'");
+ _error = make_error_code(yaml_reader_error::illegal_value);
+ }
+ _hasDefinedAtomAttributes = true;
+}
+
+void YAMLState::parseAtomIsAlias(ScalarNode *node) {
+ llvm::SmallString<32> storage;
+ if ( KeyValues::isAlias(node->getValue(storage), _isAlias) ) {
+ _stream->printError(node, "Invalid value for 'is-alias:'");
+ _error = make_error_code(yaml_reader_error::illegal_value);
+ }
+ _hasDefinedAtomAttributes = true;
+}
+
+void YAMLState::parseAtomSectionName(ScalarNode *node) {
+ _sectionName = extractString(node);
+ _hasDefinedAtomAttributes = true;
+}
+
+void YAMLState::parseAtomSize(ScalarNode *node) {
+ llvm::SmallString<32> storage;
+ StringRef offsetStr = node->getValue(storage);
+ if ( offsetStr.getAsInteger(0, _size) ) {
+ _stream->printError(node, "Invalid value for atom 'size:'");
+ _error = make_error_code(yaml_reader_error::illegal_value);
+ }
+ _hasDefinedAtomAttributes = true;
+}
+
+void YAMLState::parseAtomPermissions(ScalarNode *node) {
+ llvm::SmallString<32> storage;
+ if ( KeyValues::permissions(node->getValue(storage), _permissions) ) {
+ _stream->printError(node, "Invalid value for 'permissions:'");
+ _error = make_error_code(yaml_reader_error::illegal_value);
+ }
+ _hasDefinedAtomAttributes = true;
+}
+
+void YAMLState::parseAtomCanBeNull(ScalarNode *node) {
+ llvm::SmallString<32> storage;
+ if ( KeyValues::canBeNull(node->getValue(storage), _canBeNull) ) {
+ _stream->printError(node, "Invalid value for 'can-be-null:'");
+ _error = make_error_code(yaml_reader_error::illegal_value);
+ }
+}
+
+void YAMLState::parseFixUpOffset(ScalarNode *node) {
+ llvm::SmallString<32> storage;
+ StringRef offsetStr = node->getValue(storage);
+ if ( offsetStr.getAsInteger(0, _ref._offsetInAtom) ) {
+ _stream->printError(node, "Invalid value for fixup 'offset:'");
+ _error = make_error_code(yaml_reader_error::illegal_value);
+ }
+ _hasDefinedAtomAttributes = true;
+}
+
+void YAMLState::parseFixUpKind(ScalarNode *node) {
+ llvm::SmallString<32> storage;
+ _ref._kind = _options.kindFromString(node->getValue(storage));
+ _hasDefinedAtomAttributes = true;
+}
+
+void YAMLState::parseFixUpTarget(ScalarNode *node) {
+ _ref._targetNameNode = node;
+ _hasDefinedAtomAttributes = true;
+}
+
+void YAMLState::parseFixUpAddend(ScalarNode *node) {
+ llvm::SmallString<32> storage;
+ StringRef offsetStr = node->getValue(storage);
+ if ( offsetStr.getAsInteger(0, _ref._addend) ) {
+ _stream->printError(node, "Invalid value for fixup 'addend:'");
+ _error = make_error_code(yaml_reader_error::illegal_value);
+ }
+ _hasDefinedAtomAttributes = true;
+}
+
+void YAMLState::parseAtomContentByte(ScalarNode *node) {
+ llvm::SmallString<32> storage;
+ StringRef str = node->getValue(storage);
+ unsigned int contentByte;
+ if ( str.getAsInteger(16, contentByte) ) {
+ _stream->printError(node, "Invalid content hex byte '0x" + str + "'");
+ _error = make_error_code(yaml_reader_error::illegal_value);
+ return;
+ }
+ if (contentByte > 0xFF) {
+ _stream->printError(node, "Content hex byte out of range (0x"
+ + str + " > 0xFF)");
+ _error = make_error_code(yaml_reader_error::illegal_value);
+ return;
+ }
+ _content.push_back(contentByte & 0xFF);
+ _hasDefinedAtomAttributes = true;
+}
+
+void YAMLState::parseAtomLoadName(ScalarNode *node) {
+ _loadName = extractString(node);
+ _hasSharedLibraryAtomAttributes = true;
+}
+
+
+void YAMLState::parseAtomValue(ScalarNode *node) {
+ llvm::SmallString<32> storage;
+ StringRef offsetStr = node->getValue(storage);
+ if ( offsetStr.getAsInteger(0, _value) ) {
+ _stream->printError(node, "Invalid value for fixup 'addend:'");
+ _error = make_error_code(yaml_reader_error::illegal_value);
+ }
+ _hasAbsoluteAtomAttributes = true;
+}
+
+//
+// This is the parsing engine that walks the nodes in the yaml document
+// stream. It is table driven. See _s_transistions.
+//
+void YAMLState::parse(Node *node, StringRef keyword, Node *keywordNode) {
+ using namespace llvm::yaml;
+ DEBUG_WITH_TYPE("objtxt", llvm::dbgs() << "parse(" << keyword << "), _state="
+ << stateName(_state) << "\n");
+ if ( _error )
+ return;
+ State savedState = _state;
+ for(const Transistion* t=_s_transistions; t->state != inError; ++t) {
+ if ( t->state != _state )
+ continue;
+ if ( ! keyword.equals(t->keyword) )
+ continue;
+ ParseScalar action = t->customAction;
+ this->moveToState(t->newState);
+ if ( ScalarNode *sc = llvm::dyn_cast<ScalarNode>(node) ) {
+ if ( action ) {
+ (*this.*action)(sc);
+ }
+ else {
+ _stream->printError(node, "unexpected scalar");
+ _error = make_error_code(yaml_reader_error::illegal_value);
+ }
+ }
+ else if ( SequenceNode *seq = llvm::dyn_cast<SequenceNode>(node) ) {
+ if ( action ) {
+ _stream->printError(node, "unexpected sequence");
+ _error = make_error_code(yaml_reader_error::illegal_value);
+ }
+ else {
+ for (Node &seqEntry : *seq ) {
+ this->parse(&seqEntry, StringRef("<any-seq-item>"));
+ if ( _error )
+ break;
+ }
+ }
+ }
+ else if ( MappingNode *map = llvm::dyn_cast<MappingNode>(node) ) {
+ if ( action ) {
+ _stream->printError(node, "unexpected map");
+ _error = make_error_code(yaml_reader_error::illegal_value);
+ }
+ else {
+ llvm::SmallString<32> storage;
+ for (auto &keyVal : *map) {
+ ScalarNode *keyScalar = llvm::dyn_cast<ScalarNode>(keyVal.getKey());
+ llvm::StringRef keyStr = keyScalar->getValue(storage);
+ this->parse(keyVal.getValue(), keyStr, keyScalar);
+ if ( _error )
+ break;
+ }
+ }
+ }
+ else {
+ _stream->printError(node, "unexpected node type");
+ _error = make_error_code(yaml_reader_error::illegal_value);
+ }
+ this->returnToState(savedState, node);
+ return;
+ }
+ switch (_state) {
+ case inAtom:
+ _stream->printError(keywordNode, "Unknown atom attribute '"
+ + keyword + ":'");
+ break;
+ case inFixUp:
+ _stream->printError(keywordNode, "Unknown fixup attribute '"
+ + keyword + ":'");
+ break;
+ case inDoc:
+ _stream->printError(keywordNode, "Unknown file attribute '"
+ + keyword + ":'");
+ break;
+ default:
+ _stream->printError(keywordNode, "Unknown keyword '"
+ + keyword + ":'");
+ }
+ _error = make_error_code(yaml_reader_error::illegal_value);
+}
+
+
+/// parseObjectText - Parse the specified YAML formatted MemoryBuffer
+/// into lld::File object(s) and append each to the specified vector<File*>.
+error_code parseFile(std::unique_ptr<MemoryBuffer> &mb,
+ const ReaderOptionsYAML &options,
+ std::vector<std::unique_ptr<File>> &result) {
+ llvm::SourceMgr srcMgr;
+ llvm::yaml::Stream stream(mb->getBuffer(), srcMgr);
+
+ for (llvm::yaml::Document &d : stream) {
+ std::unique_ptr<yaml::YAMLFile> curFile(new yaml::YAMLFile);
+ if (llvm::isa<llvm::yaml::NullNode>(d.getRoot()))
+ continue; // Empty files are allowed.
+ yaml::YAMLState yamlState(options, &stream, curFile.get());
+ yamlState.parse(d.getRoot(), StringRef("<root>"));
+
+ if ( stream.failed() )
+ return make_error_code(yaml_reader_error::illegal_value);
+ if ( yamlState.error() )
+ return yamlState.error();
+
+ error_code ec = curFile->bindTargetReferences(stream);
+ if ( ec )
+ return ec;
+ result.emplace_back(curFile.release());
+ }
+
+ return make_error_code(yaml_reader_error::success);
+}
+
+
+
+} // namespace yaml
+
+
+
+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) {
+ return lld::yaml::parseFile(mb, _options, result);
+ }
+
+private:
+ const ReaderOptionsYAML &_options;
+};
+
+
+
+Reader* createReaderYAML(const ReaderOptionsYAML &options) {
+ return new ReaderYAML(options);
+}
+
+ReaderOptionsYAML::ReaderOptionsYAML() {
+}
+
+ReaderOptionsYAML::~ReaderOptionsYAML() {
+}
+
+
+
+
+} // namespace lld
OpenPOWER on IntegriCloud