| //===- Core/YamlReader.cpp - Reads YAML -----------------------------------===// |
| // |
| // The LLVM Linker |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "lld/Core/YamlReader.h" |
| #include "YamlKeyValues.h" |
| #include "lld/Core/Atom.h" |
| #include "lld/Core/AbsoluteAtom.h" |
| #include "lld/Core/Error.h" |
| #include "lld/Core/File.h" |
| #include "lld/Core/LLVM.h" |
| #include "lld/Core/Platform.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/Support/DataTypes.h" |
| #include "llvm/Support/ErrorHandling.h" |
| #include "llvm/Support/MemoryBuffer.h" |
| #include "llvm/Support/system_error.h" |
| |
| #include <cstring> |
| #include <vector> |
| |
| |
| |
| namespace lld { |
| namespace yaml { |
| |
| namespace { |
| |
| class YAML { |
| public: |
| struct Entry { |
| Entry(const char *k, const char *v, std::vector<uint8_t>* vs, |
| int d, bool bd, bool bs) |
| : key(strdup(k)) |
| , value(v ? strdup(v) : nullptr) |
| , valueSequenceBytes(vs) |
| , depth(d) |
| , beginSequence(bs) |
| , beginDocument(bd) {} |
| |
| const char * key; |
| const char * value; |
| std::vector<uint8_t>* valueSequenceBytes; |
| int depth; |
| bool beginSequence; |
| bool beginDocument; |
| }; |
| |
| static void parse(llvm::MemoryBuffer *mb, std::vector<const Entry *>&); |
| |
| private: |
| enum State { |
| start, |
| inHeaderComment, |
| inTripleDash, |
| inTriplePeriod, |
| inDocument, |
| inKey, |
| inSpaceBeforeValue, |
| inValue, |
| inValueSequence, |
| inValueSequenceEnd |
| }; |
| }; |
| |
| |
| void YAML::parse(llvm::MemoryBuffer *mb, std::vector<const Entry *> &entries) { |
| State state = start; |
| char key[64]; |
| char value[64]; |
| char *p = nullptr; |
| unsigned int lineNumber = 1; |
| int depth = 0; |
| bool nextKeyIsStartOfDocument = false; |
| bool nextKeyIsStartOfSequence = false; |
| std::vector<uint8_t>* sequenceBytes = nullptr; |
| unsigned contentByte = 0; |
| for (const char *s = mb->getBufferStart(); s < mb->getBufferEnd(); ++s) { |
| char c = *s; |
| if (c == '\n') |
| ++lineNumber; |
| switch (state) { |
| case start: |
| if (c == '#') |
| state = inHeaderComment; |
| else if (c == '-') { |
| p = &key[0]; |
| *p++ = c; |
| state = inTripleDash; |
| } |
| break; |
| case inHeaderComment: |
| if (c == '\n') { |
| state = start; |
| } |
| break; |
| case inTripleDash: |
| if (c == '-') { |
| *p++ = c; |
| } else if (c == '\n') { |
| *p = '\0'; |
| if (strcmp(key, "---") != 0) |
| return; |
| depth = 0; |
| state = inDocument; |
| nextKeyIsStartOfDocument = true; |
| } else { |
| return; |
| } |
| break; |
| case inTriplePeriod: |
| if (c == '.') { |
| *p++ = c; |
| } else if (c == '\n') { |
| *p = '\0'; |
| if (strcmp(key, "...") != 0) |
| return; |
| depth = 0; |
| state = inHeaderComment; |
| } else { |
| return; |
| } |
| break; |
| case inDocument: |
| if (isalnum(c)) { |
| state = inKey; |
| p = &key[0]; |
| *p++ = c; |
| } else if (c == '-') { |
| if (depth == 0) { |
| p = &key[0]; |
| *p++ = c; |
| state = inTripleDash; |
| } else { |
| nextKeyIsStartOfSequence = true; |
| ++depth; |
| } |
| } else if (c == ' ') { |
| ++depth; |
| } else if (c == '.') { |
| p = &key[0]; |
| *p++ = c; |
| state = inTriplePeriod; |
| } else if (c == '\n') { |
| // ignore empty lines |
| depth = 0; |
| } else if (c == '\t') { |
| llvm::report_fatal_error("TAB character found in yaml file"); |
| } else { |
| return; |
| } |
| break; |
| case inKey: |
| if (isalnum(c) || (c == '-')) { |
| *p++ = c; |
| } else if (c == ':') { |
| *p = '\0'; |
| state = inSpaceBeforeValue; |
| } else if (c == '\n') { |
| *p = '\0'; |
| if (strcmp(key, "---") == 0) |
| state = inDocument; |
| else |
| return; |
| } else { |
| return; |
| } |
| break; |
| case inSpaceBeforeValue: |
| if (isalnum(c) || (c == '-') || (c == '_') || (c == '/')) { |
| p = &value[0]; |
| *p++ = c; |
| state = inValue; |
| } else if (c == '\n') { |
| entries.push_back(new Entry(key, "", nullptr, depth, |
| nextKeyIsStartOfDocument, |
| nextKeyIsStartOfSequence)); |
| nextKeyIsStartOfSequence = false; |
| nextKeyIsStartOfDocument = false; |
| state = inDocument; |
| depth = 0; |
| } else if (c == '[') { |
| contentByte = 0; |
| sequenceBytes = new std::vector<uint8_t>(); |
| state = inValueSequence; |
| } else if (c == ' ') { |
| // eat space |
| } else if (c == '\t') { |
| llvm::report_fatal_error("TAB character found in yaml file"); |
| } else { |
| return; |
| } |
| break; |
| case inValue: |
| if (c == '\n') { |
| *p = '\0'; |
| entries.push_back(new Entry(key, value, nullptr, depth, |
| nextKeyIsStartOfDocument, |
| nextKeyIsStartOfSequence)); |
| nextKeyIsStartOfSequence = false; |
| nextKeyIsStartOfDocument = false; |
| state = inDocument; |
| depth = 0; |
| } |
| else { |
| *p++ = c; |
| } |
| break; |
| case inValueSequence: |
| if (c == ']') { |
| sequenceBytes->push_back(contentByte); |
| state = inValueSequenceEnd; |
| } |
| else if ( (c == ' ') || (c == '\n') ) { |
| // eat white space |
| } |
| else if (c == ',') { |
| sequenceBytes->push_back(contentByte); |
| } |
| else if ( isdigit(c) ) { |
| contentByte = (contentByte << 4) | (c-'0'); |
| } |
| else if ( ('a' <= tolower(c)) && (tolower(c) <= 'f') ) { |
| contentByte = (contentByte << 4) | (tolower(c)-'a'+10); |
| } |
| else { |
| llvm::report_fatal_error("non-hex digit found in content [ ]"); |
| } |
| break; |
| case inValueSequenceEnd: |
| if (c == '\n') { |
| entries.push_back(new Entry(key, nullptr, sequenceBytes, depth, |
| nextKeyIsStartOfDocument, |
| nextKeyIsStartOfSequence)); |
| nextKeyIsStartOfSequence = false; |
| nextKeyIsStartOfDocument = false; |
| state = inDocument; |
| depth = 0; |
| } |
| break; |
| } |
| } |
| } |
| |
| |
| |
| class YAMLReference : public Reference { |
| public: |
| YAMLReference() : _target(nullptr), _targetName(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; |
| } |
| |
| const Atom* _target; |
| const char* _targetName; |
| uint64_t _offsetInAtom; |
| Addend _addend; |
| Kind _kind; |
| }; |
| |
| |
| |
| class YAMLDefinedAtom; |
| |
| class YAMLFile : public File { |
| public: |
| YAMLFile() |
| : File("path") |
| , _lastRefIndex(0) {} |
| |
| 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"); |
| } |
| |
| void bindTargetReferences(); |
| void addDefinedAtom(YAMLDefinedAtom* atom, const char* refName); |
| void addUndefinedAtom(UndefinedAtom* atom); |
| void addSharedLibraryAtom(SharedLibraryAtom* atom); |
| void addAbsoluteAtom(AbsoluteAtom* atom); |
| Atom* findAtom(const char* name); |
| |
| struct NameAtomPair { |
| NameAtomPair(const char* n, Atom* a) : name(n), atom(a) {} |
| const char* 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; |
| unsigned int _lastRefIndex; |
| }; |
| |
| |
| |
| 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 |
| , const char* name |
| , const char* 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 { |
| if (_name == nullptr) |
| return StringRef(); |
| else |
| return _name; |
| } |
| |
| virtual uint64_t size() const { |
| return (_content ? _content->size() : _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 { |
| if (_content != nullptr) |
| return ArrayRef<uint8_t>(*_content); |
| else |
| return ArrayRef<uint8_t>(); |
| } |
| |
| 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); |
| } |
| |
| |
| |
| void bindTargetReferences() const { |
| for (unsigned int i=_refStartIndex; i < _refEndIndex; ++i) { |
| const char* targetName = _file._references[i]._targetName; |
| Atom* targetAtom = _file.findAtom(targetName); |
| _file._references[i]._target = targetAtom; |
| } |
| } |
| |
| private: |
| YAMLFile& _file; |
| const char * _name; |
| const char * _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; |
| }; |
| |
| |
| class YAMLUndefinedAtom : public UndefinedAtom { |
| public: |
| YAMLUndefinedAtom(YAMLFile& f, int32_t ord, const char* nm, |
| UndefinedAtom::CanBeNull cbn) |
| : _file(f), _name(nm), _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; |
| const char * _name; |
| uint32_t _ordinal; |
| UndefinedAtom::CanBeNull _canBeNull; |
| }; |
| |
| |
| |
| class YAMLSharedLibraryAtom : public SharedLibraryAtom { |
| public: |
| YAMLSharedLibraryAtom(YAMLFile& f, int32_t ord, const char* nm, |
| const char* ldnm, bool cbn) |
| : _file(f), _name(nm), _ordinal(ord), |
| _loadName(ldnm), _canBeNull(cbn) { } |
| |
| virtual const class File& file() const { |
| return _file; |
| } |
| |
| virtual StringRef name() const { |
| return _name; |
| } |
| |
| virtual StringRef loadName() const { |
| if ( _loadName == nullptr ) |
| return StringRef(); |
| else |
| return StringRef(_loadName); |
| } |
| |
| virtual bool canBeNullAtRuntime() const { |
| return _canBeNull; |
| } |
| |
| |
| private: |
| YAMLFile& _file; |
| const char * _name; |
| uint32_t _ordinal; |
| const char * _loadName; |
| bool _canBeNull; |
| }; |
| |
| |
| |
| class YAMLAbsoluteAtom : public AbsoluteAtom { |
| public: |
| YAMLAbsoluteAtom(YAMLFile& f, int32_t ord, const char* nm, uint64_t v) |
| : _file(f), _name(nm), _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; |
| const char * _name; |
| uint32_t _ordinal; |
| uint64_t _value; |
| }; |
| |
| |
| |
| void YAMLFile::bindTargetReferences() { |
| for (const DefinedAtom *defAtom : _definedAtoms) { |
| const YAMLDefinedAtom* atom = |
| reinterpret_cast<const YAMLDefinedAtom*>(defAtom); |
| atom->bindTargetReferences(); |
| } |
| } |
| |
| Atom* YAMLFile::findAtom(const char* name) { |
| for (std::vector<NameAtomPair>::const_iterator it = _nameToAtomMapping.begin(); |
| it != _nameToAtomMapping.end(); ++it) { |
| if ( strcmp(name, it->name) == 0 ) |
| return it->atom; |
| } |
| llvm::report_fatal_error("reference to atom that does not exist"); |
| } |
| |
| void YAMLFile::addDefinedAtom(YAMLDefinedAtom* atom, const char* refName) { |
| _definedAtoms._atoms.push_back(atom); |
| assert(refName != nullptr); |
| _nameToAtomMapping.push_back(NameAtomPair(refName, atom)); |
| } |
| |
| void YAMLFile::addUndefinedAtom(UndefinedAtom* atom) { |
| _undefinedAtoms._atoms.push_back(atom); |
| _nameToAtomMapping.push_back(NameAtomPair(atom->name().data(), atom)); |
| } |
| |
| void YAMLFile::addSharedLibraryAtom(SharedLibraryAtom* atom) { |
| _sharedLibraryAtoms._atoms.push_back(atom); |
| _nameToAtomMapping.push_back(NameAtomPair(atom->name().data(), atom)); |
| } |
| |
| void YAMLFile::addAbsoluteAtom(AbsoluteAtom* atom) { |
| _absoluteAtoms._atoms.push_back(atom); |
| _nameToAtomMapping.push_back(NameAtomPair(atom->name().data(), atom)); |
| } |
| |
| |
| class YAMLAtomState { |
| public: |
| YAMLAtomState(Platform& platform); |
| |
| void setName(const char *n); |
| void setRefName(const char *n); |
| void setAlign2(const char *n); |
| |
| void setFixupKind(const char *n); |
| void setFixupTarget(const char *n); |
| void addFixup(YAMLFile *f); |
| |
| void makeAtom(YAMLFile&); |
| |
| Platform& _platform; |
| const char * _name; |
| const char * _refName; |
| const char * _sectionName; |
| const char* _loadName; |
| 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; |
| }; |
| |
| |
| YAMLAtomState::YAMLAtomState(Platform& platform) |
| : _platform(platform) |
| , _name(nullptr) |
| , _refName(nullptr) |
| , _sectionName(nullptr) |
| , _loadName(nullptr) |
| , _size(0) |
| , _value(0) |
| , _ordinal(0) |
| , _content(nullptr) |
| , _alignment(0, 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) |
| { |
| } |
| |
| |
| void YAMLAtomState::makeAtom(YAMLFile& f) { |
| if ( _definition == Atom::definitionRegular ) { |
| YAMLDefinedAtom *a = new YAMLDefinedAtom(_ordinal, f, _scope, _type, |
| _sectionChoice, _interpose, _merge, _deadStrip, |
| _permissions, _isThumb, _isAlias, |
| _alignment, _name, _sectionName, _size, _content); |
| f.addDefinedAtom(a, _refName ? _refName : _name); |
| ++_ordinal; |
| } |
| else if ( _definition == Atom::definitionUndefined ) { |
| UndefinedAtom *a = new YAMLUndefinedAtom(f, _ordinal, _name, _canBeNull); |
| f.addUndefinedAtom(a); |
| ++_ordinal; |
| } |
| else if ( _definition == Atom::definitionSharedLibrary ) { |
| bool nullable = (_canBeNull == UndefinedAtom::canBeNullAtRuntime); |
| SharedLibraryAtom *a = new YAMLSharedLibraryAtom(f, _ordinal, _name, |
| _loadName, nullable); |
| f.addSharedLibraryAtom(a); |
| ++_ordinal; |
| } |
| else if ( _definition == Atom::definitionAbsolute ) { |
| AbsoluteAtom *a = new YAMLAbsoluteAtom(f, _ordinal, _name, _value); |
| f.addAbsoluteAtom(a); |
| ++_ordinal; |
| } |
| |
| // reset state for next atom |
| _name = nullptr; |
| _refName = nullptr; |
| _sectionName = nullptr; |
| _loadName = nullptr; |
| _size = 0; |
| _value = 0; |
| _ordinal = 0; |
| _content = nullptr; |
| _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._targetName = nullptr; |
| _ref._addend = 0; |
| _ref._offsetInAtom = 0; |
| _ref._kind = 0; |
| } |
| |
| void YAMLAtomState::setName(const char *n) { |
| _name = n; |
| } |
| |
| void YAMLAtomState::setRefName(const char *n) { |
| _refName = n; |
| } |
| |
| void YAMLAtomState::setAlign2(const char *s) { |
| if (StringRef(s).getAsInteger(10, _alignment.powerOf2)) |
| _alignment.powerOf2 = 1; |
| } |
| |
| void YAMLAtomState::setFixupKind(const char *s) { |
| _ref._kind = _platform.kindFromString(StringRef(s)); |
| } |
| |
| void YAMLAtomState::setFixupTarget(const char *s) { |
| _ref._targetName = s; |
| } |
| |
| |
| void YAMLAtomState::addFixup(YAMLFile *f) { |
| f->_references.push_back(_ref); |
| // clear for next ref |
| _ref._target = nullptr; |
| _ref._targetName = nullptr; |
| _ref._addend = 0; |
| _ref._offsetInAtom = 0; |
| _ref._kind = 0; |
| } |
| |
| |
| } // anonymous namespace |
| |
| |
| |
| |
| |
| /// parseObjectText - Parse the specified YAML formatted MemoryBuffer |
| /// into lld::File object(s) and append each to the specified vector<File*>. |
| error_code parseObjectText( llvm::MemoryBuffer *mb |
| , Platform& platform |
| , std::vector<const File *> &result) { |
| std::vector<const YAML::Entry *> entries; |
| YAML::parse(mb, entries); |
| |
| YAMLFile *file = nullptr; |
| YAMLAtomState atomState(platform); |
| bool inAtoms = false; |
| bool inFixups = false; |
| int depthForAtoms = -1; |
| int depthForFixups = -1; |
| int lastDepth = -1; |
| bool haveAtom = false; |
| bool haveFixup = false; |
| |
| for (std::vector<const YAML::Entry *>::iterator it = entries.begin(); |
| it != entries.end(); ++it) { |
| const YAML::Entry *entry = *it; |
| |
| if (entry->beginDocument) { |
| if (file != nullptr) { |
| if (haveAtom) { |
| atomState.makeAtom(*file); |
| haveAtom = false; |
| } |
| file->bindTargetReferences(); |
| result.push_back(file); |
| } |
| file = new YAMLFile(); |
| inAtoms = false; |
| depthForAtoms = -1; |
| } |
| if (lastDepth > entry->depth) { |
| // end of fixup sequence |
| if (haveFixup) { |
| atomState.addFixup(file); |
| haveFixup = false; |
| } |
| } |
| |
| if (inAtoms && (depthForAtoms == -1)) { |
| depthForAtoms = entry->depth; |
| } |
| if (inFixups && (depthForFixups == -1)) { |
| depthForFixups = entry->depth; |
| } |
| if (strcmp(entry->key, "atoms") == 0) { |
| inAtoms = true; |
| } |
| if (inAtoms) { |
| if (depthForAtoms == entry->depth) { |
| if (entry->beginSequence) { |
| if (haveAtom) { |
| atomState.makeAtom(*file); |
| haveAtom = false; |
| } |
| } |
| if (strcmp(entry->key, KeyValues::nameKeyword) == 0) { |
| atomState.setName(entry->value); |
| haveAtom = true; |
| } |
| else if (strcmp(entry->key, KeyValues::refNameKeyword) == 0) { |
| atomState.setRefName(entry->value); |
| haveAtom = true; |
| } |
| else if (strcmp(entry->key, KeyValues::definitionKeyword) == 0) { |
| atomState._definition = KeyValues::definition(entry->value); |
| haveAtom = true; |
| } |
| else if (strcmp(entry->key, KeyValues::scopeKeyword) == 0) { |
| atomState._scope = KeyValues::scope(entry->value); |
| haveAtom = true; |
| } |
| else if (strcmp(entry->key, KeyValues::contentTypeKeyword) == 0) { |
| atomState._type = KeyValues::contentType(entry->value); |
| haveAtom = true; |
| } |
| else if (strcmp(entry->key, KeyValues::deadStripKindKeyword) == 0) { |
| atomState._deadStrip = KeyValues::deadStripKind(entry->value); |
| haveAtom = true; |
| } |
| else if (strcmp(entry->key, KeyValues::sectionChoiceKeyword) == 0) { |
| atomState._sectionChoice = KeyValues::sectionChoice(entry->value); |
| haveAtom = true; |
| } |
| else if (strcmp(entry->key, KeyValues::mergeKeyword) == 0) { |
| atomState._merge = KeyValues::merge(entry->value); |
| haveAtom = true; |
| } |
| else if (strcmp(entry->key, KeyValues::interposableKeyword) == 0) { |
| atomState._interpose = KeyValues::interposable(entry->value); |
| haveAtom = true; |
| } |
| else if (strcmp(entry->key, KeyValues::isThumbKeyword) == 0) { |
| atomState._isThumb = KeyValues::isThumb(entry->value); |
| haveAtom = true; |
| } |
| else if (strcmp(entry->key, KeyValues::isAliasKeyword) == 0) { |
| atomState._isAlias = KeyValues::isAlias(entry->value); |
| haveAtom = true; |
| } |
| else if (strcmp(entry->key, KeyValues::canBeNullKeyword) == 0) { |
| atomState._canBeNull = KeyValues::canBeNull(entry->value); |
| if ( atomState._definition == Atom::definitionSharedLibrary ) { |
| if ( atomState._canBeNull == UndefinedAtom::canBeNullAtBuildtime ) |
| return make_error_code(yaml_reader_error::illegal_value); |
| } |
| haveAtom = true; |
| } |
| else if (strcmp(entry->key, KeyValues::sectionNameKeyword) == 0) { |
| atomState._sectionName = entry->value; |
| haveAtom = true; |
| } |
| else if (strcmp(entry->key, KeyValues::sizeKeyword) == 0) { |
| StringRef val = entry->value; |
| if (val.getAsInteger(0, atomState._size)) |
| return make_error_code(yaml_reader_error::illegal_value); |
| haveAtom = true; |
| } |
| else if (strcmp(entry->key, KeyValues::contentKeyword) == 0) { |
| atomState._content = entry->valueSequenceBytes; |
| haveAtom = true; |
| } |
| else if (strcmp(entry->key, "align2") == 0) { |
| atomState.setAlign2(entry->value); |
| haveAtom = true; |
| } |
| else if (strcmp(entry->key, KeyValues::fixupsKeyword) == 0) { |
| inFixups = true; |
| } |
| else if (strcmp(entry->key, KeyValues::loadNameKeyword) == 0) { |
| atomState._loadName = entry->value; |
| haveAtom = true; |
| } |
| else if (strcmp(entry->key, KeyValues::valueKeyword) == 0) { |
| llvm::APInt Val; |
| StringRef(entry->value).getAsInteger(0, Val); |
| atomState._value = Val.getZExtValue(); |
| haveAtom = true; |
| } |
| else { |
| return make_error_code(yaml_reader_error::unknown_keyword); |
| } |
| } |
| else if (depthForFixups == entry->depth) { |
| if (entry->beginSequence) { |
| if (haveFixup) { |
| atomState.addFixup(file); |
| haveFixup = false; |
| } |
| } |
| if (strcmp(entry->key, KeyValues::fixupsKindKeyword) == 0) { |
| atomState.setFixupKind(entry->value); |
| haveFixup = true; |
| } |
| else if (strcmp(entry->key, KeyValues::fixupsOffsetKeyword) == 0) { |
| if (StringRef(entry->value).getAsInteger(0, |
| atomState._ref._offsetInAtom)) |
| return make_error_code(yaml_reader_error::illegal_value); |
| haveFixup = true; |
| } |
| else if (strcmp(entry->key, KeyValues::fixupsTargetKeyword) == 0) { |
| atomState.setFixupTarget(entry->value); |
| haveFixup = true; |
| } |
| else if (strcmp(entry->key, KeyValues::fixupsAddendKeyword) == 0) { |
| StringRef Addend(entry->value); |
| if (Addend.getAsInteger(0, atomState._ref._addend)) |
| return make_error_code(yaml_reader_error::illegal_value); |
| haveFixup = true; |
| } |
| } |
| } |
| lastDepth = entry->depth; |
| } |
| if (haveAtom) { |
| atomState.makeAtom(*file); |
| } |
| if (file != nullptr) { |
| file->bindTargetReferences(); |
| result.push_back(file); |
| } |
| return make_error_code(yaml_reader_error::success); |
| } |
| |
| |
| // |
| // Fill in vector<File*> from path to input text file. |
| // |
| error_code parseObjectTextFileOrSTDIN( StringRef path |
| , Platform& platform |
| , std::vector<const File*>& result) { |
| OwningPtr<llvm::MemoryBuffer> mb; |
| if (error_code ec = llvm::MemoryBuffer::getFileOrSTDIN(path, mb)) |
| return ec; |
| |
| return parseObjectText(mb.get(), platform, result); |
| } |
| |
| } // namespace yaml |
| } // namespace lld |