Files
clang-p2996/lld/lib/ReaderWriter/Native/ReaderNative.cpp
Rui Ueyama d50ed14d92 Remove dead code.
isAlias always returns false and no one is using it. It was
originally added Atom to query if an atom is an alias for another
atom, assuming that alias atoms are different from normal atoms.

We now support atom aliasing, but the way that's implemented is
in a different way than what isAlias assumed. An alias atom is
just a regular defined atom with no content, and it has a layout-
before edge to alias-to atom so that they are layed out at the
same location in the result. So this is dead code, and it doesn't
make much sense to keep it.

llvm-svn: 207884
2014-05-02 23:43:59 +00:00

1022 lines
37 KiB
C++

//===- 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 "NativeFileFormat.h"
#include "lld/ReaderWriter/Reader.h"
#include "lld/ReaderWriter/Simple.h"
#include "lld/Core/Atom.h"
#include "lld/Core/Error.h"
#include "lld/Core/File.h"
#include "llvm/ADT/ArrayRef.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 <memory>
#include <vector>
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) { }
const lld::File& file() const override;
uint64_t ordinal() const override;
StringRef name() const override;
uint64_t size() const override {
return _ivarData->contentSize;
}
DefinedAtom::Scope scope() const override {
return (DefinedAtom::Scope)(attributes().scope);
}
DefinedAtom::Interposable interposable() const override {
return (DefinedAtom::Interposable)(attributes().interposable);
}
DefinedAtom::Merge merge() const override {
return (DefinedAtom::Merge)(attributes().merge);
}
DefinedAtom::ContentType contentType() const override {
const NativeAtomAttributesV1& attr = attributes();
return (DefinedAtom::ContentType)(attr.contentType);
}
DefinedAtom::Alignment alignment() const override {
return DefinedAtom::Alignment(attributes().align2, attributes().alignModulus);
}
DefinedAtom::SectionChoice sectionChoice() const override {
return (DefinedAtom::SectionChoice)(
attributes().sectionChoiceAndPosition >> 4);
}
StringRef customSectionName() const override;
SectionPosition sectionPosition() const override {
return (DefinedAtom::SectionPosition)(
attributes().sectionChoiceAndPosition & 0xF);
}
DefinedAtom::DeadStripKind deadStrip() const override {
return (DefinedAtom::DeadStripKind)(attributes().deadStrip);
}
DynamicExport dynamicExport() const override {
return (DynamicExport)attributes().dynamicExport;
}
DefinedAtom::ContentPermissions permissions() const override {
return (DefinedAtom::ContentPermissions)(attributes().permissions);
}
ArrayRef<uint8_t> rawContent() const override;
reference_iterator begin() const override;
reference_iterator end() const override;
const Reference* derefIterator(const void*) const override;
void incrementIterator(const void*& it) const override;
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) { }
const lld::File& file() const override;
StringRef name() const override;
CanBeNull canBeNull() const override {
return (CanBeNull)(_ivarData->flags & 0x3);
}
const UndefinedAtom *fallback() const override;
private:
const File *_file;
const NativeUndefinedAtomIvarsV1 *_ivarData;
mutable std::unique_ptr<const SimpleUndefinedAtom> _fallback;
};
//
// 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) { }
const lld::File& file() const override;
StringRef name() const override;
StringRef loadName() const override;
bool canBeNullAtRuntime() const override {
return (_ivarData->flags & 0x1);
}
Type type() const override {
return (Type)_ivarData->type;
}
uint64_t size() const override {
return _ivarData->size;
}
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) { }
const lld::File& file() const override;
StringRef name() const override;
Scope scope() const override {
const NativeAtomAttributesV1& attr = absAttributes();
return (Scope)(attr.scope);
}
uint64_t value() const override {
return _ivarData->value;
}
private:
const NativeAtomAttributesV1& absAttributes() const;
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)
: Reference((KindNamespace)ivarData->kindNamespace,
(KindArch)ivarData->kindArch, ivarData->kindValue),
_file(&f), _ivarData(ivarData) {}
uint64_t offsetInAtom() const override {
return _ivarData->offsetInAtom;
}
const Atom* target() const override;
Addend addend() const override;
void setTarget(const Atom* newAtom) override;
void setAddend(Addend a) override;
private:
const File *_file;
const NativeReferenceIvarsV1 *_ivarData;
};
//
// An object of this class is instantied for each NativeReferenceIvarsV1
// struct in the NCS_ReferencesArrayV1 chunk.
//
class NativeReferenceV2 : public Reference {
public:
NativeReferenceV2(const File &f, const NativeReferenceIvarsV2 *ivarData)
: Reference((KindNamespace)ivarData->kindNamespace,
(KindArch)ivarData->kindArch, ivarData->kindValue),
_file(&f), _ivarData(ivarData) {}
uint64_t offsetInAtom() const override {
return _ivarData->offsetInAtom;
}
const Atom* target() const override;
Addend addend() const override;
void setTarget(const Atom* newAtom) override;
void setAddend(Addend a) override;
private:
const File *_file;
const NativeReferenceIvarsV2 *_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 transferred to the resulting File object.
static error_code make(std::unique_ptr<MemoryBuffer> mb,
std::vector<std::unique_ptr<lld::File>> &result) {
const uint8_t *const base =
reinterpret_cast<const uint8_t *>(mb->getBufferStart());
StringRef path(mb->getBufferIdentifier());
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,
sizeof(header->magic)) != 0)
return make_error_code(NativeReaderError::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(NativeReaderError::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(NativeReaderError::file_malformed);
if ( (chunk->fileOffset + chunk->fileSize) > fileSize)
return make_error_code(NativeReaderError::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_AbsoluteAttributesV1:
ec = file->processAbsoluteAttributesV1(base, chunk);
break;
case NCS_ReferencesArrayV1:
ec = file->processReferencesV1(base, chunk);
break;
case NCS_ReferencesArrayV2:
ec = file->processReferencesV2(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(NativeReaderError::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()) {
llvm::dbgs() << llvm::format(" 0x%09lX", a)
<< ", name=" << a->name()
<< ", size=" << a->size() << "\n";
for (const Reference *r : *a) {
llvm::dbgs() << " offset="
<< llvm::format("0x%03X", r->offsetInAtom())
<< ", kind=" << r->kindValue()
<< ", target=" << r->target() << "\n";
}
}
});
result.push_back(std::move(file));
return make_error_code(NativeReaderError::success);
}
virtual ~File() {
// _buffer is automatically deleted because of std::unique_ptr<>
// 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 _referencesV1.arrayStart;
delete _referencesV2.arrayStart;
delete [] _targetsTable;
}
const atom_collection<DefinedAtom>& defined() const override {
return _definedAtoms;
}
const atom_collection<UndefinedAtom>& undefined() const override {
return _undefinedAtoms;
}
const atom_collection<SharedLibraryAtom>& sharedLibrary() const override {
return _sharedLibraryAtoms;
}
const atom_collection<AbsoluteAtom> &absolute() const override {
return _absoluteAtoms;
}
private:
friend NativeDefinedAtomV1;
friend NativeUndefinedAtomV1;
friend NativeSharedLibraryAtomV1;
friend NativeAbsoluteAtomV1;
friend NativeReferenceV1;
friend NativeReferenceV2;
// 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(NativeReaderError::memory_error);
const size_t ivarElementSize = chunk->fileSize
/ chunk->elementCount;
if ( ivarElementSize != sizeof(NativeDefinedAtomIvarsV1) )
return make_error_code(NativeReaderError::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(NativeReaderError::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(NativeReaderError::success);
}
// set up pointers to attributes array
error_code processAbsoluteAttributesV1(const uint8_t *base,
const NativeChunk *chunk) {
this->_absAttributes = base + chunk->fileOffset;
this->_absAbsoluteMaxOffset = chunk->fileSize;
DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
<< " chunk AbsoluteAttributesV1: "
<< " count=" << chunk->elementCount
<< " chunkSize=" << chunk->fileSize
<< "\n");
return make_error_code(NativeReaderError::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(NativeReaderError::memory_error);
const size_t ivarElementSize = chunk->fileSize
/ chunk->elementCount;
if ( ivarElementSize != sizeof(NativeUndefinedAtomIvarsV1) )
return make_error_code(NativeReaderError::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(NativeReaderError::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(NativeReaderError::memory_error);
const size_t ivarElementSize = chunk->fileSize
/ chunk->elementCount;
if ( ivarElementSize != sizeof(NativeSharedLibraryAtomIvarsV1) )
return make_error_code(NativeReaderError::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(NativeReaderError::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(NativeReaderError::memory_error);
const size_t ivarElementSize = chunk->fileSize
/ chunk->elementCount;
if ( ivarElementSize != sizeof(NativeAbsoluteAtomIvarsV1) )
return make_error_code(NativeReaderError::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(NativeReaderError::success);
}
template<class T, class U>
error_code processReferences(const uint8_t *base, const NativeChunk *chunk,
uint8_t *&refsStart, uint8_t *&refsEnd) const {
if (chunk->elementCount == 0)
return make_error_code(NativeReaderError::success);
size_t refsArraySize = chunk->elementCount * sizeof(T);
refsStart = reinterpret_cast<uint8_t *>(
operator new(refsArraySize, std::nothrow));
if (refsStart == nullptr)
return make_error_code(NativeReaderError::memory_error);
const size_t ivarElementSize = chunk->fileSize / chunk->elementCount;
if (ivarElementSize != sizeof(U))
return make_error_code(NativeReaderError::file_malformed);
refsEnd = refsStart + refsArraySize;
const U* ivarData = reinterpret_cast<const U *>(base + chunk->fileOffset);
for (uint8_t *s = refsStart; s != refsEnd; s += sizeof(T), ++ivarData) {
T *atomAllocSpace = reinterpret_cast<T *>(s);
new (atomAllocSpace) T(*this, ivarData);
}
return make_error_code(NativeReaderError::success);
}
// instantiate array of References from v1 ivar data in file
error_code processReferencesV1(const uint8_t *base,
const NativeChunk *chunk) {
uint8_t *refsStart, *refsEnd;
if (error_code ec
= processReferences<NativeReferenceV1, NativeReferenceIvarsV1>(
base, chunk, refsStart, refsEnd))
return ec;
this->_referencesV1.arrayStart = refsStart;
this->_referencesV1.arrayEnd = refsEnd;
this->_referencesV1.elementSize = sizeof(NativeReferenceV1);
this->_referencesV1.elementCount = chunk->elementCount;
DEBUG_WITH_TYPE("ReaderNative", {
llvm::dbgs() << " chunk ReferencesV1: "
<< " count=" << chunk->elementCount
<< " chunkSize=" << chunk->fileSize << "\n";
});
return make_error_code(NativeReaderError::success);
}
// instantiate array of References from v2 ivar data in file
error_code processReferencesV2(const uint8_t *base,
const NativeChunk *chunk) {
uint8_t *refsStart, *refsEnd;
if (error_code ec
= processReferences<NativeReferenceV2, NativeReferenceIvarsV2>(
base, chunk, refsStart, refsEnd))
return ec;
this->_referencesV2.arrayStart = refsStart;
this->_referencesV2.arrayEnd = refsEnd;
this->_referencesV2.elementSize = sizeof(NativeReferenceV2);
this->_referencesV2.elementCount = chunk->elementCount;
DEBUG_WITH_TYPE("ReaderNative", {
llvm::dbgs() << " chunk ReferencesV2: "
<< " count=" << chunk->elementCount
<< " chunkSize=" << chunk->fileSize << "\n";
});
return make_error_code(NativeReaderError::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
+ abIndex * _absoluteAtoms._elementSize;
this->_targetsTable[i] = reinterpret_cast<const AbsoluteAtom*>(p);
continue;
}
return make_error_code(NativeReaderError::file_malformed);
}
DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
<< " chunk Targets Table: "
<< " count=" << chunk->elementCount
<< " chunkSize=" << chunk->fileSize
<< "\n");
return make_error_code(NativeReaderError::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(NativeReaderError::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(NativeReaderError::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(NativeReaderError::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 NativeAtomAttributesV1& absAttribute(uint32_t off) const {
assert(off < _absAbsoluteMaxOffset);
return *reinterpret_cast<const NativeAtomAttributesV1*>(_absAttributes + 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 {
if (index < _referencesV1.elementCount) {
return reinterpret_cast<const NativeReferenceV1*>(
_referencesV1.arrayStart + index * _referencesV1.elementSize);
}
assert(index < _referencesV2.elementCount);
return reinterpret_cast<const NativeReferenceV2*>(
_referencesV2.arrayStart + index * _referencesV2.elementSize);
}
const Atom* targetV1(uint16_t index) const {
if ( index == NativeReferenceIvarsV1::noTarget )
return nullptr;
assert(index < _targetsTableCount);
return _targetsTable[index];
}
void setTargetV1(uint16_t index, const Atom* newAtom) const {
assert(index != NativeReferenceIvarsV1::noTarget);
assert(index > _targetsTableCount);
_targetsTable[index] = newAtom;
}
const Atom* targetV2(uint32_t index) const {
if (index == NativeReferenceIvarsV2::noTarget)
return nullptr;
assert(index < _targetsTableCount);
return _targetsTable[index];
}
void setTargetV2(uint32_t index, const Atom* newAtom) const {
assert(index != NativeReferenceIvarsV2::noTarget);
assert(index > _targetsTableCount);
_targetsTable[index] = newAtom;
}
// private constructor, only called by make()
File(std::unique_ptr<MemoryBuffer> mb, StringRef path)
: lld::File(path, kindObject),
_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);
}
virtual uint64_t size() const { return _elementCount; }
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<MemoryBuffer> _buffer;
const NativeFileHeader* _header;
AtomArray<DefinedAtom> _definedAtoms;
AtomArray<UndefinedAtom> _undefinedAtoms;
AtomArray<SharedLibraryAtom> _sharedLibraryAtoms;
AtomArray<AbsoluteAtom> _absoluteAtoms;
const uint8_t* _absAttributes;
uint32_t _absAbsoluteMaxOffset;
const uint8_t* _attributes;
uint32_t _attributesMaxOffset;
IvarArray _referencesV1;
IvarArray _referencesV2;
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 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 (!occupiesDiskSpace())
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 lld::File& NativeUndefinedAtomV1::file() const {
return *_file;
}
inline StringRef NativeUndefinedAtomV1::name() const {
return _file->string(_ivarData->nameOffset);
}
inline const UndefinedAtom *NativeUndefinedAtomV1::fallback() const {
if (!_ivarData->fallbackNameOffset)
return nullptr;
if (!_fallback)
_fallback.reset(new SimpleUndefinedAtom(
*_file, _file->string(_ivarData->fallbackNameOffset)));
return _fallback.get();
}
inline const 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 lld::File& NativeAbsoluteAtomV1::file() const {
return *_file;
}
inline StringRef NativeAbsoluteAtomV1::name() const {
return _file->string(_ivarData->nameOffset);
}
inline const NativeAtomAttributesV1& NativeAbsoluteAtomV1::absAttributes() const {
return _file->absAttribute(_ivarData->attributesOffset);
}
inline const Atom* NativeReferenceV1::target() const {
return _file->targetV1(_ivarData->targetIndex);
}
inline Reference::Addend NativeReferenceV1::addend() const {
return _file->addend(_ivarData->addendIndex);
}
inline void NativeReferenceV1::setTarget(const Atom* newAtom) {
return _file->setTargetV1(_ivarData->targetIndex, newAtom);
}
inline void NativeReferenceV1::setAddend(Addend a) {
// Do nothing if addend value is not being changed.
if (addend() == a)
return;
llvm_unreachable("setAddend() not supported");
}
inline const Atom* NativeReferenceV2::target() const {
return _file->targetV2(_ivarData->targetIndex);
}
inline Reference::Addend NativeReferenceV2::addend() const {
return _ivarData->addend;
}
inline void NativeReferenceV2::setTarget(const Atom* newAtom) {
return _file->setTargetV2(_ivarData->targetIndex, newAtom);
}
inline void NativeReferenceV2::setAddend(Addend a) {
// Do nothing if addend value is not being changed.
if (addend() == a)
return;
llvm_unreachable("setAddend() not supported");
}
} // end namespace native
namespace {
class NativeReader : public Reader {
public:
virtual bool canParse(file_magic magic, StringRef,
const MemoryBuffer &mb) const override {
const NativeFileHeader *const header =
reinterpret_cast<const NativeFileHeader *>(mb.getBufferStart());
return (memcmp(header->magic, NATIVE_FILE_HEADER_MAGIC,
sizeof(header->magic)) == 0);
}
virtual error_code
parseFile(std::unique_ptr<MemoryBuffer> &mb, const class Registry &,
std::vector<std::unique_ptr<File>> &result) const override {
return lld::native::File::make(std::move(mb), result);
return error_code::success();
}
};
}
void Registry::addSupportNativeObjects() {
add(std::unique_ptr<Reader>(new NativeReader()));
}
} // end namespace lld