diff options
Diffstat (limited to 'lld/lib/ReaderWriter/Native/ReaderNative.cpp')
| -rw-r--r-- | lld/lib/ReaderWriter/Native/ReaderNative.cpp | 929 |
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 + + + + |

