summaryrefslogtreecommitdiffstats
path: root/lld/lib/ReaderWriter/Native/ReaderNative.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lld/lib/ReaderWriter/Native/ReaderNative.cpp')
-rw-r--r--lld/lib/ReaderWriter/Native/ReaderNative.cpp929
1 files changed, 929 insertions, 0 deletions
diff --git a/lld/lib/ReaderWriter/Native/ReaderNative.cpp b/lld/lib/ReaderWriter/Native/ReaderNative.cpp
new file mode 100644
index 00000000000..b617a4fb9ae
--- /dev/null
+++ b/lld/lib/ReaderWriter/Native/ReaderNative.cpp
@@ -0,0 +1,929 @@
+//===- lib/ReaderWriter/Native/ReaderNative.cpp ---------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/ReaderWriter/ReaderNative.h"
+
+#include "lld/Core/Atom.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/File.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include "NativeFileFormat.h"
+
+#include <vector>
+#include <memory>
+
+namespace lld {
+namespace native {
+
+// forward reference
+class File;
+
+//
+// An object of this class is instantied for each NativeDefinedAtomIvarsV1
+// struct in the NCS_DefinedAtomsV1 chunk.
+//
+class NativeDefinedAtomV1 : public DefinedAtom {
+public:
+ NativeDefinedAtomV1(const File& f,
+ const NativeDefinedAtomIvarsV1* ivarData)
+ : _file(&f), _ivarData(ivarData) { }
+
+ virtual const class lld::File& file() const;
+
+ virtual uint64_t ordinal() const;
+
+ virtual StringRef name() const;
+
+ virtual uint64_t size() const {
+ return _ivarData->contentSize;
+ }
+
+ virtual DefinedAtom::Scope scope() const {
+ return (DefinedAtom::Scope)(attributes().scope);
+ }
+
+ virtual DefinedAtom::Interposable interposable() const {
+ return (DefinedAtom::Interposable)(attributes().interposable);
+ }
+
+ virtual DefinedAtom::Merge merge() const {
+ return (DefinedAtom::Merge)(attributes().merge);
+ }
+
+ virtual DefinedAtom::ContentType contentType() const {
+ const NativeAtomAttributesV1& attr = attributes();
+ return (DefinedAtom::ContentType)(attr.contentType);
+ }
+
+ virtual DefinedAtom::Alignment alignment() const {
+ return DefinedAtom::Alignment(attributes().align2, attributes().alignModulus);
+ }
+
+ virtual DefinedAtom::SectionChoice sectionChoice() const {
+ return (DefinedAtom::SectionChoice)(attributes().sectionChoice);
+ }
+
+ virtual StringRef customSectionName() const;
+
+ virtual DefinedAtom::DeadStripKind deadStrip() const {
+ return (DefinedAtom::DeadStripKind)(attributes().deadStrip);
+ }
+
+ virtual DefinedAtom::ContentPermissions permissions() const {
+ return (DefinedAtom::ContentPermissions)(attributes().permissions);
+ }
+
+ virtual bool isThumb() const {
+ return false; //(attributes().thumb != 0);
+ }
+
+ virtual bool isAlias() const {
+ return (attributes().alias != 0);
+ }
+
+ virtual ArrayRef<uint8_t> rawContent() const;
+
+ virtual reference_iterator begin() const;
+
+ virtual reference_iterator end() const;
+
+ virtual const Reference* derefIterator(const void*) const;
+
+ virtual void incrementIterator(const void*& it) const;
+
+private:
+ const NativeAtomAttributesV1& attributes() const;
+
+ const File *_file;
+ const NativeDefinedAtomIvarsV1 *_ivarData;
+};
+
+
+
+//
+// An object of this class is instantied for each NativeUndefinedAtomIvarsV1
+// struct in the NCS_UndefinedAtomsV1 chunk.
+//
+class NativeUndefinedAtomV1 : public UndefinedAtom {
+public:
+ NativeUndefinedAtomV1(const File& f,
+ const NativeUndefinedAtomIvarsV1* ivarData)
+ : _file(&f), _ivarData(ivarData) { }
+
+ virtual const lld::File& file() const;
+ virtual StringRef name() const;
+
+ virtual CanBeNull canBeNull() const {
+ return (CanBeNull)(_ivarData->flags & 0x3);
+ }
+
+
+private:
+ const File *_file;
+ const NativeUndefinedAtomIvarsV1 *_ivarData;
+};
+
+
+//
+// An object of this class is instantied for each NativeUndefinedAtomIvarsV1
+// struct in the NCS_SharedLibraryAtomsV1 chunk.
+//
+class NativeSharedLibraryAtomV1 : public SharedLibraryAtom {
+public:
+ NativeSharedLibraryAtomV1(const File& f,
+ const NativeSharedLibraryAtomIvarsV1* ivarData)
+ : _file(&f), _ivarData(ivarData) { }
+
+ virtual const lld::File& file() const;
+ virtual StringRef name() const;
+ virtual StringRef loadName() const;
+
+ virtual bool canBeNullAtRuntime() const {
+ return (_ivarData->flags & 0x1);
+ }
+
+private:
+ const File *_file;
+ const NativeSharedLibraryAtomIvarsV1 *_ivarData;
+};
+
+
+//
+// An object of this class is instantied for each NativeAbsoluteAtomIvarsV1
+// struct in the NCS_AbsoluteAtomsV1 chunk.
+//
+class NativeAbsoluteAtomV1 : public AbsoluteAtom {
+public:
+ NativeAbsoluteAtomV1(const File& f,
+ const NativeAbsoluteAtomIvarsV1* ivarData)
+ : _file(&f), _ivarData(ivarData) { }
+
+ virtual const lld::File& file() const;
+ virtual StringRef name() const;
+
+ virtual uint64_t value() const {
+ return _ivarData->value;
+ }
+
+private:
+ const File *_file;
+ const NativeAbsoluteAtomIvarsV1 *_ivarData;
+};
+
+
+
+//
+// An object of this class is instantied for each NativeReferenceIvarsV1
+// struct in the NCS_ReferencesArrayV1 chunk.
+//
+class NativeReferenceV1 : public Reference {
+public:
+ NativeReferenceV1(const File& f,
+ const NativeReferenceIvarsV1* ivarData)
+ : _file(&f), _ivarData(ivarData) { }
+
+ virtual uint64_t offsetInAtom() const {
+ return _ivarData->offsetInAtom;
+ }
+
+ virtual Kind kind() const {
+ return _ivarData->kind;
+ }
+
+ virtual void setKind(Kind);
+ virtual const Atom* target() const;
+ virtual Addend addend() const;
+ virtual void setTarget(const Atom* newAtom);
+ virtual void setAddend(Addend a);
+
+private:
+ // Used in rare cases when Reference is modified,
+ // since ivar data is mapped read-only.
+ void cloneIvarData() {
+ // TODO: do nothing on second call
+ NativeReferenceIvarsV1* niv = reinterpret_cast<NativeReferenceIvarsV1*>
+ (operator new(sizeof(NativeReferenceIvarsV1),
+ std::nothrow));
+ memcpy(niv, _ivarData, sizeof(NativeReferenceIvarsV1));
+ }
+
+ const File *_file;
+ const NativeReferenceIvarsV1 *_ivarData;
+};
+
+
+
+//
+// lld::File object for native llvm object file
+//
+class File : public lld::File {
+public:
+
+ /// Instantiates a File object from a native object file. Ownership
+ /// of the MemoryBuffer is transfered to the resulting File object.
+ static error_code make(std::unique_ptr<llvm::MemoryBuffer> &mb,
+ StringRef path,
+ std::vector<std::unique_ptr<lld::File>> &result) {
+ const uint8_t* const base =
+ reinterpret_cast<const uint8_t*>(mb->getBufferStart());
+ const NativeFileHeader* const header =
+ reinterpret_cast<const NativeFileHeader*>(base);
+ const NativeChunk *const chunks =
+ reinterpret_cast<const NativeChunk*>(base + sizeof(NativeFileHeader));
+ // make sure magic matches
+ if ( memcmp(header->magic, NATIVE_FILE_HEADER_MAGIC, 16) != 0 )
+ return make_error_code(native_reader_error::unknown_file_format);
+
+ // make sure mapped file contains all needed data
+ const size_t fileSize = mb->getBufferSize();
+ if ( header->fileSize > fileSize )
+ return make_error_code(native_reader_error::file_too_short);
+
+ DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
+ << " Native File Header:"
+ << " fileSize=" << header->fileSize
+ << " chunkCount=" << header->chunkCount
+ << "\n");
+
+ // instantiate NativeFile object and add values to it as found
+ std::unique_ptr<File> file(new File(std::move(mb), path));
+
+ // process each chunk
+ for(uint32_t i=0; i < header->chunkCount; ++i) {
+ error_code ec;
+ const NativeChunk* chunk = &chunks[i];
+ // sanity check chunk is within file
+ if ( chunk->fileOffset > fileSize )
+ return make_error_code(native_reader_error::file_malformed);
+ if ( (chunk->fileOffset + chunk->fileSize) > fileSize)
+ return make_error_code(native_reader_error::file_malformed);
+ // process chunk, based on signature
+ switch ( chunk->signature ) {
+ case NCS_DefinedAtomsV1:
+ ec = file->processDefinedAtomsV1(base, chunk);
+ break;
+ case NCS_AttributesArrayV1:
+ ec = file->processAttributesV1(base, chunk);
+ break;
+ case NCS_UndefinedAtomsV1:
+ ec = file->processUndefinedAtomsV1(base, chunk);
+ break;
+ case NCS_SharedLibraryAtomsV1:
+ ec = file->processSharedLibraryAtomsV1(base, chunk);
+ break;
+ case NCS_AbsoluteAtomsV1:
+ ec = file->processAbsoluteAtomsV1(base, chunk);
+ break;
+ case NCS_ReferencesArrayV1:
+ ec = file->processReferencesV1(base, chunk);
+ break;
+ case NCS_TargetsTable:
+ ec = file->processTargetsTable(base, chunk);
+ break;
+ case NCS_AddendsTable:
+ ec = file->processAddendsTable(base, chunk);
+ break;
+ case NCS_Content:
+ ec = file->processContent(base, chunk);
+ break;
+ case NCS_Strings:
+ ec = file->processStrings(base, chunk);
+ break;
+ default:
+ return make_error_code(native_reader_error::unknown_chunk_type);
+ }
+ if ( ec ) {
+ return ec;
+ }
+ }
+ // TO DO: validate enough chunks were used
+
+ DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
+ << " ReaderNative DefinedAtoms:\n");
+ for (const DefinedAtom *a : file->defined() ) {
+ DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
+ << llvm::format(" 0x%09lX", a)
+ << ", name=" << a->name()
+ << ", size=" << a->size()
+ << "\n");
+ for (const Reference *r : *a ) {
+ DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
+ << " offset="
+ << llvm::format("0x%03X", r->offsetInAtom())
+ << ", kind=" << r->kind()
+ << ", target=" << r->target()
+ << "\n");
+ }
+ }
+
+ result.push_back(std::move(file));
+ return make_error_code(native_reader_error::success);
+ }
+
+ virtual ~File() {
+ // _buffer is automatically deleted because of OwningPtr<>
+
+ // All other ivar pointers are pointers into the MemoryBuffer, except
+ // the _definedAtoms array which was allocated to contain an array
+ // of Atom objects. The atoms have empty destructors, so it is ok
+ // to just delete the memory.
+ delete _definedAtoms._arrayStart;
+ delete _undefinedAtoms._arrayStart;
+ delete _sharedLibraryAtoms._arrayStart;
+ delete _absoluteAtoms._arrayStart;
+ delete _references.arrayStart;
+ delete _targetsTable;
+ }
+
+ 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 native .o files");
+ }
+
+private:
+ friend class NativeDefinedAtomV1;
+ friend class NativeUndefinedAtomV1;
+ friend class NativeSharedLibraryAtomV1;
+ friend class NativeAbsoluteAtomV1;
+ friend class NativeReferenceV1;
+
+ // instantiate array of DefinedAtoms from v1 ivar data in file
+ error_code processDefinedAtomsV1(const uint8_t *base,
+ const NativeChunk *chunk) {
+ const size_t atomSize = sizeof(NativeDefinedAtomV1);
+ size_t atomsArraySize = chunk->elementCount * atomSize;
+ uint8_t* atomsStart = reinterpret_cast<uint8_t*>
+ (operator new(atomsArraySize, std::nothrow));
+ if (atomsStart == nullptr)
+ return make_error_code(native_reader_error::memory_error);
+ const size_t ivarElementSize = chunk->fileSize
+ / chunk->elementCount;
+ if ( ivarElementSize != sizeof(NativeDefinedAtomIvarsV1) )
+ return make_error_code(native_reader_error::file_malformed);
+ uint8_t* atomsEnd = atomsStart + atomsArraySize;
+ const NativeDefinedAtomIvarsV1* ivarData =
+ reinterpret_cast<const NativeDefinedAtomIvarsV1*>
+ (base + chunk->fileOffset);
+ for(uint8_t* s = atomsStart; s != atomsEnd; s += atomSize) {
+ NativeDefinedAtomV1* atomAllocSpace =
+ reinterpret_cast<NativeDefinedAtomV1*>(s);
+ new (atomAllocSpace) NativeDefinedAtomV1(*this, ivarData);
+ ++ivarData;
+ }
+ this->_definedAtoms._arrayStart = atomsStart;
+ this->_definedAtoms._arrayEnd = atomsEnd;
+ this->_definedAtoms._elementSize = atomSize;
+ this->_definedAtoms._elementCount = chunk->elementCount;
+ DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
+ << " chunk DefinedAtomsV1: "
+ << " count=" << chunk->elementCount
+ << " chunkSize=" << chunk->fileSize
+ << "\n");
+ return make_error_code(native_reader_error::success);
+ }
+
+
+
+ // set up pointers to attributes array
+ error_code processAttributesV1(const uint8_t *base,
+ const NativeChunk *chunk) {
+ this->_attributes = base + chunk->fileOffset;
+ this->_attributesMaxOffset = chunk->fileSize;
+ DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
+ << " chunk AttributesV1: "
+ << " count=" << chunk->elementCount
+ << " chunkSize=" << chunk->fileSize
+ << "\n");
+ return make_error_code(native_reader_error::success);
+ }
+
+ // instantiate array of UndefinedAtoms from v1 ivar data in file
+ error_code processUndefinedAtomsV1(const uint8_t *base,
+ const NativeChunk *chunk) {
+ const size_t atomSize = sizeof(NativeUndefinedAtomV1);
+ size_t atomsArraySize = chunk->elementCount * atomSize;
+ uint8_t* atomsStart = reinterpret_cast<uint8_t*>
+ (operator new(atomsArraySize, std::nothrow));
+ if (atomsStart == nullptr)
+ return make_error_code(native_reader_error::memory_error);
+ const size_t ivarElementSize = chunk->fileSize
+ / chunk->elementCount;
+ if ( ivarElementSize != sizeof(NativeUndefinedAtomIvarsV1) )
+ return make_error_code(native_reader_error::file_malformed);
+ uint8_t* atomsEnd = atomsStart + atomsArraySize;
+ const NativeUndefinedAtomIvarsV1* ivarData =
+ reinterpret_cast<const NativeUndefinedAtomIvarsV1*>
+ (base + chunk->fileOffset);
+ for(uint8_t* s = atomsStart; s != atomsEnd; s += atomSize) {
+ NativeUndefinedAtomV1* atomAllocSpace =
+ reinterpret_cast<NativeUndefinedAtomV1*>(s);
+ new (atomAllocSpace) NativeUndefinedAtomV1(*this, ivarData);
+ ++ivarData;
+ }
+ this->_undefinedAtoms._arrayStart = atomsStart;
+ this->_undefinedAtoms._arrayEnd = atomsEnd;
+ this->_undefinedAtoms._elementSize = atomSize;
+ this->_undefinedAtoms._elementCount = chunk->elementCount;
+ DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
+ << " chunk UndefinedAtomsV1:"
+ << " count=" << chunk->elementCount
+ << " chunkSize=" << chunk->fileSize
+ << "\n");
+ return make_error_code(native_reader_error::success);
+ }
+
+
+ // instantiate array of ShareLibraryAtoms from v1 ivar data in file
+ error_code processSharedLibraryAtomsV1(const uint8_t *base,
+ const NativeChunk *chunk) {
+ const size_t atomSize = sizeof(NativeSharedLibraryAtomV1);
+ size_t atomsArraySize = chunk->elementCount * atomSize;
+ uint8_t* atomsStart = reinterpret_cast<uint8_t*>
+ (operator new(atomsArraySize, std::nothrow));
+ if (atomsStart == nullptr)
+ return make_error_code(native_reader_error::memory_error);
+ const size_t ivarElementSize = chunk->fileSize
+ / chunk->elementCount;
+ if ( ivarElementSize != sizeof(NativeSharedLibraryAtomIvarsV1) )
+ return make_error_code(native_reader_error::file_malformed);
+ uint8_t* atomsEnd = atomsStart + atomsArraySize;
+ const NativeSharedLibraryAtomIvarsV1* ivarData =
+ reinterpret_cast<const NativeSharedLibraryAtomIvarsV1*>
+ (base + chunk->fileOffset);
+ for(uint8_t* s = atomsStart; s != atomsEnd; s += atomSize) {
+ NativeSharedLibraryAtomV1* atomAllocSpace =
+ reinterpret_cast<NativeSharedLibraryAtomV1*>(s);
+ new (atomAllocSpace) NativeSharedLibraryAtomV1(*this, ivarData);
+ ++ivarData;
+ }
+ this->_sharedLibraryAtoms._arrayStart = atomsStart;
+ this->_sharedLibraryAtoms._arrayEnd = atomsEnd;
+ this->_sharedLibraryAtoms._elementSize = atomSize;
+ this->_sharedLibraryAtoms._elementCount = chunk->elementCount;
+ DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
+ << " chunk SharedLibraryAtomsV1:"
+ << " count=" << chunk->elementCount
+ << " chunkSize=" << chunk->fileSize
+ << "\n");
+ return make_error_code(native_reader_error::success);
+ }
+
+
+ // instantiate array of AbsoluteAtoms from v1 ivar data in file
+ error_code processAbsoluteAtomsV1(const uint8_t *base,
+ const NativeChunk *chunk) {
+ const size_t atomSize = sizeof(NativeAbsoluteAtomV1);
+ size_t atomsArraySize = chunk->elementCount * atomSize;
+ uint8_t* atomsStart = reinterpret_cast<uint8_t*>
+ (operator new(atomsArraySize, std::nothrow));
+ if (atomsStart == nullptr)
+ return make_error_code(native_reader_error::memory_error);
+ const size_t ivarElementSize = chunk->fileSize
+ / chunk->elementCount;
+ if ( ivarElementSize != sizeof(NativeAbsoluteAtomIvarsV1) )
+ return make_error_code(native_reader_error::file_malformed);
+ uint8_t* atomsEnd = atomsStart + atomsArraySize;
+ const NativeAbsoluteAtomIvarsV1* ivarData =
+ reinterpret_cast<const NativeAbsoluteAtomIvarsV1*>
+ (base + chunk->fileOffset);
+ for(uint8_t* s = atomsStart; s != atomsEnd; s += atomSize) {
+ NativeAbsoluteAtomV1* atomAllocSpace =
+ reinterpret_cast<NativeAbsoluteAtomV1*>(s);
+ new (atomAllocSpace) NativeAbsoluteAtomV1(*this, ivarData);
+ ++ivarData;
+ }
+ this->_absoluteAtoms._arrayStart = atomsStart;
+ this->_absoluteAtoms._arrayEnd = atomsEnd;
+ this->_absoluteAtoms._elementSize = atomSize;
+ this->_absoluteAtoms._elementCount = chunk->elementCount;
+ DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
+ << " chunk AbsoluteAtomsV1: "
+ << " count=" << chunk->elementCount
+ << " chunkSize=" << chunk->fileSize
+ << "\n");
+ return make_error_code(native_reader_error::success);
+ }
+
+
+
+
+ // instantiate array of Referemces from v1 ivar data in file
+ error_code processReferencesV1(const uint8_t *base,
+ const NativeChunk *chunk) {
+ if ( chunk->elementCount == 0 )
+ return make_error_code(native_reader_error::success);
+ const size_t refSize = sizeof(NativeReferenceV1);
+ size_t refsArraySize = chunk->elementCount * refSize;
+ uint8_t* refsStart = reinterpret_cast<uint8_t*>
+ (operator new(refsArraySize, std::nothrow));
+ if (refsStart == nullptr)
+ return make_error_code(native_reader_error::memory_error);
+ const size_t ivarElementSize = chunk->fileSize
+ / chunk->elementCount;
+ if ( ivarElementSize != sizeof(NativeReferenceIvarsV1) )
+ return make_error_code(native_reader_error::file_malformed);
+ uint8_t* refsEnd = refsStart + refsArraySize;
+ const NativeReferenceIvarsV1* ivarData =
+ reinterpret_cast<const NativeReferenceIvarsV1*>
+ (base + chunk->fileOffset);
+ for(uint8_t* s = refsStart; s != refsEnd; s += refSize) {
+ NativeReferenceV1* atomAllocSpace =
+ reinterpret_cast<NativeReferenceV1*>(s);
+ new (atomAllocSpace) NativeReferenceV1(*this, ivarData);
+ ++ivarData;
+ }
+ this->_references.arrayStart = refsStart;
+ this->_references.arrayEnd = refsEnd;
+ this->_references.elementSize = refSize;
+ this->_references.elementCount = chunk->elementCount;
+ DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
+ << " chunk ReferencesV1: "
+ << " count=" << chunk->elementCount
+ << " chunkSize=" << chunk->fileSize
+ << "\n");
+ return make_error_code(native_reader_error::success);
+ }
+
+ // set up pointers to target table
+ error_code processTargetsTable(const uint8_t *base,
+ const NativeChunk *chunk) {
+ const uint32_t* targetIndexes = reinterpret_cast<const uint32_t*>
+ (base + chunk->fileOffset);
+ this->_targetsTableCount = chunk->elementCount;
+ this->_targetsTable = new const Atom*[chunk->elementCount];
+ for (uint32_t i=0; i < chunk->elementCount; ++i) {
+ const uint32_t index = targetIndexes[i];
+ if ( index < _definedAtoms._elementCount ) {
+ const uint8_t* p = _definedAtoms._arrayStart
+ + index * _definedAtoms._elementSize;
+ this->_targetsTable[i] = reinterpret_cast<const DefinedAtom*>(p);
+ continue;
+ }
+ const uint32_t undefIndex = index - _definedAtoms._elementCount;
+ if ( undefIndex < _undefinedAtoms._elementCount ) {
+ const uint8_t* p = _undefinedAtoms._arrayStart
+ + undefIndex * _undefinedAtoms._elementSize;
+ this->_targetsTable[i] = reinterpret_cast<const UndefinedAtom*>(p);
+ continue;
+ }
+ const uint32_t slIndex = index - _definedAtoms._elementCount
+ - _undefinedAtoms._elementCount;
+ if ( slIndex < _sharedLibraryAtoms._elementCount ) {
+ const uint8_t* p = _sharedLibraryAtoms._arrayStart
+ + slIndex * _sharedLibraryAtoms._elementSize;
+ this->_targetsTable[i] = reinterpret_cast<const SharedLibraryAtom*>(p);
+ continue;
+ }
+ const uint32_t abIndex = index - _definedAtoms._elementCount
+ - _undefinedAtoms._elementCount
+ - _sharedLibraryAtoms._elementCount;
+ if ( abIndex < _absoluteAtoms._elementCount ) {
+ const uint8_t* p = _absoluteAtoms._arrayStart
+ + slIndex * _absoluteAtoms._elementSize;
+ this->_targetsTable[i] = reinterpret_cast<const AbsoluteAtom*>(p);
+ continue;
+ }
+ return make_error_code(native_reader_error::file_malformed);
+ }
+ DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
+ << " chunk Targets Table: "
+ << " count=" << chunk->elementCount
+ << " chunkSize=" << chunk->fileSize
+ << "\n");
+ return make_error_code(native_reader_error::success);
+ }
+
+
+ // set up pointers to addend pool in file
+ error_code processAddendsTable(const uint8_t *base,
+ const NativeChunk *chunk) {
+ this->_addends = reinterpret_cast<const Reference::Addend*>
+ (base + chunk->fileOffset);
+ this->_addendsMaxIndex = chunk->elementCount;
+ DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
+ << " chunk Addends: "
+ << " count=" << chunk->elementCount
+ << " chunkSize=" << chunk->fileSize
+ << "\n");
+ return make_error_code(native_reader_error::success);
+ }
+
+ // set up pointers to string pool in file
+ error_code processStrings(const uint8_t *base,
+ const NativeChunk *chunk) {
+ this->_strings = reinterpret_cast<const char*>(base + chunk->fileOffset);
+ this->_stringsMaxOffset = chunk->fileSize;
+ DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
+ << " chunk Strings: "
+ << " chunkSize=" << chunk->fileSize
+ << "\n");
+ return make_error_code(native_reader_error::success);
+ }
+
+ // set up pointers to content area in file
+ error_code processContent(const uint8_t *base,
+ const NativeChunk *chunk) {
+ this->_contentStart = base + chunk->fileOffset;
+ this->_contentEnd = base + chunk->fileOffset + chunk->fileSize;
+ DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
+ << " chunk content: "
+ << " chunkSize=" << chunk->fileSize
+ << "\n");
+ return make_error_code(native_reader_error::success);
+ }
+
+ StringRef string(uint32_t offset) const {
+ assert(offset < _stringsMaxOffset);
+ return StringRef(&_strings[offset]);
+ }
+
+ Reference::Addend addend(uint32_t index) const {
+ if ( index == 0 )
+ return 0; // addend index zero is used to mean "no addend"
+ assert(index <= _addendsMaxIndex);
+ return _addends[index-1]; // one-based indexing
+ }
+
+ const NativeAtomAttributesV1& attribute(uint32_t off) const {
+ assert(off < _attributesMaxOffset);
+ return *reinterpret_cast<const NativeAtomAttributesV1*>(_attributes + off);
+ }
+
+ const uint8_t* content(uint32_t offset, uint32_t size) const {
+ const uint8_t* result = _contentStart + offset;
+ assert((result+size) <= _contentEnd);
+ return result;
+ }
+
+ const Reference* referenceByIndex(uintptr_t index) const {
+ assert(index < _references.elementCount);
+ const uint8_t* p = _references.arrayStart + index * _references.elementSize;
+ return reinterpret_cast<const NativeReferenceV1*>(p);
+ }
+
+ const Atom* target(uint16_t index) const {
+ if ( index == NativeReferenceIvarsV1::noTarget )
+ return nullptr;
+ assert(index < _targetsTableCount);
+ return _targetsTable[index];
+ }
+
+ void setTarget(uint16_t index, const Atom* newAtom) const {
+ assert(index != NativeReferenceIvarsV1::noTarget);
+ assert(index > _targetsTableCount);
+ _targetsTable[index] = newAtom;
+ }
+
+
+
+ // private constructor, only called by make()
+ File(std::unique_ptr<llvm::MemoryBuffer> mb, StringRef path) :
+ lld::File(path),
+ _buffer(std::move(mb)), // Reader now takes ownership of buffer
+ _header(nullptr),
+ _targetsTable(nullptr),
+ _targetsTableCount(0),
+ _strings(nullptr),
+ _stringsMaxOffset(0),
+ _addends(nullptr),
+ _addendsMaxIndex(0),
+ _contentStart(nullptr),
+ _contentEnd(nullptr)
+ {
+ _header = reinterpret_cast<const NativeFileHeader*>
+ (_buffer->getBufferStart());
+ }
+
+ template <typename T>
+ class AtomArray : public File::atom_collection<T> {
+ public:
+ AtomArray() : _arrayStart(nullptr), _arrayEnd(nullptr),
+ _elementSize(0), _elementCount(0) { }
+
+ virtual atom_iterator<T> begin() const {
+ return atom_iterator<T>(*this, reinterpret_cast<const void*>(_arrayStart));
+ }
+ virtual atom_iterator<T> end() const{
+ return atom_iterator<T>(*this, reinterpret_cast<const void*>(_arrayEnd));
+ }
+ virtual const T* deref(const void* it) const {
+ return reinterpret_cast<const T*>(it);
+ }
+ virtual void next(const void*& it) const {
+ const uint8_t* p = reinterpret_cast<const uint8_t*>(it);
+ p += _elementSize;
+ it = reinterpret_cast<const void*>(p);
+ }
+ const uint8_t* _arrayStart;
+ const uint8_t* _arrayEnd;
+ uint32_t _elementSize;
+ uint32_t _elementCount;
+ };
+
+ struct IvarArray {
+ IvarArray() :
+ arrayStart(nullptr),
+ arrayEnd(nullptr),
+ elementSize(0),
+ elementCount(0) { }
+
+ const uint8_t* arrayStart;
+ const uint8_t* arrayEnd;
+ uint32_t elementSize;
+ uint32_t elementCount;
+ };
+
+
+ std::unique_ptr<llvm::MemoryBuffer> _buffer;
+ const NativeFileHeader* _header;
+ AtomArray<DefinedAtom> _definedAtoms;
+ AtomArray<UndefinedAtom> _undefinedAtoms;
+ AtomArray<SharedLibraryAtom> _sharedLibraryAtoms;
+ AtomArray<AbsoluteAtom> _absoluteAtoms;
+ const uint8_t* _attributes;
+ uint32_t _attributesMaxOffset;
+ IvarArray _references;
+ const Atom** _targetsTable;
+ uint32_t _targetsTableCount;
+ const char* _strings;
+ uint32_t _stringsMaxOffset;
+ const Reference::Addend* _addends;
+ uint32_t _addendsMaxIndex;
+ const uint8_t* _contentStart;
+ const uint8_t* _contentEnd;
+};
+
+
+inline const class lld::File& NativeDefinedAtomV1::file() const {
+ return *_file;
+}
+
+inline uint64_t NativeDefinedAtomV1:: ordinal() const {
+ const uint8_t* p = reinterpret_cast<const uint8_t*>(_ivarData);
+ return p - _file->_definedAtoms._arrayStart;
+}
+
+inline StringRef NativeDefinedAtomV1::name() const {
+ return _file->string(_ivarData->nameOffset);
+}
+
+inline const NativeAtomAttributesV1& NativeDefinedAtomV1::attributes() const {
+ return _file->attribute(_ivarData->attributesOffset);
+}
+
+inline ArrayRef<uint8_t> NativeDefinedAtomV1::rawContent() const {
+ if ( this->contentType() == DefinedAtom::typeZeroFill )
+ return ArrayRef<uint8_t>();
+ const uint8_t* p = _file->content(_ivarData->contentOffset,
+ _ivarData->contentSize);
+ return ArrayRef<uint8_t>(p, _ivarData->contentSize);
+}
+
+inline StringRef NativeDefinedAtomV1::customSectionName() const {
+ uint32_t offset = attributes().sectionNameOffset;
+ return _file->string(offset);
+}
+
+DefinedAtom::reference_iterator NativeDefinedAtomV1::begin() const {
+ uintptr_t index = _ivarData->referencesStartIndex;
+ const void* it = reinterpret_cast<const void*>(index);
+ return reference_iterator(*this, it);
+}
+
+DefinedAtom::reference_iterator NativeDefinedAtomV1::end() const {
+ uintptr_t index = _ivarData->referencesStartIndex+_ivarData->referencesCount;
+ const void* it = reinterpret_cast<const void*>(index);
+ return reference_iterator(*this, it);
+}
+
+const Reference* NativeDefinedAtomV1::derefIterator(const void* it) const {
+ uintptr_t index = reinterpret_cast<uintptr_t>(it);
+ return _file->referenceByIndex(index);
+}
+
+void NativeDefinedAtomV1::incrementIterator(const void*& it) const {
+ uintptr_t index = reinterpret_cast<uintptr_t>(it);
+ ++index;
+ it = reinterpret_cast<const void*>(index);
+}
+
+inline const class lld::File& NativeUndefinedAtomV1::file() const {
+ return *_file;
+}
+
+inline StringRef NativeUndefinedAtomV1::name() const {
+ return _file->string(_ivarData->nameOffset);
+}
+
+
+
+
+inline const class lld::File& NativeSharedLibraryAtomV1::file() const {
+ return *_file;
+}
+
+inline StringRef NativeSharedLibraryAtomV1::name() const {
+ return _file->string(_ivarData->nameOffset);
+}
+
+inline StringRef NativeSharedLibraryAtomV1::loadName() const {
+ return _file->string(_ivarData->loadNameOffset);
+}
+
+
+
+inline const class lld::File& NativeAbsoluteAtomV1::file() const {
+ return *_file;
+}
+
+inline StringRef NativeAbsoluteAtomV1::name() const {
+ return _file->string(_ivarData->nameOffset);
+}
+
+
+inline const Atom* NativeReferenceV1::target() const {
+ return _file->target(_ivarData->targetIndex);
+}
+
+inline Reference::Addend NativeReferenceV1::addend() const {
+ return _file->addend(_ivarData->addendIndex);
+}
+
+inline void NativeReferenceV1::setKind(Kind k) {
+ this->cloneIvarData();
+ const_cast<NativeReferenceIvarsV1*>(_ivarData)->kind = k;
+}
+
+inline void NativeReferenceV1::setTarget(const Atom* newAtom) {
+ return _file->setTarget(_ivarData->targetIndex, newAtom);
+}
+
+inline void NativeReferenceV1::setAddend(Addend a) {
+ // Do nothing if addend value is not being changed.
+ if ( this->addend() == a )
+ return;
+ assert(0 && "setAddend() not supported");
+}
+
+
+class Reader : public lld::Reader {
+public:
+ Reader(const ReaderOptionsNative &options) : _options(options) {
+ }
+
+ virtual error_code parseFile(std::unique_ptr<MemoryBuffer> mb,
+ std::vector<std::unique_ptr<lld::File>> &result) {
+ return File::make(mb, mb->getBufferIdentifier(), result);
+ }
+
+private:
+ const ReaderOptionsNative &_options;
+};
+
+
+
+} // namespace native
+
+Reader* createReaderNative(const ReaderOptionsNative &options) {
+ return new lld::native::Reader(options);
+}
+
+ReaderOptionsNative::ReaderOptionsNative() {
+}
+
+ReaderOptionsNative::~ReaderOptionsNative() {
+}
+
+
+} // namespace lld
+
+
+
+
OpenPOWER on IntegriCloud