summaryrefslogtreecommitdiffstats
path: root/lld/lib/Core/YamlReader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lld/lib/Core/YamlReader.cpp')
-rw-r--r--lld/lib/Core/YamlReader.cpp559
1 files changed, 559 insertions, 0 deletions
diff --git a/lld/lib/Core/YamlReader.cpp b/lld/lib/Core/YamlReader.cpp
new file mode 100644
index 00000000000..86dea545858
--- /dev/null
+++ b/lld/lib/Core/YamlReader.cpp
@@ -0,0 +1,559 @@
+//===- 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 "lld/Core/Atom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Reference.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 <vector>
+
+namespace { const llvm::error_code success; }
+
+namespace lld {
+namespace yaml {
+class YAML {
+public:
+ struct Entry {
+ Entry(const char *k, const char *v, int d, bool bd, bool bs)
+ : key(strdup(k))
+ , value(strdup(v))
+ , depth(d)
+ , beginSequence(bs)
+ , beginDocument(bd) {}
+
+ const char *key;
+ const char *value;
+ 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 = NULL;
+ unsigned int lineNumber = 1;
+ int depth = 0;
+ bool nextKeyIsStartOfDocument = false;
+ bool nextKeyIsStartOfSequence = false;
+ 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
+ } 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 == '_')) {
+ p = &value[0];
+ *p++ = c;
+ state = inValue;
+ } else if (c == '\n') {
+ entries.push_back(new Entry(key, "", depth,
+ nextKeyIsStartOfDocument,
+ nextKeyIsStartOfSequence));
+ nextKeyIsStartOfSequence = false;
+ nextKeyIsStartOfDocument = false;
+ state = inDocument;
+ depth = 0;
+ } else if (c == '[') {
+ state = inValueSequence;
+ } else if (c == ' ') {
+ // eat space
+ } else {
+ return;
+ }
+ break;
+ case inValue:
+ if (isalnum(c) || (c == '-') || (c == '_')) {
+ *p++ = c;
+ } else if (c == '\n') {
+ *p = '\0';
+ entries.push_back(new Entry(key, value, depth,
+ nextKeyIsStartOfDocument,
+ nextKeyIsStartOfSequence));
+ nextKeyIsStartOfSequence = false;
+ nextKeyIsStartOfDocument = false;
+ state = inDocument;
+ depth = 0;
+ }
+ break;
+ case inValueSequence:
+ if (c == ']')
+ state = inValueSequenceEnd;
+ break;
+ case inValueSequenceEnd:
+ if (c == '\n') {
+ state = inDocument;
+ depth = 0;
+ }
+ break;
+ }
+ }
+}
+
+class YAMLFile : public File {
+public:
+ YAMLFile()
+ : File("path")
+ , _lastRefIndex(0) {}
+
+ virtual bool forEachAtom(File::AtomHandler &) const;
+ virtual bool justInTimeforEachAtom(llvm::StringRef name,
+ File::AtomHandler &) const;
+
+ std::vector<Atom *> _atoms;
+ std::vector<Reference> _references;
+ unsigned int _lastRefIndex;
+};
+
+bool YAMLFile::forEachAtom(File::AtomHandler &handler) const {
+ handler.doFile(*this);
+ for (std::vector<Atom *>::const_iterator it = _atoms.begin();
+ it != _atoms.end(); ++it) {
+ handler.doAtom(**it);
+ }
+ return true;
+}
+
+bool YAMLFile::justInTimeforEachAtom(llvm::StringRef name,
+ File::AtomHandler &handler) const {
+ return false;
+}
+
+
+class YAMLAtom : public Atom {
+public:
+ YAMLAtom( Definition d
+ , Combine c
+ , Scope s
+ , ContentType ct
+ , SectionChoice sc
+ , bool uvn
+ , bool dds
+ , bool tb
+ , bool al
+ , Alignment a
+ , YAMLFile *f
+ , const char *n)
+ : Atom(d, c, s, ct, sc, uvn, dds, tb, al, a)
+ , _file(f)
+ , _name(n)
+ , _size(0)
+ , _refStartIndex(f->_lastRefIndex)
+ , _refEndIndex(f->_references.size()) {
+ f->_lastRefIndex = _refEndIndex;
+ }
+
+ virtual const class File *file() const {
+ return _file;
+ }
+
+ virtual bool translationUnitSource(const char* *dir, const char* *name) const{
+ return false;
+ }
+
+ virtual llvm::StringRef name() const {
+ return _name;
+ }
+
+ virtual uint64_t objectAddress() const {
+ return 0;
+ }
+
+ virtual uint64_t size() const {
+ return _size;
+ }
+
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual Reference::iterator referencesBegin() const;
+ virtual Reference::iterator referencesEnd() const;
+private:
+ YAMLFile *_file;
+ const char *_name;
+ unsigned long _size;
+ unsigned int _refStartIndex;
+ unsigned int _refEndIndex;
+};
+
+Reference::iterator YAMLAtom::referencesBegin() const {
+ if (_file->_references.size() < _refStartIndex)
+ return (Reference::iterator)&_file->_references[_refStartIndex];
+ return 0;
+}
+
+Reference::iterator YAMLAtom::referencesEnd() const {
+ if (_file->_references.size() < _refEndIndex)
+ return (Reference::iterator)&_file->_references[_refEndIndex];
+ return 0;
+}
+
+class YAMLAtomState {
+public:
+ YAMLAtomState();
+
+ void setName(const char *n);
+ void setScope(const char *n);
+ void setType(const char *n);
+ void setAlign2(const char *n);
+ void setDefinition(const char *n);
+
+ void setFixupKind(const char *n);
+ void setFixupOffset(const char *n);
+ void setFixupTarget(const char *n);
+ void addFixup(YAMLFile *f);
+
+ void makeAtom(YAMLFile *);
+
+private:
+ const char *_name;
+ Atom::Alignment _align;
+ Atom::Combine _combine;
+ Atom::ContentType _type;
+ Atom::Scope _scope;
+ Atom::Definition _def;
+ Atom::SectionChoice _sectionChoice;
+ bool _userVisibleName;
+ bool _dontDeadStrip;
+ bool _thumb;
+ bool _alias;
+ Reference _ref;
+};
+
+YAMLAtomState::YAMLAtomState()
+ : _name(NULL)
+ , _align(0, 0)
+ , _combine(Atom::combineNever)
+ , _type(Atom::typeData)
+ , _scope(Atom::scopeGlobal)
+ , _userVisibleName(true)
+ , _dontDeadStrip(false)
+ , _thumb(false)
+ , _alias(false) {
+ _ref.target = NULL;
+ _ref.addend = 0;
+ _ref.offsetInAtom = 0;
+ _ref.kind = 0;
+ _ref.flags = 0;
+}
+
+void YAMLAtomState::makeAtom(YAMLFile *f) {
+ Atom *a = new YAMLAtom(_def, _combine, _scope, _type, _sectionChoice,
+ _userVisibleName, _dontDeadStrip, _thumb, _alias,
+ _align, f, _name);
+
+ f->_atoms.push_back(a);
+
+ // reset state for next atom
+ _name = NULL;
+ _align.powerOf2 = 0;
+ _align.modulus = 0;
+ _combine = Atom::combineNever;
+ _type = Atom::typeData;
+ _scope = Atom::scopeGlobal;
+ _def = Atom::definitionRegular;
+ _sectionChoice = Atom::sectionBasedOnContent;
+ _userVisibleName = true;
+ _dontDeadStrip = false;
+ _thumb = false;
+ _alias = false;
+ _ref.target = NULL;
+ _ref.addend = 0;
+ _ref.offsetInAtom = 0;
+ _ref.kind = 0;
+ _ref.flags = 0;
+}
+
+void YAMLAtomState::setName(const char *n) {
+ _name = n;
+}
+
+void YAMLAtomState::setScope(const char *s) {
+ if (strcmp(s, "global") == 0)
+ _scope = Atom::scopeGlobal;
+ else if (strcmp(s, "hidden") == 0)
+ _scope = Atom::scopeLinkageUnit;
+ else if (strcmp(s, "static") == 0)
+ _scope = Atom::scopeTranslationUnit;
+ else
+ llvm::report_fatal_error("bad scope value");
+}
+
+void YAMLAtomState::setType(const char *s) {
+ if (strcmp(s, "code") == 0)
+ _type = Atom::typeCode;
+ else if (strcmp(s, "c-string") == 0)
+ _type = Atom::typeCString;
+ else if (strcmp(s, "zero-fill") == 0)
+ _type = Atom::typeZeroFill;
+ else if (strcmp(s, "data") == 0)
+ _type = Atom::typeData;
+ else
+ llvm::report_fatal_error("bad type value");
+}
+
+void YAMLAtomState::setAlign2(const char *s) {
+ llvm::StringRef str(s);
+ uint32_t res;
+ str.getAsInteger(10, res);
+ _align.powerOf2 = static_cast<uint16_t>(res);
+}
+
+void YAMLAtomState::setDefinition(const char *s) {
+ if (strcmp(s, "regular") == 0)
+ _def = Atom::definitionRegular;
+ else if (strcmp(s, "tentative") == 0)
+ _def = Atom::definitionTentative;
+ else if (strcmp(s, "absolute") == 0)
+ _def = Atom::definitionAbsolute;
+ else
+ llvm::report_fatal_error("bad definition value");
+}
+
+void YAMLAtomState::setFixupKind(const char *s) {
+ if (strcmp(s, "pcrel32") == 0)
+ _ref.kind = 1;
+ else if (strcmp(s, "call32") == 0)
+ _ref.kind = 2;
+ else
+ llvm::report_fatal_error("bad fixup kind value");
+}
+
+void YAMLAtomState::setFixupOffset(const char *s) {
+ if ((s[0] == '0') && (s[1] == 'x'))
+ llvm::StringRef(s).getAsInteger(16, _ref.offsetInAtom);
+ else
+ llvm::StringRef(s).getAsInteger(10, _ref.offsetInAtom);
+}
+
+void YAMLAtomState::setFixupTarget(const char *s) {
+}
+
+void YAMLAtomState::addFixup(YAMLFile *f) {
+ f->_references.push_back(_ref);
+ // clear for next ref
+ _ref.target = NULL;
+ _ref.addend = 0;
+ _ref.offsetInAtom = 0;
+ _ref.kind = 0;
+ _ref.flags = 0;
+}
+
+llvm::error_code parseObjectText( llvm::MemoryBuffer *mb
+ , std::vector<File *> &result) {
+ std::vector<const YAML::Entry *> entries;
+ YAML::parse(mb, entries);
+
+ YAMLFile *file = NULL;
+ YAMLAtomState atomState;
+ 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 != NULL) {
+ if (haveAtom) {
+ atomState.makeAtom(file);
+ haveAtom = false;
+ }
+ 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, "name") == 0) {
+ atomState.setName(entry->value);
+ haveAtom = true;
+ } else if (strcmp(entry->key, "scope") == 0) {
+ atomState.setScope(entry->value);
+ haveAtom = true;
+ } else if (strcmp(entry->key, "type") == 0) {
+ atomState.setType(entry->value);
+ haveAtom = true;
+ } else if (strcmp(entry->key, "align2") == 0) {
+ atomState.setAlign2(entry->value);
+ haveAtom = true;
+ } else if (strcmp(entry->key, "definition") == 0) {
+ atomState.setDefinition(entry->value);
+ haveAtom = true;
+ } else if (strcmp(entry->key, "fixups") == 0) {
+ inFixups = true;
+ }
+ } else if (depthForFixups == entry->depth) {
+ if (entry->beginSequence) {
+ if (haveFixup) {
+ atomState.addFixup(file);
+ haveFixup = false;
+ }
+ }
+ if (strcmp(entry->key, "kind") == 0) {
+ atomState.setFixupKind(entry->value);
+ haveFixup = true;
+ } else if (strcmp(entry->key, "offset") == 0) {
+ atomState.setFixupOffset(entry->value);
+ haveFixup = true;
+ } else if (strcmp(entry->key, "target") == 0) {
+ atomState.setFixupTarget(entry->value);
+ haveFixup = true;
+ }
+ }
+ }
+ lastDepth = entry->depth;
+ }
+ if (haveAtom) {
+ atomState.makeAtom(file);
+ }
+
+ result.push_back(file);
+ return success;
+}
+} // namespace yaml
+} // namespace lld
OpenPOWER on IntegriCloud