diff options
| -rw-r--r-- | lld/lib/Core/InputFiles.cpp | 2 | ||||
| -rw-r--r-- | lld/lib/Core/YamlKeyValues.cpp | 199 | ||||
| -rw-r--r-- | lld/lib/Core/YamlKeyValues.h | 41 | ||||
| -rw-r--r-- | lld/lib/Core/YamlReader.cpp | 1086 | ||||
| -rw-r--r-- | lld/lib/Core/YamlWriter.cpp | 141 | ||||
| -rw-r--r-- | lld/test/archive-tentdef-search.objtxt | 2 | ||||
| -rw-r--r-- | lld/test/error-atom-attribute.objtxt | 19 | ||||
| -rw-r--r-- | lld/test/error-atom-content-byte-value.objtxt | 18 | ||||
| -rw-r--r-- | lld/test/error-atom-content-bytes.objtxt | 19 | ||||
| -rw-r--r-- | lld/test/error-atom-type.objtxt | 19 | ||||
| -rw-r--r-- | lld/test/error-atom-undefined-wrong-attribue.objtxt | 18 | ||||
| -rw-r--r-- | lld/test/error-file-attribute.objtxt | 18 | ||||
| -rw-r--r-- | lld/test/error-fixup-attribute.objtxt | 22 | ||||
| -rw-r--r-- | lld/test/error-fixup-target.objtxt | 27 |
14 files changed, 1015 insertions, 616 deletions
diff --git a/lld/lib/Core/InputFiles.cpp b/lld/lib/Core/InputFiles.cpp index 5840151a894..e9a423d9a30 100644 --- a/lld/lib/Core/InputFiles.cpp +++ b/lld/lib/Core/InputFiles.cpp @@ -1,4 +1,4 @@ -//===- Core/InputFiles.cpp - Manages list of Files -----------------------===// +//===- Core/InputFiles.cpp - Manages list of Files ------------------------===// // // The LLVM Linker // diff --git a/lld/lib/Core/YamlKeyValues.cpp b/lld/lib/Core/YamlKeyValues.cpp index e21860ee199..3eab4e6d9c5 100644 --- a/lld/lib/Core/YamlKeyValues.cpp +++ b/lld/lib/Core/YamlKeyValues.cpp @@ -18,35 +18,6 @@ namespace lld { namespace yaml { -const char* const KeyValues::nameKeyword = "name"; -const char* const KeyValues::refNameKeyword = "ref-name"; -const char* const KeyValues::definitionKeyword = "definition"; -const char* const KeyValues::scopeKeyword = "scope"; -const char* const KeyValues::contentTypeKeyword = "type"; -const char* const KeyValues::deadStripKindKeyword = "dead-strip"; -const char* const KeyValues::sectionChoiceKeyword = "section-choice"; -const char* const KeyValues::interposableKeyword = "interposable"; -const char* const KeyValues::mergeKeyword = "merge"; -const char* const KeyValues::isThumbKeyword = "is-thumb"; -const char* const KeyValues::isAliasKeyword = "is-alias"; -const char* const KeyValues::sectionNameKeyword = "section-name"; -const char* const KeyValues::contentKeyword = "content"; -const char* const KeyValues::loadNameKeyword = "load-name"; -const char* const KeyValues::sizeKeyword = "size"; -const char* const KeyValues::valueKeyword = "value"; -const char* const KeyValues::fixupsKeyword = "fixups"; -const char* const KeyValues::permissionsKeyword = "permissions"; -const char* const KeyValues::canBeNullKeyword = "can-be-null"; -const char* const KeyValues::fixupsKindKeyword = "kind"; -const char* const KeyValues::fixupsOffsetKeyword = "offset"; -const char* const KeyValues::fixupsTargetKeyword = "target"; -const char* const KeyValues::fixupsAddendKeyword = "addend"; -const char* const KeyValues::fileAtomsKeyword = "atoms"; -const char* const KeyValues::fileKindKeyword = "kind"; -const char* const KeyValues::fileMembersKeyword = "members"; - - - const DefinedAtom::Definition KeyValues::definitionDefault = Atom::definitionRegular; const DefinedAtom::Scope KeyValues::scopeDefault = DefinedAtom::scopeTranslationUnit; const DefinedAtom::ContentType KeyValues::contentTypeDefault = DefinedAtom::typeData; @@ -58,36 +29,8 @@ const DefinedAtom::ContentPermissions KeyValues::permissionsDefault = DefinedAto const bool KeyValues::isThumbDefault = false; const bool KeyValues::isAliasDefault = false; const UndefinedAtom::CanBeNull KeyValues::canBeNullDefault = UndefinedAtom::canBeNullNever; -const File::Kind KeyValues::fileKindDefault = File::kindObject; -struct FileKindMapping { - const char* string; - File::Kind value; -}; - -static const FileKindMapping fileKindMappings[] = { - { "object", File::kindObject }, - { "archive", File::kindArchiveLibrary }, - { "shared-library", File::kindSharedLibrary }, - { nullptr, File::kindObject } -}; - - File::Kind KeyValues::fileKind(StringRef str) { - for (const FileKindMapping* p = fileKindMappings; p->string != nullptr; ++p) { - if (str == p->string) - return p->value; - } - llvm::report_fatal_error("bad file kind value"); -} - -const char* KeyValues::fileKind(File::Kind k) { - for (const FileKindMapping* p = fileKindMappings; p->string != nullptr; ++p) { - if ( p->value == k ) - return p->string; - } - llvm::report_fatal_error("bad file kind value"); -} struct DefinitionMapping { @@ -103,13 +46,15 @@ static const DefinitionMapping defMappings[] = { { nullptr, Atom::definitionRegular } }; -Atom::Definition KeyValues::definition(StringRef s) +bool KeyValues::definition(StringRef s, Atom::Definition &out) { for (const DefinitionMapping* p = defMappings; p->string != nullptr; ++p) { - if (s == p->string) - return p->value; + if (s == p->string) { + out = p->value; + return false; + } } - llvm::report_fatal_error("bad definition value"); + return true; } const char* KeyValues::definition(Atom::Definition s) { @@ -136,13 +81,15 @@ static const ScopeMapping scopeMappings[] = { { nullptr, DefinedAtom::scopeGlobal } }; -DefinedAtom::Scope KeyValues::scope(StringRef s) +bool KeyValues::scope(StringRef s, DefinedAtom::Scope &out) { for (const ScopeMapping* p = scopeMappings; p->string != nullptr; ++p) { - if (s == p->string) - return p->value; + if (s == p->string) { + out = p->value; + return false; + } } - llvm::report_fatal_error("bad scope value"); + return true; } const char* KeyValues::scope(DefinedAtom::Scope s) { @@ -197,13 +144,15 @@ static const ContentTypeMapping typeMappings[] = { { nullptr, DefinedAtom::typeUnknown } }; -DefinedAtom::ContentType KeyValues::contentType(StringRef s) +bool KeyValues::contentType(StringRef s, DefinedAtom::ContentType &out) { for (const ContentTypeMapping* p = typeMappings; p->string != nullptr; ++p) { - if (s == p->string) - return p->value; + if (s == p->string) { + out = p->value; + return false; + } } - llvm::report_fatal_error("bad content type value"); + return true; } const char* KeyValues::contentType(DefinedAtom::ContentType s) { @@ -225,26 +174,26 @@ struct DeadStripMapping { DefinedAtom::DeadStripKind value; }; -static const DeadStripMapping deadStripMappings[] = { +static const DeadStripMapping dsMappings[] = { { "normal", DefinedAtom::deadStripNormal }, { "never", DefinedAtom::deadStripNever }, { "always", DefinedAtom::deadStripAlways }, { nullptr, DefinedAtom::deadStripNormal } }; -DefinedAtom::DeadStripKind KeyValues::deadStripKind(StringRef s) +bool KeyValues::deadStripKind(StringRef s, DefinedAtom::DeadStripKind &out) { - for (const DeadStripMapping* p = deadStripMappings; p->string != nullptr; ++p) - { - if (s == p->string) - return p->value; + for (const DeadStripMapping* p = dsMappings; p->string != nullptr; ++p) { + if (s == p->string) { + out = p->value; + return false; + } } - llvm::report_fatal_error("bad dead strip value"); + return true; } const char* KeyValues::deadStripKind(DefinedAtom::DeadStripKind dsk) { - for (const DeadStripMapping* p = deadStripMappings; p->string != nullptr; ++p) - { + for (const DeadStripMapping* p = dsMappings; p->string != nullptr; ++p) { if ( p->value == dsk ) return p->string; } @@ -267,13 +216,15 @@ static const InterposableMapping interMappings[] = { { nullptr, DefinedAtom::interposeNo } }; -DefinedAtom::Interposable KeyValues::interposable(StringRef s) +bool KeyValues::interposable(StringRef s, DefinedAtom::Interposable &out) { for (const InterposableMapping* p = interMappings; p->string != nullptr; ++p){ - if (s == p->string) - return p->value; + if (s == p->string) { + out = p->value; + return false; + } } - llvm::report_fatal_error("bad interposable value"); + return true; } const char* KeyValues::interposable(DefinedAtom::Interposable in) { @@ -302,13 +253,15 @@ static const MergeMapping mergeMappings[] = { { nullptr, DefinedAtom::mergeNo } }; -DefinedAtom::Merge KeyValues::merge(StringRef s) +bool KeyValues::merge(StringRef s, DefinedAtom::Merge& out) { for (const MergeMapping* p = mergeMappings; p->string != nullptr; ++p) { - if (s == p->string) - return p->value; + if (s == p->string) { + out = p->value; + return false; + } } - llvm::report_fatal_error("bad merge value"); + return true; } const char* KeyValues::merge(DefinedAtom::Merge in) { @@ -336,13 +289,15 @@ static const SectionChoiceMapping sectMappings[] = { { nullptr, DefinedAtom::sectionBasedOnContent } }; -DefinedAtom::SectionChoice KeyValues::sectionChoice(StringRef s) +bool KeyValues::sectionChoice(StringRef s, DefinedAtom::SectionChoice &out) { for (const SectionChoiceMapping* p = sectMappings; p->string != nullptr; ++p){ - if (s == p->string) - return p->value; + if (s == p->string) { + out = p->value; + return false; + } } - llvm::report_fatal_error("bad dead strip value"); + return true; } const char* KeyValues::sectionChoice(DefinedAtom::SectionChoice s) { @@ -365,21 +320,23 @@ struct PermissionsMapping { }; static const PermissionsMapping permMappings[] = { - { "content", DefinedAtom::perm___ }, - { "custom", DefinedAtom::permR__ }, - { "custom-required", DefinedAtom::permR_X }, - { "custom-required", DefinedAtom::permRW_ }, - { "custom-required", DefinedAtom::permRW_L }, - { nullptr, DefinedAtom::perm___ } + { "---", DefinedAtom::perm___ }, + { "r--", DefinedAtom::permR__ }, + { "r-x", DefinedAtom::permR_X }, + { "rw-", DefinedAtom::permRW_ }, + { "rw-l", DefinedAtom::permRW_L }, + { nullptr, DefinedAtom::perm___ } }; -DefinedAtom::ContentPermissions KeyValues::permissions(StringRef s) +bool KeyValues::permissions(StringRef s, DefinedAtom::ContentPermissions &out) { for (const PermissionsMapping* p = permMappings; p->string != nullptr; ++p) { - if (s == p->string) - return p->value; + if (s == p->string) { + out = p->value; + return false; + } } - llvm::report_fatal_error("bad permissions value"); + return true; } const char* KeyValues::permissions(DefinedAtom::ContentPermissions s) { @@ -390,10 +347,42 @@ const char* KeyValues::permissions(DefinedAtom::ContentPermissions s) { llvm::report_fatal_error("bad permissions value"); } + +bool KeyValues::isThumb(StringRef s, bool &out) +{ + if ( s.equals("true") ) { + out = true; + return false; + } + + if ( s.equals("false") ) { + out = false; + return false; + } + + return true; +} + const char* KeyValues::isThumb(bool b) { return b ? "true" : "false"; } + +bool KeyValues::isAlias(StringRef s, bool &out) +{ + if ( s.equals("true") ) { + out = true; + return false; + } + + if ( s.equals("false") ) { + out = false; + return false; + } + + return true; +} + const char* KeyValues::isAlias(bool b) { return b ? "true" : "false"; } @@ -414,13 +403,15 @@ static const CanBeNullMapping cbnMappings[] = { }; -UndefinedAtom::CanBeNull KeyValues::canBeNull(StringRef s) +bool KeyValues::canBeNull(StringRef s, UndefinedAtom::CanBeNull &out) { for (const CanBeNullMapping* p = cbnMappings; p->string != nullptr; ++p) { - if (s == p->string) - return p->value; + if (s == p->string) { + out = p->value; + return false; + } } - llvm::report_fatal_error("bad can-be-null value"); + return true; } const char* KeyValues::canBeNull(UndefinedAtom::CanBeNull c) { diff --git a/lld/lib/Core/YamlKeyValues.h b/lld/lib/Core/YamlKeyValues.h index 18c8e469b5a..ecb3d2e239a 100644 --- a/lld/lib/Core/YamlKeyValues.h +++ b/lld/lib/Core/YamlKeyValues.h @@ -20,81 +20,62 @@ namespace yaml { class KeyValues { public: - static const char* const nameKeyword; - static const char* const refNameKeyword; - static const char* const sectionNameKeyword; - static const char* const contentKeyword; - static const char* const sizeKeyword; - static const char* const loadNameKeyword; - static const char* const valueKeyword; - static const char* const fixupsKeyword; - static const char* const fileAtomsKeyword; - static const char* const fileMembersKeyword; - - static const char* const fileKindKeyword; - static const File::Kind fileKindDefault; - static File::Kind fileKind(StringRef); - static const char* fileKind(File::Kind); static const char* const definitionKeyword; static const Atom::Definition definitionDefault; - static Atom::Definition definition(StringRef); + static bool definition(StringRef, Atom::Definition&); static const char* definition(Atom::Definition); static const char* const scopeKeyword; static const DefinedAtom::Scope scopeDefault; - static DefinedAtom::Scope scope(StringRef); + static bool scope(StringRef, DefinedAtom::Scope&); static const char* scope(DefinedAtom::Scope); static const char* const contentTypeKeyword; static const DefinedAtom::ContentType contentTypeDefault; - static DefinedAtom::ContentType contentType(StringRef); + static bool contentType(StringRef, DefinedAtom::ContentType&); static const char* contentType(DefinedAtom::ContentType); static const char* const deadStripKindKeyword; static const DefinedAtom::DeadStripKind deadStripKindDefault; - static DefinedAtom::DeadStripKind deadStripKind(StringRef); + static bool deadStripKind(StringRef, DefinedAtom::DeadStripKind&); static const char* deadStripKind(DefinedAtom::DeadStripKind); static const char* const sectionChoiceKeyword; static const DefinedAtom::SectionChoice sectionChoiceDefault; - static DefinedAtom::SectionChoice sectionChoice(StringRef); + static bool sectionChoice(StringRef, DefinedAtom::SectionChoice&); static const char* sectionChoice(DefinedAtom::SectionChoice); static const char* const interposableKeyword; static const DefinedAtom::Interposable interposableDefault; - static DefinedAtom::Interposable interposable(StringRef); + static bool interposable(StringRef, DefinedAtom::Interposable&); static const char* interposable(DefinedAtom::Interposable); static const char* const mergeKeyword; static const DefinedAtom::Merge mergeDefault; - static DefinedAtom::Merge merge(StringRef); + static bool merge(StringRef, DefinedAtom::Merge&); static const char* merge(DefinedAtom::Merge); static const char* const permissionsKeyword; static const DefinedAtom::ContentPermissions permissionsDefault; - static DefinedAtom::ContentPermissions permissions(StringRef); + static bool permissions(StringRef, DefinedAtom::ContentPermissions&); static const char* permissions(DefinedAtom::ContentPermissions); static const char* const isThumbKeyword; static const bool isThumbDefault; + static bool isThumb(StringRef, bool&); static const char* isThumb(bool); static const char* const isAliasKeyword; static const bool isAliasDefault; + static bool isAlias(StringRef, bool&); static const char* isAlias(bool); static const char* const canBeNullKeyword; static const UndefinedAtom::CanBeNull canBeNullDefault; - static UndefinedAtom::CanBeNull canBeNull(StringRef); + static bool canBeNull(StringRef, UndefinedAtom::CanBeNull&); static const char* canBeNull(UndefinedAtom::CanBeNull); - - static const char* const fixupsKindKeyword; - static const char* const fixupsOffsetKeyword; - static const char* const fixupsTargetKeyword; - static const char* const fixupsAddendKeyword; - }; } // namespace yaml diff --git a/lld/lib/Core/YamlReader.cpp b/lld/lib/Core/YamlReader.cpp index 6641f2f6b20..87f1e142355 100644 --- a/lld/lib/Core/YamlReader.cpp +++ b/lld/lib/Core/YamlReader.cpp @@ -1,4 +1,4 @@ -//===- Core/YamlReader.cpp - Reads YAML -----------------------------------===// +//===- Core/YamlReader.cpp - Reads YAML encode object files ---------------===// // // The LLVM Linker // @@ -31,43 +31,25 @@ #include "llvm/Support/SourceMgr.h" #include "llvm/Support/system_error.h" #include "llvm/Support/YAMLParser.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Debug.h" #include <cstring> -#include <set> -#include <type_traits> #include <vector> -using namespace lld; - -static bool getAs(const llvm::yaml::ScalarNode *SN, bool &Result) { - SmallString<4> Storage; - StringRef Value = SN->getValue(Storage); - if (Value == "true") - Result = true; - else if (Value == "false") - Result = false; - else - return false; - return true; -} - -template<class T> -typename std::enable_if<std::numeric_limits<T>::is_integer, bool>::type -getAs(const llvm::yaml::ScalarNode *SN, T &Result) { - SmallString<4> Storage; - StringRef Value = SN->getValue(Storage); - if (Value.getAsInteger(0, Result)) - return false; - return true; -} 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) @@ -101,24 +83,31 @@ public: _target = newAtom; } + typedef llvm::yaml::ScalarNode ScalarNode; + const Atom *_target; - StringRef _targetName; + ScalarNode * _targetNameNode; uint64_t _offsetInAtom; Addend _addend; Kind _kind; }; -class YAMLDefinedAtom; +/// +/// Concrete instance of lld::File created parsing YAML object files. +/// class YAMLFile : public ArchiveLibraryFile { public: YAMLFile() : ArchiveLibraryFile("<anonymous>") , _lastRefIndex(0) - , _kind(File::kindObject) - , _inArchive(false) { + , _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; } @@ -140,10 +129,12 @@ public: assert(0 && "cannot add atoms to YAML files"); } + // Standard way that archives are searched. virtual const File *find(StringRef name, bool dataSymbolOnly) const; - void bindTargetReferences(); - void addDefinedAtom(YAMLDefinedAtom *atom, StringRef refName); + 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); @@ -151,6 +142,8 @@ public: void addMember(StringRef); void setName(StringRef); + StringRef copyString(StringRef); + struct NameAtomPair { NameAtomPair(StringRef n, Atom *a) : name(n), atom(a) {} StringRef name; @@ -163,13 +156,17 @@ public: atom_collection_vector<AbsoluteAtom> _absoluteAtoms; std::vector<YAMLReference> _references; std::vector<NameAtomPair> _nameToAtomMapping; - std::vector<StringRef> _memberNames; std::vector<std::unique_ptr<YAMLFile>> _memberFiles; + std::vector<char*> _stringCopies; unsigned int _lastRefIndex; File::Kind _kind; - bool _inArchive; }; + + +/// +/// Concrete instance of lld::DefinedAtom created parsing YAML object files. +/// class YAMLDefinedAtom : public DefinedAtom { public: YAMLDefinedAtom( uint32_t ord @@ -187,13 +184,13 @@ public: , StringRef name , StringRef sectionName , uint64_t size - , std::vector<uint8_t> content) + , std::vector<uint8_t>& content) : _file(file) , _name(name) , _sectionName(sectionName) , _size(size) , _ord(ord) - , _content(std::move(content)) + , _content(content) , _alignment(alignment) , _scope(scope) , _type(type) @@ -299,12 +296,23 @@ public: it = reinterpret_cast<const void*>(index); } - void bindTargetReferences() const { + // 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) { - StringRef targetName = _file._references[i]._targetName; - Atom *targetAtom = _file.findAtom(targetName); - _file._references[i]._target = targetAtom; + 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: @@ -328,6 +336,11 @@ private: unsigned int _refEndIndex; }; + + +/// +/// Concrete instance of lld::UndefinedAtom created parsing YAML object files. +/// class YAMLUndefinedAtom : public UndefinedAtom { public: YAMLUndefinedAtom( YAMLFile &f @@ -359,6 +372,11 @@ private: UndefinedAtom::CanBeNull _canBeNull; }; + + +/// +/// Concrete instance of lld::SharedLibraryAtom created parsing YAML files. +/// class YAMLSharedLibraryAtom : public SharedLibraryAtom { public: YAMLSharedLibraryAtom( YAMLFile &f @@ -397,6 +415,11 @@ private: 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) @@ -425,12 +448,30 @@ private: uint64_t _value; }; -void YAMLFile::bindTargetReferences() { + + + +//===----------------------------------------------------------------------===// +// 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); - atom->bindTargetReferences(); + ec = atom->bindTargetReferences(stream); + if ( ec ) + return ec; } + return ec; } Atom *YAMLFile::findAtom(StringRef name) { @@ -438,7 +479,7 @@ Atom *YAMLFile::findAtom(StringRef name) { if (ci.name == name) return ci.atom; } - llvm::report_fatal_error("reference to atom that does not exist"); + return nullptr; } void YAMLFile::addDefinedAtom(YAMLDefinedAtom *atom, StringRef refName) { @@ -461,14 +502,20 @@ void YAMLFile::addAbsoluteAtom(AbsoluteAtom *atom) { _nameToAtomMapping.push_back(NameAtomPair(atom->name(), atom)); } -void YAMLFile::addMember(StringRef name) { - _memberNames.push_back(name); -} - 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() ) { @@ -479,25 +526,96 @@ const File *YAMLFile::find(StringRef name, bool dataSymbolOnly) const { return nullptr; } -class YAMLAtomState { + + +/// +/// 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: - YAMLAtomState(Platform &platform); + YAMLState(Platform &platform, llvm::yaml::Stream *s, YAMLFile *f); - void setName(StringRef n); - void setRefName(StringRef n); + 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 setFixupKind(StringRef n); - void setFixupTarget(StringRef n); - void addFixup(YAMLFile *f); + 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 makeAtom(YAMLFile&); + void moveToState(State s); + void returnToState(State s, Node *node); + + static const Transistion _s_transistions[]; Platform &_platform; + 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; @@ -515,71 +633,164 @@ public: 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 }, }; -YAMLAtomState::YAMLAtomState(Platform &platform) + +YAMLState::YAMLState(Platform &platform, Stream *stream, YAMLFile *file) : _platform(platform) - , _size(0) - , _value(0) - , _ordinal(0) - , _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.empty() ? _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; - } + , _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; @@ -598,346 +809,429 @@ void YAMLAtomState::makeAtom(YAMLFile &f) { _isAlias = KeyValues::isAliasDefault; _canBeNull = KeyValues::canBeNullDefault; _ref._target = nullptr; - _ref._targetName = StringRef(); + _ref._targetNameNode= nullptr; _ref._addend = 0; _ref._offsetInAtom = 0; _ref._kind = 0; + + _hasDefinedAtomAttributes = false; + _hasUndefinedAtomAttributes = false; + _hasSharedLibraryAtomAttributes = false; + _hasAbsoluteAtomAttributes = false; } -void YAMLAtomState::setName(StringRef n) { - _name = n; -} -void YAMLAtomState::setRefName(StringRef n) { - _refName = n; +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 YAMLAtomState::setAlign2(StringRef s) { + + +void YAMLState::setAlign2(StringRef s) { if (StringRef(s).getAsInteger(10, _alignment.powerOf2)) _alignment.powerOf2 = 1; } -void YAMLAtomState::setFixupKind(StringRef s) { - _ref._kind = _platform.kindFromString(StringRef(s)); + +// 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"; } -void YAMLAtomState::setFixupTarget(StringRef s) { - _ref._targetName = s; +// Called by parse() when recursing and switching to a new state. +void YAMLState::moveToState(State newState) { + if ( newState == _state ) + return; + DEBUG(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; } -void YAMLAtomState::addFixup(YAMLFile *f) { - f->_references.push_back(_ref); - // clear for next ref - _ref._target = nullptr; - _ref._targetName = StringRef(); - _ref._addend = 0; - _ref._offsetInAtom = 0; - _ref._kind = 0; -} - -llvm::error_code parseFixup( llvm::yaml::MappingNode *mn - , llvm::yaml::Stream &s - , Platform &p - , YAMLFile &f - , YAMLAtomState &yas) { - using namespace llvm::yaml; +// Called by parse() when returning from recursion and restoring the old state. +void YAMLState::returnToState(State prevState, Node *node) { + if ( prevState == _state ) + return; + DEBUG(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; +} - for (auto &keyval : *mn) { - ScalarNode *key = llvm::dyn_cast<ScalarNode>(keyval.getKey()); - if (!key) { - s.printError(key, "Expected a scalar value"); - return make_error_code(yaml_reader_error::illegal_value); - } - ScalarNode *value = llvm::dyn_cast<ScalarNode>(keyval.getValue()); - if (!value) { - s.printError(value, "Expected a scalar value"); - return make_error_code(yaml_reader_error::illegal_value); - } - llvm::StringRef keyValue = key->getValue(storage); - if (keyValue == KeyValues::fixupsOffsetKeyword) { - if (!getAs(value, yas._ref._offsetInAtom)) { - s.printError(value, "Invalid value for offset"); - return make_error_code(yaml_reader_error::illegal_value); - } - } else if (keyValue == KeyValues::fixupsKindKeyword) { - yas._ref._kind = p.kindFromString(value->getValue(storage)); - } else if (keyValue == KeyValues::fixupsTargetKeyword) { - // FIXME: string lifetime. - yas._ref._targetName = value->getValue(storage); - } else if (keyValue == KeyValues::fixupsAddendKeyword) { - if (!getAs(value, yas._ref._addend)) { - s.printError(value, "Invalid value for addend"); - return make_error_code(yaml_reader_error::illegal_value); - } - } else { - s.printError(key, "Unrecognized key"); - return make_error_code(yaml_reader_error::unknown_keyword); - } + +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); } - yas.addFixup(&f); - return make_error_code(yaml_reader_error::success); + _hasDefinedAtomAttributes = true; } -llvm::error_code parseAtom( llvm::yaml::MappingNode *mn - , llvm::yaml::Stream &s - , Platform &p - , YAMLFile &f) { - using namespace llvm::yaml; - YAMLAtomState yas(p); +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); + } +} - for (MappingNode::iterator i = mn->begin(), e = mn->end(); i != e; ++i) { - ScalarNode *Key = llvm::dyn_cast<ScalarNode>(i->getKey()); - if (!Key) - return make_error_code(yaml_reader_error::illegal_value); - llvm::StringRef KeyValue = Key->getValue(storage); - if (KeyValue == KeyValues::contentKeyword) { - ScalarNode *scalarValue = llvm::dyn_cast<ScalarNode>(i->getValue()); - if (scalarValue) { - yas._type = KeyValues::contentType(scalarValue->getValue(storage)); - } else { - SequenceNode *Value = llvm::dyn_cast<SequenceNode>(i->getValue()); - if (!Value) { - s.printError(i->getValue(), "Expected a sequence"); - return make_error_code(yaml_reader_error::illegal_value); - } - for (SequenceNode::iterator ci = Value->begin(), ce = Value->end(); - ci != ce; ++ci) { - ScalarNode *Entry = llvm::dyn_cast<ScalarNode>(&*ci); - if (!Entry) { - s.printError(i->getValue(), "Expected a scalar value"); - return make_error_code(yaml_reader_error::illegal_value); - } - unsigned int ContentByte; - if (Entry->getValue(storage).getAsInteger(16, ContentByte)) { - s.printError(i->getValue(), "Invalid content byte"); - return make_error_code(yaml_reader_error::illegal_value); - } - if (ContentByte > 0xFF) { - s.printError(i->getValue(), "Byte out of range (> 0xFF)"); - return make_error_code(yaml_reader_error::illegal_value); - } - yas._content.push_back(ContentByte & 0xFF); - } - } - } else if (KeyValue == KeyValues::fixupsKeyword) { - SequenceNode *Value = llvm::dyn_cast<SequenceNode>(i->getValue()); - if (!Value) { - s.printError(i->getValue(), "Expected a sequence"); - return make_error_code(yaml_reader_error::illegal_value); - } - for (auto &i : *Value) { - MappingNode *Fixup = llvm::dyn_cast<MappingNode>(&i); - if (!Fixup) { - s.printError(&i, "Expected a map"); - return make_error_code(yaml_reader_error::illegal_value); - } - if (error_code ec = parseFixup(Fixup, s, p, f, yas)) - return ec; - } - } else { - // The rest of theses all require value to be a scalar. - ScalarNode *Value = llvm::dyn_cast<ScalarNode>(i->getValue()); - if (!Value) { - s.printError(i->getValue(), "Expected a scalar value"); - return make_error_code(yaml_reader_error::illegal_value); - } - if (KeyValue == KeyValues::nameKeyword) { - // FIXME: String lifetime. - yas.setName(Value->getValue(storage)); - } else if (KeyValue == KeyValues::refNameKeyword) { - // FIXME: String lifetime. - yas.setRefName(Value->getValue(storage)); - } else if (KeyValue == KeyValues::valueKeyword) { - if (!getAs(Value, yas._value)) { - s.printError(Value, "Invalid value for value"); - return make_error_code(yaml_reader_error::illegal_value); - } - } else if (KeyValue == KeyValues::loadNameKeyword) - // FIXME: String lifetime. - yas._loadName = Value->getValue(storage); - else if (KeyValue == KeyValues::definitionKeyword) - yas._definition = KeyValues::definition(Value->getValue(storage)); - else if (KeyValue == KeyValues::scopeKeyword) - yas._scope = KeyValues::scope(Value->getValue(storage)); - else if (KeyValue == KeyValues::contentTypeKeyword) - yas._type = KeyValues::contentType(Value->getValue(storage)); - else if (KeyValue == KeyValues::deadStripKindKeyword) - yas._deadStrip = KeyValues::deadStripKind(Value->getValue(storage)); - else if (KeyValue == KeyValues::sectionChoiceKeyword) - yas._sectionChoice = KeyValues::sectionChoice(Value->getValue(storage)); - else if (KeyValue == KeyValues::mergeKeyword) - yas._merge = KeyValues::merge(Value->getValue(storage)); - else if (KeyValue == KeyValues::interposableKeyword) - yas._interpose = KeyValues::interposable(Value->getValue(storage)); - else if (KeyValue == KeyValues::isThumbKeyword) { - if (!getAs(Value, yas._isThumb)) { - s.printError(Value, "Invalid value for isThumb"); - return make_error_code(yaml_reader_error::illegal_value); - } - } else if (KeyValue == KeyValues::isAliasKeyword) { - if (!getAs(Value, yas._isAlias)) { - s.printError(Value, "Invalid value for isAlias"); - return make_error_code(yaml_reader_error::illegal_value); - } - } else if (KeyValue == KeyValues::canBeNullKeyword) { - yas._canBeNull = KeyValues::canBeNull(Value->getValue(storage)); - if (yas._definition == Atom::definitionSharedLibrary - && yas._canBeNull == UndefinedAtom::canBeNullAtBuildtime) { - s.printError(Value, "Invalid value for can be null"); - return make_error_code(yaml_reader_error::illegal_value); - } - } else if (KeyValue == KeyValues::sectionNameKeyword) - // FIXME: String lifetime. - yas._sectionName = Value->getValue(storage); - else if (KeyValue == KeyValues::sizeKeyword) { - if (!getAs(Value, yas._size)) { - s.printError(Value, "Invalid value for size"); - return make_error_code(yaml_reader_error::illegal_value); - } - } else if (KeyValue == "align2") - yas.setAlign2(Value->getValue(storage)); - else { - s.printError(Key, "Unrecognized key"); - return make_error_code(yaml_reader_error::unknown_keyword); - } - } +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); } - yas.makeAtom(f); - return make_error_code(yaml_reader_error::success); + _hasDefinedAtomAttributes = true; } -llvm::error_code parseAtoms( llvm::yaml::SequenceNode *atoms - , llvm::yaml::Stream &s - , Platform &p - , YAMLFile &f) { - using namespace llvm::yaml; +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; +} - for (auto &atom : *atoms) { - if (MappingNode *a = llvm::dyn_cast<MappingNode>(&atom)) { - if (llvm::error_code ec = parseAtom(a, s, p, f)) - return ec; - } else { - s.printError(&atom, "Expected map"); - return make_error_code(yaml_reader_error::illegal_value); - } +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); } - return make_error_code(yaml_reader_error::success); + _hasDefinedAtomAttributes = true; } -llvm::error_code parseArchive( llvm::yaml::SequenceNode *archive - , llvm::yaml::Stream &s - , Platform &p - , YAMLFile &f) { - using namespace llvm::yaml; +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; +} - for (auto &member : *archive) { - std::unique_ptr<YAMLFile> mf(new YAMLFile); - MappingNode *mem = llvm::dyn_cast<MappingNode>(&member); - if (!mem) { - s.printError(&member, "Expected map"); - return make_error_code(yaml_reader_error::illegal_value); +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 = _platform.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(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); + } } - for (auto &keyVal : *mem) { - ScalarNode *key = llvm::dyn_cast<ScalarNode>(keyVal.getKey()); - if (!key) { - s.printError(keyVal.getKey(), "Expected scalar value"); - return 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); } - if (key->getValue(storage) == "name") { - ScalarNode *value = llvm::dyn_cast<ScalarNode>(keyVal.getValue()); - if (!value) { - s.printError(keyVal.getValue(), "Expected scalar value"); - return make_error_code(yaml_reader_error::illegal_value); + else { + for (Node &seqEntry : *seq ) { + this->parse(&seqEntry, StringRef("<any-seq-item>")); + if ( _error ) + break; } - // FIXME: String lifetime. - mf->setName(value->getValue(storage)); - } else if (key->getValue(storage) == "atoms") { - SequenceNode *atoms = llvm::dyn_cast<SequenceNode>(keyVal.getValue()); - if (!atoms) { - s.printError(keyVal.getValue(), "Expected sequence"); - return make_error_code(yaml_reader_error::illegal_value); + } + } + 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; } - if (error_code ec = parseAtoms(atoms, s, p, *mf)) - return ec; - } else { - s.printError(key, "Unrecognized key"); - return make_error_code(yaml_reader_error::unknown_keyword); } } - f._memberFiles.push_back(std::move(mf)); + else { + _stream->printError(node, "unexpected node type"); + _error = make_error_code(yaml_reader_error::illegal_value); + } + this->returnToState(savedState, node); + return; } - return make_error_code(yaml_reader_error::success); + 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 parseObjectText( llvm::MemoryBuffer *mb - , Platform& platform - , std::vector<std::unique_ptr<const File>> &result) { - using namespace llvm::yaml; - llvm::SourceMgr sm; - Stream stream(mb->getBuffer(), sm); - - llvm::SmallString<32> storage; - for (Document &d : stream) { - std::unique_ptr<YAMLFile> CurFile(new YAMLFile); - if (llvm::isa<NullNode>(d.getRoot())) + , Platform& platform + , std::vector<std::unique_ptr<const File>> &result) { + llvm::SourceMgr srcMgr; + llvm::yaml::Stream stream(mb->getBuffer(), srcMgr); + + for (llvm::yaml::Document &d : stream) { + std::unique_ptr<YAMLFile> curFile(new YAMLFile); + if (llvm::isa<llvm::yaml::NullNode>(d.getRoot())) continue; // Empty files are allowed. - MappingNode *n = llvm::dyn_cast<MappingNode>(d.getRoot()); - if (!n) { - stream.printError(d.getRoot(), "Expected map"); - return make_error_code(yaml_reader_error::illegal_value); - } - for (MappingNode::iterator mi = n->begin(), me = n->end(); mi != me; ++mi) { - ScalarNode *key = llvm::dyn_cast<ScalarNode>(mi->getKey()); - if (!key) { - stream.printError(mi->getValue(), "Expected scalar value"); - return make_error_code(yaml_reader_error::illegal_value); - } - if (key->getValue(storage) == "atoms") { - SequenceNode *Atoms = llvm::dyn_cast<SequenceNode>(mi->getValue()); - if (!Atoms) { - stream.printError(mi->getValue(), "Expected sequence"); - return make_error_code(yaml_reader_error::illegal_value); - } - if (error_code ec = parseAtoms(Atoms, stream, platform, *CurFile)) - return ec; - } else if (key->getValue(storage) == "archive") { - CurFile->_kind = YAMLFile::kindArchiveLibrary; - SequenceNode *members = llvm::dyn_cast<SequenceNode>(mi->getValue()); - if (!members) { - stream.printError(mi->getValue(), "Expected sequence"); - return make_error_code(yaml_reader_error::illegal_value); - } - if (error_code ec = parseArchive( members - , stream - , platform - , *CurFile)) - return ec; - } else { - stream.printError(key, "Unrecognized key"); - return make_error_code(yaml_reader_error::unknown_keyword); - } - } - if (stream.failed()) + YAMLState yamlState(platform, &stream, curFile.get()); + yamlState.parse(d.getRoot(), StringRef("<root>")); + + if ( stream.failed() ) return make_error_code(yaml_reader_error::illegal_value); - CurFile->bindTargetReferences(); - result.emplace_back(CurFile.release()); + 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); } + + // // Fill in vector<File*> from path to input text file. // -error_code parseObjectTextFileOrSTDIN( StringRef path - , Platform& platform - , std::vector< - std::unique_ptr<const File>>& result) { +error_code +parseObjectTextFileOrSTDIN( StringRef path + , Platform& platform + , std::vector<std::unique_ptr<const File>>& result) { OwningPtr<llvm::MemoryBuffer> mb; if (error_code ec = llvm::MemoryBuffer::getFileOrSTDIN(path, mb)) return ec; diff --git a/lld/lib/Core/YamlWriter.cpp b/lld/lib/Core/YamlWriter.cpp index e056eb898c9..03539c99914 100644 --- a/lld/lib/Core/YamlWriter.cpp +++ b/lld/lib/Core/YamlWriter.cpp @@ -164,9 +164,8 @@ public: bool hasDash = false; if ( !atom.name().empty() ) { out << " - " - << KeyValues::nameKeyword - << ":" - << spacePadding(KeyValues::nameKeyword) + << "name:" + << spacePadding(strlen("name")) << atom.name() << "\n"; hasDash = true; @@ -174,9 +173,8 @@ public: if ( _rnb.hasRefName(&atom) ) { out << (hasDash ? " " : " - ") - << KeyValues::refNameKeyword - << ":" - << spacePadding(KeyValues::refNameKeyword) + << "ref-name:" + << spacePadding(strlen("ref-name")) << _rnb.refName(&atom) << "\n"; hasDash = true; @@ -184,9 +182,8 @@ public: if ( atom.definition() != KeyValues::definitionDefault ) { out << (hasDash ? " " : " - ") - << KeyValues::definitionKeyword - << ":" - << spacePadding(KeyValues::definitionKeyword) + << "definition:" + << spacePadding(strlen("definition")) << KeyValues::definition(atom.definition()) << "\n"; hasDash = true; @@ -194,9 +191,8 @@ public: if ( atom.scope() != KeyValues::scopeDefault ) { out << (hasDash ? " " : " - ") - << KeyValues::scopeKeyword - << ":" - << spacePadding(KeyValues::scopeKeyword) + << "scope:" + << spacePadding(strlen("scope")) << KeyValues::scope(atom.scope()) << "\n"; hasDash = true; @@ -204,70 +200,62 @@ public: if ( atom.interposable() != KeyValues::interposableDefault ) { out << " " - << KeyValues::interposableKeyword - << ":" - << spacePadding(KeyValues::interposableKeyword) + << "interposable:" + << spacePadding(strlen("interposable")) << KeyValues::interposable(atom.interposable()) << "\n"; } if ( atom.merge() != KeyValues::mergeDefault ) { out << " " - << KeyValues::mergeKeyword - << ":" - << spacePadding(KeyValues::mergeKeyword) + << "merge:" + << spacePadding(strlen("merge")) << KeyValues::merge(atom.merge()) << "\n"; } if ( atom.contentType() != KeyValues::contentTypeDefault ) { out << " " - << KeyValues::contentTypeKeyword - << ":" - << spacePadding(KeyValues::contentTypeKeyword) + << "type:" + << spacePadding(strlen("type")) << KeyValues::contentType(atom.contentType()) << "\n"; } if ( atom.deadStrip() != KeyValues::deadStripKindDefault ) { out << " " - << KeyValues::deadStripKindKeyword - << ":" - << spacePadding(KeyValues::deadStripKindKeyword) + << "dead-strip:" + << spacePadding(strlen("dead-strip")) << KeyValues::deadStripKind(atom.deadStrip()) << "\n"; } if ( atom.sectionChoice() != KeyValues::sectionChoiceDefault ) { out << " " - << KeyValues::sectionChoiceKeyword - << ":" - << spacePadding(KeyValues::sectionChoiceKeyword) + << "section-choice:" + << spacePadding(strlen("section-choice")) << KeyValues::sectionChoice(atom.sectionChoice()) << "\n"; assert( ! atom.customSectionName().empty() ); out << " " - << KeyValues::sectionNameKeyword - << ":" - << spacePadding(KeyValues::sectionNameKeyword) + << "section-name:" + << spacePadding(strlen("section-name")) << atom.customSectionName() << "\n"; } if ( atom.isThumb() != KeyValues::isThumbDefault ) { out << " " - << KeyValues::isThumbKeyword - << ":" - << spacePadding(KeyValues::isThumbKeyword) + << "is-thumb:" + << spacePadding(strlen("is-thumb")) << KeyValues::isThumb(atom.isThumb()) << "\n"; } if ( atom.isAlias() != KeyValues::isAliasDefault ) { out << " " - << KeyValues::isAliasKeyword - << ":" - << spacePadding(KeyValues::isAliasKeyword) + << "is-alias:" + << spacePadding(strlen("is-alias")) << KeyValues::isAlias(atom.isAlias()) << "\n"; } @@ -275,9 +263,8 @@ public: if ( (atom.contentType() != DefinedAtom::typeZeroFill) && (atom.size() != 0) ) { out << " " - << KeyValues::contentKeyword - << ":" - << spacePadding(KeyValues::contentKeyword) + << "content:" + << spacePadding(strlen("content")) << "[ "; ArrayRef<uint8_t> arr = atom.rawContent(); bool needComma = false; @@ -301,15 +288,13 @@ public: wroteFirstFixup = true; } out << " - " - << KeyValues::fixupsOffsetKeyword - << ":" - << spacePadding(KeyValues::fixupsOffsetKeyword) + << "offset:" + << spacePadding(strlen("offset")) << ref->offsetInAtom() << "\n"; out << " " - << KeyValues::fixupsKindKeyword - << ":" - << spacePadding(KeyValues::fixupsKindKeyword) + << "kind:" + << spacePadding(strlen("kind")) << _platform.kindToString(ref->kind()) << "\n"; const Atom* target = ref->target(); @@ -319,17 +304,15 @@ public: refName = _rnb.refName(target); assert(!refName.empty()); out << " " - << KeyValues::fixupsTargetKeyword - << ":" - << spacePadding(KeyValues::fixupsTargetKeyword) + << "target:" + << spacePadding(strlen("target")) << refName << "\n"; } if ( ref->addend() != 0 ) { out << " " - << KeyValues::fixupsAddendKeyword - << ":" - << spacePadding(KeyValues::fixupsAddendKeyword) + << "addend:" + << spacePadding(strlen("addend")) << ref->addend() << "\n"; } @@ -348,24 +331,21 @@ public: } out << " - " - << KeyValues::nameKeyword - << ":" - << spacePadding(KeyValues::nameKeyword) + << "name:" + << spacePadding(strlen("name")) << atom.name() << "\n"; out << " " - << KeyValues::definitionKeyword - << ":" - << spacePadding(KeyValues::definitionKeyword) + << "definition:" + << spacePadding(strlen("definition")) << KeyValues::definition(atom.definition()) << "\n"; if ( atom.canBeNull() != KeyValues::canBeNullDefault ) { out << " " - << KeyValues::canBeNullKeyword - << ":" - << spacePadding(KeyValues::canBeNullKeyword) + << "can-be-null:" + << spacePadding(strlen("can-be-null")) << KeyValues::canBeNull(atom.canBeNull()) << "\n"; } @@ -382,33 +362,29 @@ public: } out << " - " - << KeyValues::nameKeyword - << ":" - << spacePadding(KeyValues::nameKeyword) + << "name:" + << spacePadding(strlen("name")) << atom.name() << "\n"; out << " " - << KeyValues::definitionKeyword - << ":" - << spacePadding(KeyValues::definitionKeyword) + << "definition:" + << spacePadding(strlen("definition")) << KeyValues::definition(atom.definition()) << "\n"; if ( !atom.loadName().empty() ) { out << " " - << KeyValues::loadNameKeyword - << ":" - << spacePadding(KeyValues::loadNameKeyword) + << "load-name:" + << spacePadding(strlen("load-name")) << atom.loadName() << "\n"; } if ( atom.canBeNullAtRuntime() ) { out << " " - << KeyValues::canBeNullKeyword - << ":" - << spacePadding(KeyValues::canBeNullKeyword) + << "can-be-null:" + << spacePadding(strlen("can-be-null")) << KeyValues::canBeNull(UndefinedAtom::canBeNullAtRuntime) << "\n"; } @@ -425,23 +401,20 @@ public: } out << " - " - << KeyValues::nameKeyword - << ":" - << spacePadding(KeyValues::nameKeyword) + << "name:" + << spacePadding(strlen("name")) << atom.name() << "\n"; out << " " - << KeyValues::definitionKeyword - << ":" - << spacePadding(KeyValues::definitionKeyword) + << "definition:" + << spacePadding(strlen("definition")) << KeyValues::definition(atom.definition()) << "\n"; out << " " - << KeyValues::valueKeyword - << ":" - << spacePadding(KeyValues::valueKeyword) + << "value:" + << spacePadding(strlen("value")) << "0x"; out.write_hex(atom.value()); out << "\n"; @@ -450,10 +423,10 @@ public: private: // return a string of the correct number of spaces to align value - const char* spacePadding(const char* key) { + const char* spacePadding(int keyLen) { const char* spaces = " "; - assert(strlen(spaces) > strlen(key)); - return &spaces[strlen(key)]; + assert(strlen(spaces) > keyLen); + return &spaces[keyLen]; } char hexdigit(uint8_t nibble) { diff --git a/lld/test/archive-tentdef-search.objtxt b/lld/test/archive-tentdef-search.objtxt index 48859088895..09cb3673ec5 100644 --- a/lld/test/archive-tentdef-search.objtxt +++ b/lld/test/archive-tentdef-search.objtxt @@ -14,7 +14,7 @@ atoms: - name: bar scope: global - content: zero-fill + type: zero-fill merge: asTentative --- diff --git a/lld/test/error-atom-attribute.objtxt b/lld/test/error-atom-attribute.objtxt new file mode 100644 index 00000000000..5be6287bbbd --- /dev/null +++ b/lld/test/error-atom-attribute.objtxt @@ -0,0 +1,19 @@ +# RUN: not lld-core %s 2> %t.err +# RUN: FileCheck < %t.err %s + +# +# Test that unknown atom attribute produces a readable error. +# + +--- +atoms: + - name: entry + scope: hidden + foobar: true + dead-strip: never + +... + + +# CHECK: error: Unknown atom attribute +# CHECK: foobar diff --git a/lld/test/error-atom-content-byte-value.objtxt b/lld/test/error-atom-content-byte-value.objtxt new file mode 100644 index 00000000000..4113cad5e2b --- /dev/null +++ b/lld/test/error-atom-content-byte-value.objtxt @@ -0,0 +1,18 @@ +# RUN: not lld-core %s 2> %t.err +# RUN: FileCheck < %t.err %s + +# +# Test that an invalid hex byte produces a readable error. +# + +--- +atoms: + - name: entry + scope: hidden + content: [ A5, 00, 4G, 1F ] + +... + + +# CHECK: error: Invalid content hex byte +# CHECK: 4G diff --git a/lld/test/error-atom-content-bytes.objtxt b/lld/test/error-atom-content-bytes.objtxt new file mode 100644 index 00000000000..40e9d6e4b6a --- /dev/null +++ b/lld/test/error-atom-content-bytes.objtxt @@ -0,0 +1,19 @@ +# RUN: not lld-core %s 2> %t.err +# RUN: FileCheck < %t.err %s + +# +# Test that an out of range byte value produces a readable error. +# + +--- +atoms: + - name: entry + scope: hidden + content: [ A5, 1234, 00, 4F ] + +... + + +# CHECK: error: Content hex byte out of range +# CHECK: 1234 + diff --git a/lld/test/error-atom-type.objtxt b/lld/test/error-atom-type.objtxt new file mode 100644 index 00000000000..85a568e6503 --- /dev/null +++ b/lld/test/error-atom-type.objtxt @@ -0,0 +1,19 @@ +# RUN: not lld-core %s 2> %t.err +# RUN: FileCheck < %t.err %s + +# +# Test that an unknown content type produces a readable error. +# + +--- +atoms: + - name: entry + scope: hidden + type: superluminal + dead-strip: never + +... + + +# CHECK: error: Invalid value for 'type:' +# CHECK: superluminal diff --git a/lld/test/error-atom-undefined-wrong-attribue.objtxt b/lld/test/error-atom-undefined-wrong-attribue.objtxt new file mode 100644 index 00000000000..342adfb3208 --- /dev/null +++ b/lld/test/error-atom-undefined-wrong-attribue.objtxt @@ -0,0 +1,18 @@ +# RUN: not lld-core %s 2> %t.err +# RUN: FileCheck < %t.err %s + +# +# Test that a defined attribute on an undefined atom produces a readable error. +# + +--- +atoms: + - name: foo + type: code + definition: undefined + +... + + +# CHECK: error: Undefined atom 'foo' has attributes only allowed on defined atoms + diff --git a/lld/test/error-file-attribute.objtxt b/lld/test/error-file-attribute.objtxt new file mode 100644 index 00000000000..4806e4c8562 --- /dev/null +++ b/lld/test/error-file-attribute.objtxt @@ -0,0 +1,18 @@ +# RUN: not lld-core %s 2> %t.err +# RUN: FileCheck < %t.err %s + +# +# Test that unknown file attribute produces a readable error. +# + +--- +aardvark: true +atoms: + - name: entry + scope: hidden + +... + + +# CHECK: error: Unknown file attribute +# CHECK: aardvark diff --git a/lld/test/error-fixup-attribute.objtxt b/lld/test/error-fixup-attribute.objtxt new file mode 100644 index 00000000000..6a2fd2a94e1 --- /dev/null +++ b/lld/test/error-fixup-attribute.objtxt @@ -0,0 +1,22 @@ +# RUN: not lld-core %s 2> %t.err +# RUN: FileCheck < %t.err %s + +# +# Test that unknown fixup attribute produces a readable error. +# + +--- +atoms: + - name: entry + scope: hidden + fixups: + - offset: 3 + kind: 3 + weasel: bar + addend: 100 + +... + + +# CHECK: error: Unknown fixup attribute +# CHECK: weasel diff --git a/lld/test/error-fixup-target.objtxt b/lld/test/error-fixup-target.objtxt new file mode 100644 index 00000000000..664d0904692 --- /dev/null +++ b/lld/test/error-fixup-target.objtxt @@ -0,0 +1,27 @@ +# RUN: not lld-core %s 2> %t.err +# RUN: FileCheck < %t.err %s + +# +# Test that unbindable target name produces a readable error. +# + +--- +atoms: + - name: entry + scope: hidden + fixups: + - offset: 3 + kind: 3 + target: bar + - offset: 5 + kind: 3 + target: baz + + - name: bar + definition: undefined + +... + + +# CHECK: error: Fixup has target 'baz' which does not exist +# CHECK: baz |

