diff options
Diffstat (limited to 'lib/Object')
-rw-r--r-- | lib/Object/Archive.cpp | 40 | ||||
-rw-r--r-- | lib/Object/Binary.cpp | 37 | ||||
-rw-r--r-- | lib/Object/COFFObjectFile.cpp | 1007 | ||||
-rw-r--r-- | lib/Object/COFFYAML.cpp | 106 | ||||
-rw-r--r-- | lib/Object/ELF.cpp | 12 | ||||
-rw-r--r-- | lib/Object/ELFObjectFile.cpp | 37 | ||||
-rw-r--r-- | lib/Object/ELFYAML.cpp | 159 | ||||
-rw-r--r-- | lib/Object/Error.cpp | 10 | ||||
-rw-r--r-- | lib/Object/IRObjectFile.cpp | 74 | ||||
-rw-r--r-- | lib/Object/LLVMBuild.txt | 2 | ||||
-rw-r--r-- | lib/Object/MachOObjectFile.cpp | 1379 | ||||
-rw-r--r-- | lib/Object/MachOUniversal.cpp | 33 | ||||
-rw-r--r-- | lib/Object/Object.cpp | 60 | ||||
-rw-r--r-- | lib/Object/ObjectFile.cpp | 30 | ||||
-rw-r--r-- | lib/Object/RecordStreamer.h | 4 | ||||
-rw-r--r-- | lib/Object/SymbolicFile.cpp | 37 |
16 files changed, 2151 insertions, 876 deletions
diff --git a/lib/Object/Archive.cpp b/lib/Object/Archive.cpp index 6d09bdb..d169dbe 100644 --- a/lib/Object/Archive.cpp +++ b/lib/Object/Archive.cpp @@ -109,7 +109,7 @@ Archive::Child Archive::Child::getNext() const { const char *NextLoc = Data.data() + SpaceToSkip; // Check to see if this is past the end of the archive. - if (NextLoc >= Parent->Data->getBufferEnd()) + if (NextLoc >= Parent->Data.getBufferEnd()) return Child(Parent, nullptr); return Child(Parent, NextLoc); @@ -159,46 +159,36 @@ ErrorOr<StringRef> Archive::Child::getName() const { return name; } -ErrorOr<std::unique_ptr<MemoryBuffer>> -Archive::Child::getMemoryBuffer(bool FullPath) const { +ErrorOr<MemoryBufferRef> Archive::Child::getMemoryBufferRef() const { ErrorOr<StringRef> NameOrErr = getName(); if (std::error_code EC = NameOrErr.getError()) return EC; StringRef Name = NameOrErr.get(); - SmallString<128> Path; - std::unique_ptr<MemoryBuffer> Ret(MemoryBuffer::getMemBuffer( - getBuffer(), - FullPath - ? (Twine(Parent->getFileName()) + "(" + Name + ")").toStringRef(Path) - : Name, - false)); - return std::move(Ret); + return MemoryBufferRef(getBuffer(), Name); } ErrorOr<std::unique_ptr<Binary>> Archive::Child::getAsBinary(LLVMContext *Context) const { - std::unique_ptr<Binary> ret; - ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr = getMemoryBuffer(); + ErrorOr<MemoryBufferRef> BuffOrErr = getMemoryBufferRef(); if (std::error_code EC = BuffOrErr.getError()) return EC; - std::unique_ptr<MemoryBuffer> Buff(BuffOrErr.get().release()); - return createBinary(Buff, Context); + return createBinary(BuffOrErr.get(), Context); } -ErrorOr<Archive *> Archive::create(std::unique_ptr<MemoryBuffer> Source) { +ErrorOr<std::unique_ptr<Archive>> Archive::create(MemoryBufferRef Source) { std::error_code EC; - std::unique_ptr<Archive> Ret(new Archive(std::move(Source), EC)); + std::unique_ptr<Archive> Ret(new Archive(Source, EC)); if (EC) return EC; - return Ret.release(); + return std::move(Ret); } -Archive::Archive(std::unique_ptr<MemoryBuffer> Source, std::error_code &ec) - : Binary(Binary::ID_Archive, std::move(Source)), SymbolTable(child_end()) { +Archive::Archive(MemoryBufferRef Source, std::error_code &ec) + : Binary(Binary::ID_Archive, Source), SymbolTable(child_end()) { // Check for sufficient magic. - if (Data->getBufferSize() < 8 || - StringRef(Data->getBufferStart(), 8) != Magic) { + if (Data.getBufferSize() < 8 || + StringRef(Data.getBufferStart(), 8) != Magic) { ec = object_error::invalid_file_type; return; } @@ -250,7 +240,7 @@ Archive::Archive(std::unique_ptr<MemoryBuffer> Source, std::error_code &ec) if (ec) return; Name = NameOrErr.get(); - if (Name == "__.SYMDEF SORTED") { + if (Name == "__.SYMDEF SORTED" || Name == "__.SYMDEF") { SymbolTable = i; ++i; } @@ -312,13 +302,13 @@ Archive::Archive(std::unique_ptr<MemoryBuffer> Source, std::error_code &ec) } Archive::child_iterator Archive::child_begin(bool SkipInternal) const { - if (Data->getBufferSize() == 8) // empty archive. + if (Data.getBufferSize() == 8) // empty archive. return child_end(); if (SkipInternal) return FirstRegular; - const char *Loc = Data->getBufferStart() + strlen(Magic); + const char *Loc = Data.getBufferStart() + strlen(Magic); Child c(this, Loc); return c; } diff --git a/lib/Object/Binary.cpp b/lib/Object/Binary.cpp index 9f6a685..c56eeb1 100644 --- a/lib/Object/Binary.cpp +++ b/lib/Object/Binary.cpp @@ -27,24 +27,23 @@ using namespace object; Binary::~Binary() {} -Binary::Binary(unsigned int Type, std::unique_ptr<MemoryBuffer> Source) - : TypeID(Type), Data(std::move(Source)) {} +Binary::Binary(unsigned int Type, MemoryBufferRef Source) + : TypeID(Type), Data(Source) {} -StringRef Binary::getData() const { - return Data->getBuffer(); -} +StringRef Binary::getData() const { return Data.getBuffer(); } -StringRef Binary::getFileName() const { - return Data->getBufferIdentifier(); -} +StringRef Binary::getFileName() const { return Data.getBufferIdentifier(); } + +MemoryBufferRef Binary::getMemoryBufferRef() const { return Data; } -ErrorOr<Binary *> object::createBinary(std::unique_ptr<MemoryBuffer> &Buffer, - LLVMContext *Context) { - sys::fs::file_magic Type = sys::fs::identify_magic(Buffer->getBuffer()); +ErrorOr<std::unique_ptr<Binary>> object::createBinary(MemoryBufferRef Buffer, + LLVMContext *Context) { + sys::fs::file_magic Type = sys::fs::identify_magic(Buffer.getBuffer()); switch (Type) { case sys::fs::file_magic::archive: - return Archive::create(std::move(Buffer)); + return Archive::create(Buffer); + case sys::fs::file_magic::elf: case sys::fs::file_magic::elf_relocatable: case sys::fs::file_magic::elf_executable: case sys::fs::file_magic::elf_shared_object: @@ -65,7 +64,7 @@ ErrorOr<Binary *> object::createBinary(std::unique_ptr<MemoryBuffer> &Buffer, case sys::fs::file_magic::bitcode: return ObjectFile::createSymbolicFile(Buffer, Type, Context); case sys::fs::file_magic::macho_universal_binary: - return MachOUniversalBinary::create(std::move(Buffer)); + return MachOUniversalBinary::create(Buffer); case sys::fs::file_magic::unknown: case sys::fs::file_magic::windows_resource: // Unrecognized object file format. @@ -74,10 +73,18 @@ ErrorOr<Binary *> object::createBinary(std::unique_ptr<MemoryBuffer> &Buffer, llvm_unreachable("Unexpected Binary File Type"); } -ErrorOr<Binary *> object::createBinary(StringRef Path) { +ErrorOr<OwningBinary<Binary>> object::createBinary(StringRef Path) { ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr = MemoryBuffer::getFileOrSTDIN(Path); if (std::error_code EC = FileOrErr.getError()) return EC; - return createBinary(FileOrErr.get()); + std::unique_ptr<MemoryBuffer> &Buffer = FileOrErr.get(); + + ErrorOr<std::unique_ptr<Binary>> BinOrErr = + createBinary(Buffer->getMemBufferRef()); + if (std::error_code EC = BinOrErr.getError()) + return EC; + std::unique_ptr<Binary> &Bin = BinOrErr.get(); + + return OwningBinary<Binary>(std::move(Bin), std::move(Buffer)); } diff --git a/lib/Object/COFFObjectFile.cpp b/lib/Object/COFFObjectFile.cpp index 46ef87d..d5ff7d6 100644 --- a/lib/Object/COFFObjectFile.cpp +++ b/lib/Object/COFFObjectFile.cpp @@ -25,14 +25,13 @@ using namespace llvm; using namespace object; -using support::ulittle8_t; using support::ulittle16_t; using support::ulittle32_t; +using support::ulittle64_t; using support::little16_t; // Returns false if size is greater than the buffer size. And sets ec. -static bool checkSize(const MemoryBuffer &M, std::error_code &EC, - uint64_t Size) { +static bool checkSize(MemoryBufferRef M, std::error_code &EC, uint64_t Size) { if (M.getBufferSize() < Size) { EC = object_error::unexpected_eof; return false; @@ -40,17 +39,25 @@ static bool checkSize(const MemoryBuffer &M, std::error_code &EC, return true; } +static std::error_code checkOffset(MemoryBufferRef M, uintptr_t Addr, + const uint64_t Size) { + if (Addr + Size < Addr || Addr + Size < Size || + Addr + Size > uintptr_t(M.getBufferEnd()) || + Addr < uintptr_t(M.getBufferStart())) { + return object_error::unexpected_eof; + } + return object_error::success; +} + // Sets Obj unless any bytes in [addr, addr + size) fall outsize of m. // Returns unexpected_eof if error. template <typename T> -static std::error_code getObject(const T *&Obj, const MemoryBuffer &M, - const uint8_t *Ptr, - const size_t Size = sizeof(T)) { +static std::error_code getObject(const T *&Obj, MemoryBufferRef M, + const void *Ptr, + const uint64_t Size = sizeof(T)) { uintptr_t Addr = uintptr_t(Ptr); - if (Addr + Size < Addr || Addr + Size < Size || - Addr + Size > uintptr_t(M.getBufferEnd())) { - return object_error::unexpected_eof; - } + if (std::error_code EC = checkOffset(M, Addr, Size)) + return EC; Obj = reinterpret_cast<const T *>(Addr); return object_error::success; } @@ -89,20 +96,19 @@ static bool decodeBase64StringEntry(StringRef Str, uint32_t &Result) { return false; } -const coff_symbol *COFFObjectFile::toSymb(DataRefImpl Ref) const { - const coff_symbol *Addr = reinterpret_cast<const coff_symbol*>(Ref.p); +template <typename coff_symbol_type> +const coff_symbol_type *COFFObjectFile::toSymb(DataRefImpl Ref) const { + const coff_symbol_type *Addr = + reinterpret_cast<const coff_symbol_type *>(Ref.p); -# ifndef NDEBUG + assert(!checkOffset(Data, uintptr_t(Addr), sizeof(*Addr))); +#ifndef NDEBUG // Verify that the symbol points to a valid entry in the symbol table. uintptr_t Offset = uintptr_t(Addr) - uintptr_t(base()); - if (Offset < COFFHeader->PointerToSymbolTable - || Offset >= COFFHeader->PointerToSymbolTable - + (COFFHeader->NumberOfSymbols * sizeof(coff_symbol))) - report_fatal_error("Symbol was outside of symbol table."); - assert((Offset - COFFHeader->PointerToSymbolTable) % sizeof(coff_symbol) - == 0 && "Symbol did not point to the beginning of a symbol"); -# endif + assert((Offset - getPointerToSymbolTable()) % sizeof(coff_symbol_type) == 0 && + "Symbol did not point to the beginning of a symbol"); +#endif return Addr; } @@ -112,8 +118,7 @@ const coff_section *COFFObjectFile::toSec(DataRefImpl Ref) const { # ifndef NDEBUG // Verify that the section points to a valid entry in the section table. - if (Addr < SectionTable - || Addr >= (SectionTable + COFFHeader->NumberOfSections)) + if (Addr < SectionTable || Addr >= (SectionTable + getNumberOfSections())) report_fatal_error("Section was outside of section table."); uintptr_t Offset = uintptr_t(Addr) - uintptr_t(SectionTable); @@ -125,112 +130,180 @@ const coff_section *COFFObjectFile::toSec(DataRefImpl Ref) const { } void COFFObjectFile::moveSymbolNext(DataRefImpl &Ref) const { - const coff_symbol *Symb = toSymb(Ref); - Symb += 1 + Symb->NumberOfAuxSymbols; - Ref.p = reinterpret_cast<uintptr_t>(Symb); + auto End = reinterpret_cast<uintptr_t>(StringTable); + if (SymbolTable16) { + const coff_symbol16 *Symb = toSymb<coff_symbol16>(Ref); + Symb += 1 + Symb->NumberOfAuxSymbols; + Ref.p = std::min(reinterpret_cast<uintptr_t>(Symb), End); + } else if (SymbolTable32) { + const coff_symbol32 *Symb = toSymb<coff_symbol32>(Ref); + Symb += 1 + Symb->NumberOfAuxSymbols; + Ref.p = std::min(reinterpret_cast<uintptr_t>(Symb), End); + } else { + llvm_unreachable("no symbol table pointer!"); + } } std::error_code COFFObjectFile::getSymbolName(DataRefImpl Ref, StringRef &Result) const { - const coff_symbol *Symb = toSymb(Ref); + COFFSymbolRef Symb = getCOFFSymbol(Ref); return getSymbolName(Symb, Result); } std::error_code COFFObjectFile::getSymbolAddress(DataRefImpl Ref, uint64_t &Result) const { - const coff_symbol *Symb = toSymb(Ref); - const coff_section *Section = nullptr; - if (std::error_code EC = getSection(Symb->SectionNumber, Section)) - return EC; + COFFSymbolRef Symb = getCOFFSymbol(Ref); - if (Symb->SectionNumber == COFF::IMAGE_SYM_UNDEFINED) + if (Symb.isAnyUndefined()) { Result = UnknownAddressOrSize; - else if (Section) - Result = Section->VirtualAddress + Symb->Value; - else - Result = Symb->Value; + return object_error::success; + } + if (Symb.isCommon()) { + Result = UnknownAddressOrSize; + return object_error::success; + } + int32_t SectionNumber = Symb.getSectionNumber(); + if (!COFF::isReservedSectionNumber(SectionNumber)) { + const coff_section *Section = nullptr; + if (std::error_code EC = getSection(SectionNumber, Section)) + return EC; + + Result = Section->VirtualAddress + Symb.getValue(); + return object_error::success; + } + + Result = Symb.getValue(); return object_error::success; } std::error_code COFFObjectFile::getSymbolType(DataRefImpl Ref, SymbolRef::Type &Result) const { - const coff_symbol *Symb = toSymb(Ref); + COFFSymbolRef Symb = getCOFFSymbol(Ref); + int32_t SectionNumber = Symb.getSectionNumber(); Result = SymbolRef::ST_Other; - if (Symb->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL && - Symb->SectionNumber == COFF::IMAGE_SYM_UNDEFINED) { + + if (Symb.isAnyUndefined()) { Result = SymbolRef::ST_Unknown; - } else if (Symb->isFunctionDefinition()) { + } else if (Symb.isFunctionDefinition()) { Result = SymbolRef::ST_Function; - } else { - uint32_t Characteristics = 0; - if (!COFF::isReservedSectionNumber(Symb->SectionNumber)) { - const coff_section *Section = nullptr; - if (std::error_code EC = getSection(Symb->SectionNumber, Section)) - return EC; - Characteristics = Section->Characteristics; - } - if (Characteristics & COFF::IMAGE_SCN_MEM_READ && - ~Characteristics & COFF::IMAGE_SCN_MEM_WRITE) // Read only. + } else if (Symb.isCommon()) { + Result = SymbolRef::ST_Data; + } else if (Symb.isFileRecord()) { + Result = SymbolRef::ST_File; + } else if (SectionNumber == COFF::IMAGE_SYM_DEBUG) { + Result = SymbolRef::ST_Debug; + } else if (!COFF::isReservedSectionNumber(SectionNumber)) { + const coff_section *Section = nullptr; + if (std::error_code EC = getSection(SectionNumber, Section)) + return EC; + uint32_t Characteristics = Section->Characteristics; + if (Characteristics & COFF::IMAGE_SCN_CNT_CODE) + Result = SymbolRef::ST_Function; + else if (Characteristics & (COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)) Result = SymbolRef::ST_Data; } return object_error::success; } uint32_t COFFObjectFile::getSymbolFlags(DataRefImpl Ref) const { - const coff_symbol *Symb = toSymb(Ref); + COFFSymbolRef Symb = getCOFFSymbol(Ref); uint32_t Result = SymbolRef::SF_None; - // TODO: Correctly set SF_FormatSpecific, SF_Common - - if (Symb->SectionNumber == COFF::IMAGE_SYM_UNDEFINED) { - if (Symb->Value == 0) - Result |= SymbolRef::SF_Undefined; - else - Result |= SymbolRef::SF_Common; - } - - - // TODO: This are certainly too restrictive. - if (Symb->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL) + if (Symb.isExternal() || Symb.isWeakExternal()) Result |= SymbolRef::SF_Global; - if (Symb->StorageClass == COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL) + if (Symb.isWeakExternal()) Result |= SymbolRef::SF_Weak; - if (Symb->SectionNumber == COFF::IMAGE_SYM_ABSOLUTE) + if (Symb.getSectionNumber() == COFF::IMAGE_SYM_ABSOLUTE) Result |= SymbolRef::SF_Absolute; + if (Symb.isFileRecord()) + Result |= SymbolRef::SF_FormatSpecific; + + if (Symb.isSectionDefinition()) + Result |= SymbolRef::SF_FormatSpecific; + + if (Symb.isCommon()) + Result |= SymbolRef::SF_Common; + + if (Symb.isAnyUndefined()) + Result |= SymbolRef::SF_Undefined; + return Result; } std::error_code COFFObjectFile::getSymbolSize(DataRefImpl Ref, uint64_t &Result) const { - // FIXME: Return the correct size. This requires looking at all the symbols - // in the same section as this symbol, and looking for either the next - // symbol, or the end of the section. - const coff_symbol *Symb = toSymb(Ref); - const coff_section *Section = nullptr; - if (std::error_code EC = getSection(Symb->SectionNumber, Section)) - return EC; + COFFSymbolRef Symb = getCOFFSymbol(Ref); - if (Symb->SectionNumber == COFF::IMAGE_SYM_UNDEFINED) + if (Symb.isAnyUndefined()) { Result = UnknownAddressOrSize; - else if (Section) - Result = Section->SizeOfRawData - Symb->Value; - else + return object_error::success; + } + if (Symb.isCommon()) { + Result = Symb.getValue(); + return object_error::success; + } + + // Let's attempt to get the size of the symbol by looking at the address of + // the symbol after the symbol in question. + uint64_t SymbAddr; + if (std::error_code EC = getSymbolAddress(Ref, SymbAddr)) + return EC; + int32_t SectionNumber = Symb.getSectionNumber(); + if (COFF::isReservedSectionNumber(SectionNumber)) { + // Absolute and debug symbols aren't sorted in any interesting way. Result = 0; + return object_error::success; + } + const section_iterator SecEnd = section_end(); + uint64_t AfterAddr = UnknownAddressOrSize; + for (const symbol_iterator &SymbI : symbols()) { + section_iterator SecI = SecEnd; + if (std::error_code EC = SymbI->getSection(SecI)) + return EC; + // Check the symbol's section, skip it if it's in the wrong section. + // First, make sure it is in any section. + if (SecI == SecEnd) + continue; + // Second, make sure it is in the same section as the symbol in question. + if (!sectionContainsSymbol(SecI->getRawDataRefImpl(), Ref)) + continue; + uint64_t Addr; + if (std::error_code EC = SymbI->getAddress(Addr)) + return EC; + // We want to compare our symbol in question with the closest possible + // symbol that comes after. + if (AfterAddr > Addr && Addr > SymbAddr) + AfterAddr = Addr; + } + if (AfterAddr == UnknownAddressOrSize) { + // No symbol comes after this one, assume that everything after our symbol + // is part of it. + const coff_section *Section = nullptr; + if (std::error_code EC = getSection(SectionNumber, Section)) + return EC; + Result = Section->SizeOfRawData - Symb.getValue(); + } else { + // Take the difference between our symbol and the symbol that comes after + // our symbol. + Result = AfterAddr - SymbAddr; + } + return object_error::success; } std::error_code COFFObjectFile::getSymbolSection(DataRefImpl Ref, section_iterator &Result) const { - const coff_symbol *Symb = toSymb(Ref); - if (COFF::isReservedSectionNumber(Symb->SectionNumber)) { + COFFSymbolRef Symb = getCOFFSymbol(Ref); + if (COFF::isReservedSectionNumber(Symb.getSectionNumber())) { Result = section_end(); } else { const coff_section *Sec = nullptr; - if (std::error_code EC = getSection(Symb->SectionNumber, Sec)) + if (std::error_code EC = getSection(Symb.getSectionNumber(), Sec)) return EC; DataRefImpl Ref; Ref.p = reinterpret_cast<uintptr_t>(Sec); @@ -251,18 +324,13 @@ std::error_code COFFObjectFile::getSectionName(DataRefImpl Ref, return getSectionName(Sec, Result); } -std::error_code COFFObjectFile::getSectionAddress(DataRefImpl Ref, - uint64_t &Result) const { +uint64_t COFFObjectFile::getSectionAddress(DataRefImpl Ref) const { const coff_section *Sec = toSec(Ref); - Result = Sec->VirtualAddress; - return object_error::success; + return Sec->VirtualAddress; } -std::error_code COFFObjectFile::getSectionSize(DataRefImpl Ref, - uint64_t &Result) const { - const coff_section *Sec = toSec(Ref); - Result = Sec->SizeOfRawData; - return object_error::success; +uint64_t COFFObjectFile::getSectionSize(DataRefImpl Ref) const { + return getSectionSize(toSec(Ref)); } std::error_code COFFObjectFile::getSectionContents(DataRefImpl Ref, @@ -274,146 +342,144 @@ std::error_code COFFObjectFile::getSectionContents(DataRefImpl Ref, return EC; } -std::error_code COFFObjectFile::getSectionAlignment(DataRefImpl Ref, - uint64_t &Res) const { +uint64_t COFFObjectFile::getSectionAlignment(DataRefImpl Ref) const { const coff_section *Sec = toSec(Ref); - if (!Sec) - return object_error::parse_failed; - Res = uint64_t(1) << (((Sec->Characteristics & 0x00F00000) >> 20) - 1); - return object_error::success; + return uint64_t(1) << (((Sec->Characteristics & 0x00F00000) >> 20) - 1); } -std::error_code COFFObjectFile::isSectionText(DataRefImpl Ref, - bool &Result) const { +bool COFFObjectFile::isSectionText(DataRefImpl Ref) const { const coff_section *Sec = toSec(Ref); - Result = Sec->Characteristics & COFF::IMAGE_SCN_CNT_CODE; - return object_error::success; + return Sec->Characteristics & COFF::IMAGE_SCN_CNT_CODE; } -std::error_code COFFObjectFile::isSectionData(DataRefImpl Ref, - bool &Result) const { +bool COFFObjectFile::isSectionData(DataRefImpl Ref) const { const coff_section *Sec = toSec(Ref); - Result = Sec->Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA; - return object_error::success; + return Sec->Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA; } -std::error_code COFFObjectFile::isSectionBSS(DataRefImpl Ref, - bool &Result) const { +bool COFFObjectFile::isSectionBSS(DataRefImpl Ref) const { const coff_section *Sec = toSec(Ref); - Result = Sec->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA; - return object_error::success; + return Sec->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA; } -std::error_code -COFFObjectFile::isSectionRequiredForExecution(DataRefImpl Ref, - bool &Result) const { - // FIXME: Unimplemented - Result = true; - return object_error::success; +bool COFFObjectFile::isSectionRequiredForExecution(DataRefImpl Ref) const { + // Sections marked 'Info', 'Remove', or 'Discardable' aren't required for + // execution. + const coff_section *Sec = toSec(Ref); + return !(Sec->Characteristics & + (COFF::IMAGE_SCN_LNK_INFO | COFF::IMAGE_SCN_LNK_REMOVE | + COFF::IMAGE_SCN_MEM_DISCARDABLE)); } -std::error_code COFFObjectFile::isSectionVirtual(DataRefImpl Ref, - bool &Result) const { +bool COFFObjectFile::isSectionVirtual(DataRefImpl Ref) const { const coff_section *Sec = toSec(Ref); - Result = Sec->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA; - return object_error::success; + return Sec->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA; } -std::error_code COFFObjectFile::isSectionZeroInit(DataRefImpl Ref, - bool &Result) const { - // FIXME: Unimplemented. - Result = false; - return object_error::success; +bool COFFObjectFile::isSectionZeroInit(DataRefImpl Ref) const { + const coff_section *Sec = toSec(Ref); + return Sec->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA; } -std::error_code COFFObjectFile::isSectionReadOnlyData(DataRefImpl Ref, - bool &Result) const { - // FIXME: Unimplemented. - Result = false; - return object_error::success; +bool COFFObjectFile::isSectionReadOnlyData(DataRefImpl Ref) const { + const coff_section *Sec = toSec(Ref); + // Check if it's any sort of data section. + if (!(Sec->Characteristics & (COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA | + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA))) + return false; + // If it's writable or executable or contains code, it isn't read-only data. + if (Sec->Characteristics & + (COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE | + COFF::IMAGE_SCN_MEM_WRITE)) + return false; + return true; } -std::error_code COFFObjectFile::sectionContainsSymbol(DataRefImpl SecRef, - DataRefImpl SymbRef, - bool &Result) const { +bool COFFObjectFile::sectionContainsSymbol(DataRefImpl SecRef, + DataRefImpl SymbRef) const { const coff_section *Sec = toSec(SecRef); - const coff_symbol *Symb = toSymb(SymbRef); - const coff_section *SymbSec = nullptr; - if (std::error_code EC = getSection(Symb->SectionNumber, SymbSec)) - return EC; - if (SymbSec == Sec) - Result = true; - else - Result = false; - return object_error::success; -} - -relocation_iterator COFFObjectFile::section_rel_begin(DataRefImpl Ref) const { - const coff_section *Sec = toSec(Ref); - DataRefImpl Ret; - if (Sec->NumberOfRelocations == 0) { - Ret.p = 0; - } else { - auto begin = reinterpret_cast<const coff_relocation*>( - base() + Sec->PointerToRelocations); - if (Sec->hasExtendedRelocations()) { - // Skip the first relocation entry repurposed to store the number of - // relocations. - begin++; - } - Ret.p = reinterpret_cast<uintptr_t>(begin); - } - return relocation_iterator(RelocationRef(Ret, this)); + COFFSymbolRef Symb = getCOFFSymbol(SymbRef); + int32_t SecNumber = (Sec - SectionTable) + 1; + return SecNumber == Symb.getSectionNumber(); } static uint32_t getNumberOfRelocations(const coff_section *Sec, - const uint8_t *base) { + MemoryBufferRef M, const uint8_t *base) { // The field for the number of relocations in COFF section table is only // 16-bit wide. If a section has more than 65535 relocations, 0xFFFF is set to // NumberOfRelocations field, and the actual relocation count is stored in the // VirtualAddress field in the first relocation entry. if (Sec->hasExtendedRelocations()) { - auto *FirstReloc = reinterpret_cast<const coff_relocation*>( - base + Sec->PointerToRelocations); + const coff_relocation *FirstReloc; + if (getObject(FirstReloc, M, reinterpret_cast<const coff_relocation*>( + base + Sec->PointerToRelocations))) + return 0; return FirstReloc->VirtualAddress; } return Sec->NumberOfRelocations; } +static const coff_relocation * +getFirstReloc(const coff_section *Sec, MemoryBufferRef M, const uint8_t *Base) { + uint64_t NumRelocs = getNumberOfRelocations(Sec, M, Base); + if (!NumRelocs) + return nullptr; + auto begin = reinterpret_cast<const coff_relocation *>( + Base + Sec->PointerToRelocations); + if (Sec->hasExtendedRelocations()) { + // Skip the first relocation entry repurposed to store the number of + // relocations. + begin++; + } + if (checkOffset(M, uintptr_t(begin), sizeof(coff_relocation) * NumRelocs)) + return nullptr; + return begin; +} + +relocation_iterator COFFObjectFile::section_rel_begin(DataRefImpl Ref) const { + const coff_section *Sec = toSec(Ref); + const coff_relocation *begin = getFirstReloc(Sec, Data, base()); + DataRefImpl Ret; + Ret.p = reinterpret_cast<uintptr_t>(begin); + return relocation_iterator(RelocationRef(Ret, this)); +} + relocation_iterator COFFObjectFile::section_rel_end(DataRefImpl Ref) const { const coff_section *Sec = toSec(Ref); + const coff_relocation *I = getFirstReloc(Sec, Data, base()); + if (I) + I += getNumberOfRelocations(Sec, Data, base()); DataRefImpl Ret; - if (Sec->NumberOfRelocations == 0) { - Ret.p = 0; - } else { - auto begin = reinterpret_cast<const coff_relocation*>( - base() + Sec->PointerToRelocations); - uint32_t NumReloc = getNumberOfRelocations(Sec, base()); - Ret.p = reinterpret_cast<uintptr_t>(begin + NumReloc); - } + Ret.p = reinterpret_cast<uintptr_t>(I); return relocation_iterator(RelocationRef(Ret, this)); } // Initialize the pointer to the symbol table. std::error_code COFFObjectFile::initSymbolTablePtr() { - if (std::error_code EC = getObject( - SymbolTable, *Data, base() + COFFHeader->PointerToSymbolTable, - COFFHeader->NumberOfSymbols * sizeof(coff_symbol))) - return EC; + if (COFFHeader) + if (std::error_code EC = getObject( + SymbolTable16, Data, base() + getPointerToSymbolTable(), + (uint64_t)getNumberOfSymbols() * getSymbolTableEntrySize())) + return EC; + + if (COFFBigObjHeader) + if (std::error_code EC = getObject( + SymbolTable32, Data, base() + getPointerToSymbolTable(), + (uint64_t)getNumberOfSymbols() * getSymbolTableEntrySize())) + return EC; // Find string table. The first four byte of the string table contains the // total size of the string table, including the size field itself. If the // string table is empty, the value of the first four byte would be 4. - const uint8_t *StringTableAddr = - base() + COFFHeader->PointerToSymbolTable + - COFFHeader->NumberOfSymbols * sizeof(coff_symbol); + uint32_t StringTableOffset = getPointerToSymbolTable() + + getNumberOfSymbols() * getSymbolTableEntrySize(); + const uint8_t *StringTableAddr = base() + StringTableOffset; const ulittle32_t *StringTableSizePtr; - if (std::error_code EC = - getObject(StringTableSizePtr, *Data, StringTableAddr)) + if (std::error_code EC = getObject(StringTableSizePtr, Data, StringTableAddr)) return EC; StringTableSize = *StringTableSizePtr; if (std::error_code EC = - getObject(StringTable, *Data, StringTableAddr, StringTableSize)) + getObject(StringTable, Data, StringTableAddr, StringTableSize)) return EC; // Treat table sizes < 4 as empty because contrary to the PECOFF spec, some @@ -477,8 +543,9 @@ std::error_code COFFObjectFile::initImportTablePtr() { return object_error::success; uint32_t ImportTableRva = DataEntry->RelativeVirtualAddress; + // -1 because the last entry is the null entry. NumberOfImportDirectory = DataEntry->Size / - sizeof(import_directory_table_entry); + sizeof(import_directory_table_entry) - 1; // Find the section that contains the RVA. This is needed because the RVA is // the import table's memory address which is different from its file offset. @@ -490,6 +557,26 @@ std::error_code COFFObjectFile::initImportTablePtr() { return object_error::success; } +// Initializes DelayImportDirectory and NumberOfDelayImportDirectory. +std::error_code COFFObjectFile::initDelayImportTablePtr() { + const data_directory *DataEntry; + if (getDataDirectory(COFF::DELAY_IMPORT_DESCRIPTOR, DataEntry)) + return object_error::success; + if (DataEntry->RelativeVirtualAddress == 0) + return object_error::success; + + uint32_t RVA = DataEntry->RelativeVirtualAddress; + NumberOfDelayImportDirectory = DataEntry->Size / + sizeof(delay_import_directory_table_entry) - 1; + + uintptr_t IntPtr = 0; + if (std::error_code EC = getRvaPtr(RVA, IntPtr)) + return EC; + DelayImportDirectory = reinterpret_cast< + const delay_import_directory_table_entry *>(IntPtr); + return object_error::success; +} + // Find the export table. std::error_code COFFObjectFile::initExportTablePtr() { // First, we get the RVA of the export table. If the file lacks a pointer to @@ -511,15 +598,34 @@ std::error_code COFFObjectFile::initExportTablePtr() { return object_error::success; } -COFFObjectFile::COFFObjectFile(std::unique_ptr<MemoryBuffer> Object, - std::error_code &EC) - : ObjectFile(Binary::ID_COFF, std::move(Object)), COFFHeader(nullptr), - PE32Header(nullptr), PE32PlusHeader(nullptr), DataDirectory(nullptr), - SectionTable(nullptr), SymbolTable(nullptr), StringTable(nullptr), - StringTableSize(0), ImportDirectory(nullptr), NumberOfImportDirectory(0), - ExportDirectory(nullptr) { +std::error_code COFFObjectFile::initBaseRelocPtr() { + const data_directory *DataEntry; + if (getDataDirectory(COFF::BASE_RELOCATION_TABLE, DataEntry)) + return object_error::success; + if (DataEntry->RelativeVirtualAddress == 0) + return object_error::success; + + uintptr_t IntPtr = 0; + if (std::error_code EC = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr)) + return EC; + BaseRelocHeader = reinterpret_cast<const coff_base_reloc_block_header *>( + IntPtr); + BaseRelocEnd = reinterpret_cast<coff_base_reloc_block_header *>( + IntPtr + DataEntry->Size); + return object_error::success; +} + +COFFObjectFile::COFFObjectFile(MemoryBufferRef Object, std::error_code &EC) + : ObjectFile(Binary::ID_COFF, Object), COFFHeader(nullptr), + COFFBigObjHeader(nullptr), PE32Header(nullptr), PE32PlusHeader(nullptr), + DataDirectory(nullptr), SectionTable(nullptr), SymbolTable16(nullptr), + SymbolTable32(nullptr), StringTable(nullptr), StringTableSize(0), + ImportDirectory(nullptr), NumberOfImportDirectory(0), + DelayImportDirectory(nullptr), NumberOfDelayImportDirectory(0), + ExportDirectory(nullptr), BaseRelocHeader(nullptr), + BaseRelocEnd(nullptr) { // Check that we at least have enough room for a header. - if (!checkSize(*Data, EC, sizeof(coff_file_header))) + if (!checkSize(Data, EC, sizeof(coff_file_header))) return; // The current location in the file where we are looking at. @@ -530,37 +636,66 @@ COFFObjectFile::COFFObjectFile(std::unique_ptr<MemoryBuffer> Object, bool HasPEHeader = false; // Check if this is a PE/COFF file. - if (base()[0] == 0x4d && base()[1] == 0x5a) { + if (checkSize(Data, EC, sizeof(dos_header) + sizeof(COFF::PEMagic))) { // PE/COFF, seek through MS-DOS compatibility stub and 4-byte // PE signature to find 'normal' COFF header. - if (!checkSize(*Data, EC, 0x3c + 8)) - return; - CurPtr = *reinterpret_cast<const ulittle16_t *>(base() + 0x3c); - // Check the PE magic bytes. ("PE\0\0") - if (std::memcmp(base() + CurPtr, "PE\0\0", 4) != 0) { - EC = object_error::parse_failed; - return; + const auto *DH = reinterpret_cast<const dos_header *>(base()); + if (DH->Magic[0] == 'M' && DH->Magic[1] == 'Z') { + CurPtr = DH->AddressOfNewExeHeader; + // Check the PE magic bytes. ("PE\0\0") + if (memcmp(base() + CurPtr, COFF::PEMagic, sizeof(COFF::PEMagic)) != 0) { + EC = object_error::parse_failed; + return; + } + CurPtr += sizeof(COFF::PEMagic); // Skip the PE magic bytes. + HasPEHeader = true; } - CurPtr += 4; // Skip the PE magic bytes. - HasPEHeader = true; } - if ((EC = getObject(COFFHeader, *Data, base() + CurPtr))) + if ((EC = getObject(COFFHeader, Data, base() + CurPtr))) return; - CurPtr += sizeof(coff_file_header); + + // It might be a bigobj file, let's check. Note that COFF bigobj and COFF + // import libraries share a common prefix but bigobj is more restrictive. + if (!HasPEHeader && COFFHeader->Machine == COFF::IMAGE_FILE_MACHINE_UNKNOWN && + COFFHeader->NumberOfSections == uint16_t(0xffff) && + checkSize(Data, EC, sizeof(coff_bigobj_file_header))) { + if ((EC = getObject(COFFBigObjHeader, Data, base() + CurPtr))) + return; + + // Verify that we are dealing with bigobj. + if (COFFBigObjHeader->Version >= COFF::BigObjHeader::MinBigObjectVersion && + std::memcmp(COFFBigObjHeader->UUID, COFF::BigObjMagic, + sizeof(COFF::BigObjMagic)) == 0) { + COFFHeader = nullptr; + CurPtr += sizeof(coff_bigobj_file_header); + } else { + // It's not a bigobj. + COFFBigObjHeader = nullptr; + } + } + if (COFFHeader) { + // The prior checkSize call may have failed. This isn't a hard error + // because we were just trying to sniff out bigobj. + EC = object_error::success; + CurPtr += sizeof(coff_file_header); + + if (COFFHeader->isImportLibrary()) + return; + } if (HasPEHeader) { const pe32_header *Header; - if ((EC = getObject(Header, *Data, base() + CurPtr))) + if ((EC = getObject(Header, Data, base() + CurPtr))) return; const uint8_t *DataDirAddr; uint64_t DataDirSize; - if (Header->Magic == 0x10b) { + if (Header->Magic == COFF::PE32Header::PE32) { PE32Header = Header; DataDirAddr = base() + CurPtr + sizeof(pe32_header); DataDirSize = sizeof(data_directory) * PE32Header->NumberOfRvaAndSize; - } else if (Header->Magic == 0x20b) { + } else if (Header->Magic == COFF::PE32Header::PE32_PLUS) { PE32PlusHeader = reinterpret_cast<const pe32plus_header *>(Header); DataDirAddr = base() + CurPtr + sizeof(pe32plus_header); DataDirSize = sizeof(data_directory) * PE32PlusHeader->NumberOfRvaAndSize; @@ -569,37 +704,47 @@ COFFObjectFile::COFFObjectFile(std::unique_ptr<MemoryBuffer> Object, EC = object_error::parse_failed; return; } - if ((EC = getObject(DataDirectory, *Data, DataDirAddr, DataDirSize))) + if ((EC = getObject(DataDirectory, Data, DataDirAddr, DataDirSize))) return; CurPtr += COFFHeader->SizeOfOptionalHeader; } - if (COFFHeader->isImportLibrary()) - return; - - if ((EC = getObject(SectionTable, *Data, base() + CurPtr, - COFFHeader->NumberOfSections * sizeof(coff_section)))) + if ((EC = getObject(SectionTable, Data, base() + CurPtr, + (uint64_t)getNumberOfSections() * sizeof(coff_section)))) return; // Initialize the pointer to the symbol table. - if (COFFHeader->PointerToSymbolTable != 0) + if (getPointerToSymbolTable() != 0) { if ((EC = initSymbolTablePtr())) return; + } else { + // We had better not have any symbols if we don't have a symbol table. + if (getNumberOfSymbols() != 0) { + EC = object_error::parse_failed; + return; + } + } // Initialize the pointer to the beginning of the import table. if ((EC = initImportTablePtr())) return; + if ((EC = initDelayImportTablePtr())) + return; // Initialize the pointer to the export table. if ((EC = initExportTablePtr())) return; + // Initialize the pointer to the base relocation table. + if ((EC = initBaseRelocPtr())) + return; + EC = object_error::success; } basic_symbol_iterator COFFObjectFile::symbol_begin_impl() const { DataRefImpl Ret; - Ret.p = reinterpret_cast<uintptr_t>(SymbolTable); + Ret.p = getSymbolTable(); return basic_symbol_iterator(SymbolRef(Ret, this)); } @@ -610,21 +755,6 @@ basic_symbol_iterator COFFObjectFile::symbol_end_impl() const { return basic_symbol_iterator(SymbolRef(Ret, this)); } -library_iterator COFFObjectFile::needed_library_begin() const { - // TODO: implement - report_fatal_error("Libraries needed unimplemented in COFFObjectFile"); -} - -library_iterator COFFObjectFile::needed_library_end() const { - // TODO: implement - report_fatal_error("Libraries needed unimplemented in COFFObjectFile"); -} - -StringRef COFFObjectFile::getLoadName() const { - // COFF does not have this field. - return ""; -} - import_directory_iterator COFFObjectFile::import_directory_begin() const { return import_directory_iterator( ImportDirectoryEntryRef(ImportDirectory, 0, this)); @@ -635,6 +765,19 @@ import_directory_iterator COFFObjectFile::import_directory_end() const { ImportDirectoryEntryRef(ImportDirectory, NumberOfImportDirectory, this)); } +delay_import_directory_iterator +COFFObjectFile::delay_import_directory_begin() const { + return delay_import_directory_iterator( + DelayImportDirectoryEntryRef(DelayImportDirectory, 0, this)); +} + +delay_import_directory_iterator +COFFObjectFile::delay_import_directory_end() const { + return delay_import_directory_iterator( + DelayImportDirectoryEntryRef( + DelayImportDirectory, NumberOfDelayImportDirectory, this)); +} + export_directory_iterator COFFObjectFile::export_directory_begin() const { return export_directory_iterator( ExportDirectoryEntryRef(ExportDirectory, 0, this)); @@ -656,18 +799,26 @@ section_iterator COFFObjectFile::section_begin() const { section_iterator COFFObjectFile::section_end() const { DataRefImpl Ret; - int NumSections = COFFHeader->isImportLibrary() - ? 0 : COFFHeader->NumberOfSections; + int NumSections = + COFFHeader && COFFHeader->isImportLibrary() ? 0 : getNumberOfSections(); Ret.p = reinterpret_cast<uintptr_t>(SectionTable + NumSections); return section_iterator(SectionRef(Ret, this)); } +base_reloc_iterator COFFObjectFile::base_reloc_begin() const { + return base_reloc_iterator(BaseRelocRef(BaseRelocHeader, this)); +} + +base_reloc_iterator COFFObjectFile::base_reloc_end() const { + return base_reloc_iterator(BaseRelocRef(BaseRelocEnd, this)); +} + uint8_t COFFObjectFile::getBytesInAddress() const { return getArch() == Triple::x86_64 ? 8 : 4; } StringRef COFFObjectFile::getFileFormatName() const { - switch(COFFHeader->Machine) { + switch(getMachine()) { case COFF::IMAGE_FILE_MACHINE_I386: return "COFF-i386"; case COFF::IMAGE_FILE_MACHINE_AMD64: @@ -680,7 +831,7 @@ StringRef COFFObjectFile::getFileFormatName() const { } unsigned COFFObjectFile::getArch() const { - switch(COFFHeader->Machine) { + switch (getMachine()) { case COFF::IMAGE_FILE_MACHINE_I386: return Triple::x86; case COFF::IMAGE_FILE_MACHINE_AMD64: @@ -692,16 +843,24 @@ unsigned COFFObjectFile::getArch() const { } } -// This method is kept here because lld uses this. As soon as we make -// lld to use getCOFFHeader, this method will be removed. -std::error_code COFFObjectFile::getHeader(const coff_file_header *&Res) const { - return getCOFFHeader(Res); +iterator_range<import_directory_iterator> +COFFObjectFile::import_directories() const { + return make_range(import_directory_begin(), import_directory_end()); } -std::error_code -COFFObjectFile::getCOFFHeader(const coff_file_header *&Res) const { - Res = COFFHeader; - return object_error::success; +iterator_range<delay_import_directory_iterator> +COFFObjectFile::delay_import_directories() const { + return make_range(delay_import_directory_begin(), + delay_import_directory_end()); +} + +iterator_range<export_directory_iterator> +COFFObjectFile::export_directories() const { + return make_range(export_directory_begin(), export_directory_end()); +} + +iterator_range<base_reloc_iterator> COFFObjectFile::base_relocs() const { + return make_range(base_reloc_begin(), base_reloc_end()); } std::error_code COFFObjectFile::getPE32Header(const pe32_header *&Res) const { @@ -719,28 +878,32 @@ std::error_code COFFObjectFile::getDataDirectory(uint32_t Index, const data_directory *&Res) const { // Error if if there's no data directory or the index is out of range. - if (!DataDirectory) + if (!DataDirectory) { + Res = nullptr; return object_error::parse_failed; + } assert(PE32Header || PE32PlusHeader); uint32_t NumEnt = PE32Header ? PE32Header->NumberOfRvaAndSize : PE32PlusHeader->NumberOfRvaAndSize; - if (Index > NumEnt) + if (Index >= NumEnt) { + Res = nullptr; return object_error::parse_failed; + } Res = &DataDirectory[Index]; return object_error::success; } std::error_code COFFObjectFile::getSection(int32_t Index, const coff_section *&Result) const { - // Check for special index values. + Result = nullptr; if (COFF::isReservedSectionNumber(Index)) - Result = nullptr; - else if (Index > 0 && Index <= COFFHeader->NumberOfSections) + return object_error::success; + if (static_cast<uint32_t>(Index) <= getNumberOfSections()) { // We already verified the section table data, so no need to check again. Result = SectionTable + (Index - 1); - else - return object_error::parse_failed; - return object_error::success; + return object_error::success; + } + return object_error::parse_failed; } std::error_code COFFObjectFile::getString(uint32_t Offset, @@ -754,71 +917,62 @@ std::error_code COFFObjectFile::getString(uint32_t Offset, return object_error::success; } -std::error_code COFFObjectFile::getSymbol(uint32_t Index, - const coff_symbol *&Result) const { - if (Index < COFFHeader->NumberOfSymbols) - Result = SymbolTable + Index; - else - return object_error::parse_failed; - return object_error::success; -} - -std::error_code COFFObjectFile::getSymbolName(const coff_symbol *Symbol, +std::error_code COFFObjectFile::getSymbolName(COFFSymbolRef Symbol, StringRef &Res) const { // Check for string table entry. First 4 bytes are 0. - if (Symbol->Name.Offset.Zeroes == 0) { - uint32_t Offset = Symbol->Name.Offset.Offset; + if (Symbol.getStringTableOffset().Zeroes == 0) { + uint32_t Offset = Symbol.getStringTableOffset().Offset; if (std::error_code EC = getString(Offset, Res)) return EC; return object_error::success; } - if (Symbol->Name.ShortName[7] == 0) + if (Symbol.getShortName()[COFF::NameSize - 1] == 0) // Null terminated, let ::strlen figure out the length. - Res = StringRef(Symbol->Name.ShortName); + Res = StringRef(Symbol.getShortName()); else // Not null terminated, use all 8 bytes. - Res = StringRef(Symbol->Name.ShortName, 8); + Res = StringRef(Symbol.getShortName(), COFF::NameSize); return object_error::success; } -ArrayRef<uint8_t> COFFObjectFile::getSymbolAuxData( - const coff_symbol *Symbol) const { +ArrayRef<uint8_t> +COFFObjectFile::getSymbolAuxData(COFFSymbolRef Symbol) const { const uint8_t *Aux = nullptr; - if (Symbol->NumberOfAuxSymbols > 0) { - // AUX data comes immediately after the symbol in COFF - Aux = reinterpret_cast<const uint8_t *>(Symbol + 1); + size_t SymbolSize = getSymbolTableEntrySize(); + if (Symbol.getNumberOfAuxSymbols() > 0) { + // AUX data comes immediately after the symbol in COFF + Aux = reinterpret_cast<const uint8_t *>(Symbol.getRawPtr()) + SymbolSize; # ifndef NDEBUG // Verify that the Aux symbol points to a valid entry in the symbol table. uintptr_t Offset = uintptr_t(Aux) - uintptr_t(base()); - if (Offset < COFFHeader->PointerToSymbolTable - || Offset >= COFFHeader->PointerToSymbolTable - + (COFFHeader->NumberOfSymbols * sizeof(coff_symbol))) + if (Offset < getPointerToSymbolTable() || + Offset >= + getPointerToSymbolTable() + (getNumberOfSymbols() * SymbolSize)) report_fatal_error("Aux Symbol data was outside of symbol table."); - assert((Offset - COFFHeader->PointerToSymbolTable) % sizeof(coff_symbol) - == 0 && "Aux Symbol data did not point to the beginning of a symbol"); + assert((Offset - getPointerToSymbolTable()) % SymbolSize == 0 && + "Aux Symbol data did not point to the beginning of a symbol"); # endif } - return ArrayRef<uint8_t>(Aux, - Symbol->NumberOfAuxSymbols * sizeof(coff_symbol)); + return makeArrayRef(Aux, Symbol.getNumberOfAuxSymbols() * SymbolSize); } std::error_code COFFObjectFile::getSectionName(const coff_section *Sec, StringRef &Res) const { StringRef Name; - if (Sec->Name[7] == 0) + if (Sec->Name[COFF::NameSize - 1] == 0) // Null terminated, let ::strlen figure out the length. Name = Sec->Name; else // Not null terminated, use all 8 bytes. - Name = StringRef(Sec->Name, 8); + Name = StringRef(Sec->Name, COFF::NameSize); // Check for string table entry. First byte is '/'. - if (Name[0] == '/') { + if (Name.startswith("/")) { uint32_t Offset; - if (Name[1] == '/') { + if (Name.startswith("//")) { if (decodeBase64StringEntry(Name.substr(2), Offset)) return object_error::parse_failed; } else { @@ -833,18 +987,41 @@ std::error_code COFFObjectFile::getSectionName(const coff_section *Sec, return object_error::success; } +uint64_t COFFObjectFile::getSectionSize(const coff_section *Sec) const { + // SizeOfRawData and VirtualSize change what they represent depending on + // whether or not we have an executable image. + // + // For object files, SizeOfRawData contains the size of section's data; + // VirtualSize is always zero. + // + // For executables, SizeOfRawData *must* be a multiple of FileAlignment; the + // actual section size is in VirtualSize. It is possible for VirtualSize to + // be greater than SizeOfRawData; the contents past that point should be + // considered to be zero. + uint32_t SectionSize; + if (Sec->VirtualSize) + SectionSize = std::min(Sec->VirtualSize, Sec->SizeOfRawData); + else + SectionSize = Sec->SizeOfRawData; + + return SectionSize; +} + std::error_code COFFObjectFile::getSectionContents(const coff_section *Sec, ArrayRef<uint8_t> &Res) const { + // PointerToRawData and SizeOfRawData won't make sense for BSS sections, + // don't do anything interesting for them. + assert((Sec->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 && + "BSS sections don't have contents!"); // The only thing that we need to verify is that the contents is contained // within the file bounds. We don't need to make sure it doesn't cover other // data, as there's nothing that says that is not allowed. uintptr_t ConStart = uintptr_t(base()) + Sec->PointerToRawData; - uintptr_t ConEnd = ConStart + Sec->SizeOfRawData; - if (ConEnd > uintptr_t(Data->getBufferEnd())) + uint32_t SectionSize = getSectionSize(Sec); + if (checkOffset(Data, ConStart, SectionSize)) return object_error::parse_failed; - Res = ArrayRef<uint8_t>(reinterpret_cast<const unsigned char*>(ConStart), - Sec->SizeOfRawData); + Res = makeArrayRef(reinterpret_cast<const uint8_t *>(ConStart), SectionSize); return object_error::success; } @@ -864,14 +1041,26 @@ std::error_code COFFObjectFile::getRelocationAddress(DataRefImpl Rel, std::error_code COFFObjectFile::getRelocationOffset(DataRefImpl Rel, uint64_t &Res) const { - Res = toRel(Rel)->VirtualAddress; + const coff_relocation *R = toRel(Rel); + const support::ulittle32_t *VirtualAddressPtr; + if (std::error_code EC = + getObject(VirtualAddressPtr, Data, &R->VirtualAddress)) + return EC; + Res = *VirtualAddressPtr; return object_error::success; } symbol_iterator COFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const { - const coff_relocation* R = toRel(Rel); + const coff_relocation *R = toRel(Rel); DataRefImpl Ref; - Ref.p = reinterpret_cast<uintptr_t>(SymbolTable + R->SymbolTableIndex); + if (R->SymbolTableIndex >= getNumberOfSymbols()) + return symbol_end(); + if (SymbolTable16) + Ref.p = reinterpret_cast<uintptr_t>(SymbolTable16 + R->SymbolTableIndex); + else if (SymbolTable32) + Ref.p = reinterpret_cast<uintptr_t>(SymbolTable32 + R->SymbolTableIndex); + else + return symbol_end(); return symbol_iterator(SymbolRef(Ref, this)); } @@ -887,9 +1076,16 @@ COFFObjectFile::getCOFFSection(const SectionRef &Section) const { return toSec(Section.getRawDataRefImpl()); } -const coff_symbol * -COFFObjectFile::getCOFFSymbol(const SymbolRef &Symbol) const { - return toSymb(Symbol.getRawDataRefImpl()); +COFFSymbolRef COFFObjectFile::getCOFFSymbol(const DataRefImpl &Ref) const { + if (SymbolTable16) + return toSymb<coff_symbol16>(Ref); + if (SymbolTable32) + return toSymb<coff_symbol32>(Ref); + llvm_unreachable("no symbol table pointer!"); +} + +COFFSymbolRef COFFObjectFile::getCOFFSymbol(const SymbolRef &Symbol) const { + return getCOFFSymbol(Symbol.getRawDataRefImpl()); } const coff_relocation * @@ -907,7 +1103,7 @@ COFFObjectFile::getRelocationTypeName(DataRefImpl Rel, SmallVectorImpl<char> &Result) const { const coff_relocation *Reloc = toRel(Rel); StringRef Res; - switch (COFFHeader->Machine) { + switch (getMachine()) { case COFF::IMAGE_FILE_MACHINE_AMD64: switch (Reloc->Type) { LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ABSOLUTE); @@ -982,11 +1178,11 @@ std::error_code COFFObjectFile::getRelocationValueString(DataRefImpl Rel, SmallVectorImpl<char> &Result) const { const coff_relocation *Reloc = toRel(Rel); - const coff_symbol *Symb = nullptr; - if (std::error_code EC = getSymbol(Reloc->SymbolTableIndex, Symb)) - return EC; DataRefImpl Sym; - Sym.p = reinterpret_cast<uintptr_t>(Symb); + ErrorOr<COFFSymbolRef> Symb = getSymbol(Reloc->SymbolTableIndex); + if (std::error_code EC = Symb.getError()) + return EC; + Sym.p = reinterpret_cast<uintptr_t>(Symb->getRawPtr()); StringRef SymName; if (std::error_code EC = getSymbolName(Sym, SymName)) return EC; @@ -994,14 +1190,8 @@ COFFObjectFile::getRelocationValueString(DataRefImpl Rel, return object_error::success; } -std::error_code COFFObjectFile::getLibraryNext(DataRefImpl LibData, - LibraryRef &Result) const { - report_fatal_error("getLibraryNext not implemented in COFFObjectFile"); -} - -std::error_code COFFObjectFile::getLibraryPath(DataRefImpl LibData, - StringRef &Result) const { - report_fatal_error("getLibraryPath not implemented in COFFObjectFile"); +bool COFFObjectFile::isRelocatableObject() const { + return !DataDirectory; } bool ImportDirectoryEntryRef:: @@ -1015,29 +1205,148 @@ void ImportDirectoryEntryRef::moveNext() { std::error_code ImportDirectoryEntryRef::getImportTableEntry( const import_directory_table_entry *&Result) const { - Result = ImportTable; + Result = ImportTable + Index; return object_error::success; } +static imported_symbol_iterator +makeImportedSymbolIterator(const COFFObjectFile *Object, + uintptr_t Ptr, int Index) { + if (Object->getBytesInAddress() == 4) { + auto *P = reinterpret_cast<const import_lookup_table_entry32 *>(Ptr); + return imported_symbol_iterator(ImportedSymbolRef(P, Index, Object)); + } + auto *P = reinterpret_cast<const import_lookup_table_entry64 *>(Ptr); + return imported_symbol_iterator(ImportedSymbolRef(P, Index, Object)); +} + +static imported_symbol_iterator +importedSymbolBegin(uint32_t RVA, const COFFObjectFile *Object) { + uintptr_t IntPtr = 0; + Object->getRvaPtr(RVA, IntPtr); + return makeImportedSymbolIterator(Object, IntPtr, 0); +} + +static imported_symbol_iterator +importedSymbolEnd(uint32_t RVA, const COFFObjectFile *Object) { + uintptr_t IntPtr = 0; + Object->getRvaPtr(RVA, IntPtr); + // Forward the pointer to the last entry which is null. + int Index = 0; + if (Object->getBytesInAddress() == 4) { + auto *Entry = reinterpret_cast<ulittle32_t *>(IntPtr); + while (*Entry++) + ++Index; + } else { + auto *Entry = reinterpret_cast<ulittle64_t *>(IntPtr); + while (*Entry++) + ++Index; + } + return makeImportedSymbolIterator(Object, IntPtr, Index); +} + +imported_symbol_iterator +ImportDirectoryEntryRef::imported_symbol_begin() const { + return importedSymbolBegin(ImportTable[Index].ImportLookupTableRVA, + OwningObject); +} + +imported_symbol_iterator +ImportDirectoryEntryRef::imported_symbol_end() const { + return importedSymbolEnd(ImportTable[Index].ImportLookupTableRVA, + OwningObject); +} + +iterator_range<imported_symbol_iterator> +ImportDirectoryEntryRef::imported_symbols() const { + return make_range(imported_symbol_begin(), imported_symbol_end()); +} + std::error_code ImportDirectoryEntryRef::getName(StringRef &Result) const { uintptr_t IntPtr = 0; if (std::error_code EC = - OwningObject->getRvaPtr(ImportTable->NameRVA, IntPtr)) + OwningObject->getRvaPtr(ImportTable[Index].NameRVA, IntPtr)) return EC; Result = StringRef(reinterpret_cast<const char *>(IntPtr)); return object_error::success; } +std::error_code +ImportDirectoryEntryRef::getImportLookupTableRVA(uint32_t &Result) const { + Result = ImportTable[Index].ImportLookupTableRVA; + return object_error::success; +} + +std::error_code +ImportDirectoryEntryRef::getImportAddressTableRVA(uint32_t &Result) const { + Result = ImportTable[Index].ImportAddressTableRVA; + return object_error::success; +} + std::error_code ImportDirectoryEntryRef::getImportLookupEntry( const import_lookup_table_entry32 *&Result) const { uintptr_t IntPtr = 0; - if (std::error_code EC = - OwningObject->getRvaPtr(ImportTable->ImportLookupTableRVA, IntPtr)) + uint32_t RVA = ImportTable[Index].ImportLookupTableRVA; + if (std::error_code EC = OwningObject->getRvaPtr(RVA, IntPtr)) return EC; Result = reinterpret_cast<const import_lookup_table_entry32 *>(IntPtr); return object_error::success; } +bool DelayImportDirectoryEntryRef:: +operator==(const DelayImportDirectoryEntryRef &Other) const { + return Table == Other.Table && Index == Other.Index; +} + +void DelayImportDirectoryEntryRef::moveNext() { + ++Index; +} + +imported_symbol_iterator +DelayImportDirectoryEntryRef::imported_symbol_begin() const { + return importedSymbolBegin(Table[Index].DelayImportNameTable, + OwningObject); +} + +imported_symbol_iterator +DelayImportDirectoryEntryRef::imported_symbol_end() const { + return importedSymbolEnd(Table[Index].DelayImportNameTable, + OwningObject); +} + +iterator_range<imported_symbol_iterator> +DelayImportDirectoryEntryRef::imported_symbols() const { + return make_range(imported_symbol_begin(), imported_symbol_end()); +} + +std::error_code DelayImportDirectoryEntryRef::getName(StringRef &Result) const { + uintptr_t IntPtr = 0; + if (std::error_code EC = OwningObject->getRvaPtr(Table[Index].Name, IntPtr)) + return EC; + Result = StringRef(reinterpret_cast<const char *>(IntPtr)); + return object_error::success; +} + +std::error_code DelayImportDirectoryEntryRef:: +getDelayImportTable(const delay_import_directory_table_entry *&Result) const { + Result = Table; + return object_error::success; +} + +std::error_code DelayImportDirectoryEntryRef:: +getImportAddress(int AddrIndex, uint64_t &Result) const { + uint32_t RVA = Table[Index].DelayImportAddressTable + + AddrIndex * (OwningObject->is64() ? 8 : 4); + uintptr_t IntPtr = 0; + if (std::error_code EC = OwningObject->getRvaPtr(RVA, IntPtr)) + return EC; + if (OwningObject->is64()) + Result = *reinterpret_cast<const ulittle64_t *>(IntPtr); + else + Result = *reinterpret_cast<const ulittle32_t *>(IntPtr); + return object_error::success; +} + bool ExportDirectoryEntryRef:: operator==(const ExportDirectoryEntryRef &Other) const { return ExportTable == Other.ExportTable && Index == Other.Index; @@ -1112,12 +1421,98 @@ ExportDirectoryEntryRef::getSymbolName(StringRef &Result) const { return object_error::success; } -ErrorOr<ObjectFile *> -ObjectFile::createCOFFObjectFile(std::unique_ptr<MemoryBuffer> Object) { +bool ImportedSymbolRef:: +operator==(const ImportedSymbolRef &Other) const { + return Entry32 == Other.Entry32 && Entry64 == Other.Entry64 + && Index == Other.Index; +} + +void ImportedSymbolRef::moveNext() { + ++Index; +} + +std::error_code +ImportedSymbolRef::getSymbolName(StringRef &Result) const { + uint32_t RVA; + if (Entry32) { + // If a symbol is imported only by ordinal, it has no name. + if (Entry32[Index].isOrdinal()) + return object_error::success; + RVA = Entry32[Index].getHintNameRVA(); + } else { + if (Entry64[Index].isOrdinal()) + return object_error::success; + RVA = Entry64[Index].getHintNameRVA(); + } + uintptr_t IntPtr = 0; + if (std::error_code EC = OwningObject->getRvaPtr(RVA, IntPtr)) + return EC; + // +2 because the first two bytes is hint. + Result = StringRef(reinterpret_cast<const char *>(IntPtr + 2)); + return object_error::success; +} + +std::error_code ImportedSymbolRef::getOrdinal(uint16_t &Result) const { + uint32_t RVA; + if (Entry32) { + if (Entry32[Index].isOrdinal()) { + Result = Entry32[Index].getOrdinal(); + return object_error::success; + } + RVA = Entry32[Index].getHintNameRVA(); + } else { + if (Entry64[Index].isOrdinal()) { + Result = Entry64[Index].getOrdinal(); + return object_error::success; + } + RVA = Entry64[Index].getHintNameRVA(); + } + uintptr_t IntPtr = 0; + if (std::error_code EC = OwningObject->getRvaPtr(RVA, IntPtr)) + return EC; + Result = *reinterpret_cast<const ulittle16_t *>(IntPtr); + return object_error::success; +} + +ErrorOr<std::unique_ptr<COFFObjectFile>> +ObjectFile::createCOFFObjectFile(MemoryBufferRef Object) { std::error_code EC; - std::unique_ptr<COFFObjectFile> Ret( - new COFFObjectFile(std::move(Object), EC)); + std::unique_ptr<COFFObjectFile> Ret(new COFFObjectFile(Object, EC)); if (EC) return EC; - return Ret.release(); + return std::move(Ret); +} + +bool BaseRelocRef::operator==(const BaseRelocRef &Other) const { + return Header == Other.Header && Index == Other.Index; +} + +void BaseRelocRef::moveNext() { + // Header->BlockSize is the size of the current block, including the + // size of the header itself. + uint32_t Size = sizeof(*Header) + + sizeof(coff_base_reloc_block_entry) * (Index + 1); + if (Size == Header->BlockSize) { + // .reloc contains a list of base relocation blocks. Each block + // consists of the header followed by entries. The header contains + // how many entories will follow. When we reach the end of the + // current block, proceed to the next block. + Header = reinterpret_cast<const coff_base_reloc_block_header *>( + reinterpret_cast<const uint8_t *>(Header) + Size); + Index = 0; + } else { + ++Index; + } +} + +std::error_code BaseRelocRef::getType(uint8_t &Type) const { + auto *Entry = reinterpret_cast<const coff_base_reloc_block_entry *>(Header + 1); + Type = Entry[Index].getType(); + return object_error::success; +} + +std::error_code BaseRelocRef::getRVA(uint32_t &Result) const { + auto *Entry = reinterpret_cast<const coff_base_reloc_block_entry *>(Header + 1); + Result = Header->PageRVA + Entry[Index].getOffset(); + return object_error::success; } diff --git a/lib/Object/COFFYAML.cpp b/lib/Object/COFFYAML.cpp index 49c5dda..9a24b53 100644 --- a/lib/Object/COFFYAML.cpp +++ b/lib/Object/COFFYAML.cpp @@ -168,6 +168,24 @@ void ScalarEnumerationTraits<COFF::RelocationTypeAMD64>::enumeration( ECase(IMAGE_REL_AMD64_PAIR); ECase(IMAGE_REL_AMD64_SSPAN32); } + +void ScalarEnumerationTraits<COFF::WindowsSubsystem>::enumeration( + IO &IO, COFF::WindowsSubsystem &Value) { + ECase(IMAGE_SUBSYSTEM_UNKNOWN); + ECase(IMAGE_SUBSYSTEM_NATIVE); + ECase(IMAGE_SUBSYSTEM_WINDOWS_GUI); + ECase(IMAGE_SUBSYSTEM_WINDOWS_CUI); + ECase(IMAGE_SUBSYSTEM_OS2_CUI); + ECase(IMAGE_SUBSYSTEM_POSIX_CUI); + ECase(IMAGE_SUBSYSTEM_NATIVE_WINDOWS); + ECase(IMAGE_SUBSYSTEM_WINDOWS_CE_GUI); + ECase(IMAGE_SUBSYSTEM_EFI_APPLICATION); + ECase(IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER); + ECase(IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER); + ECase(IMAGE_SUBSYSTEM_EFI_ROM); + ECase(IMAGE_SUBSYSTEM_XBOX); + ECase(IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION); +} #undef ECase #define BCase(X) IO.bitSetCase(Value, #X, COFF::X); @@ -214,6 +232,21 @@ void ScalarBitSetTraits<COFF::SectionCharacteristics>::bitset( BCase(IMAGE_SCN_MEM_READ); BCase(IMAGE_SCN_MEM_WRITE); } + +void ScalarBitSetTraits<COFF::DLLCharacteristics>::bitset( + IO &IO, COFF::DLLCharacteristics &Value) { + BCase(IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA); + BCase(IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE); + BCase(IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY); + BCase(IMAGE_DLL_CHARACTERISTICS_NX_COMPAT); + BCase(IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION); + BCase(IMAGE_DLL_CHARACTERISTICS_NO_SEH); + BCase(IMAGE_DLL_CHARACTERISTICS_NO_BIND); + BCase(IMAGE_DLL_CHARACTERISTICS_APPCONTAINER); + BCase(IMAGE_DLL_CHARACTERISTICS_WDM_DRIVER); + BCase(IMAGE_DLL_CHARACTERISTICS_GUARD_CF); + BCase(IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE); +} #undef BCase namespace { @@ -285,6 +318,23 @@ struct NType { RelocType Type; }; +struct NWindowsSubsystem { + NWindowsSubsystem(IO &) : Subsystem(COFF::WindowsSubsystem(0)) {} + NWindowsSubsystem(IO &, uint16_t C) : Subsystem(COFF::WindowsSubsystem(C)) {} + uint16_t denormalize(IO &) { return Subsystem; } + + COFF::WindowsSubsystem Subsystem; +}; + +struct NDLLCharacteristics { + NDLLCharacteristics(IO &) : Characteristics(COFF::DLLCharacteristics(0)) {} + NDLLCharacteristics(IO &, uint16_t C) + : Characteristics(COFF::DLLCharacteristics(C)) {} + uint16_t denormalize(IO &) { return Characteristics; } + + COFF::DLLCharacteristics Characteristics; +}; + } void MappingTraits<COFFYAML::Relocation>::mapping(IO &IO, @@ -306,6 +356,59 @@ void MappingTraits<COFFYAML::Relocation>::mapping(IO &IO, } } +void MappingTraits<COFF::DataDirectory>::mapping(IO &IO, + COFF::DataDirectory &DD) { + IO.mapRequired("RelativeVirtualAddress", DD.RelativeVirtualAddress); + IO.mapRequired("Size", DD.Size); +} + +void MappingTraits<COFFYAML::PEHeader>::mapping(IO &IO, + COFFYAML::PEHeader &PH) { + MappingNormalization<NWindowsSubsystem, uint16_t> NWS(IO, + PH.Header.Subsystem); + MappingNormalization<NDLLCharacteristics, uint16_t> NDC( + IO, PH.Header.DLLCharacteristics); + + IO.mapRequired("AddressOfEntryPoint", PH.Header.AddressOfEntryPoint); + IO.mapRequired("ImageBase", PH.Header.ImageBase); + IO.mapRequired("SectionAlignment", PH.Header.SectionAlignment); + IO.mapRequired("FileAlignment", PH.Header.FileAlignment); + IO.mapRequired("MajorOperatingSystemVersion", + PH.Header.MajorOperatingSystemVersion); + IO.mapRequired("MinorOperatingSystemVersion", + PH.Header.MinorOperatingSystemVersion); + IO.mapRequired("MajorImageVersion", PH.Header.MajorImageVersion); + IO.mapRequired("MinorImageVersion", PH.Header.MinorImageVersion); + IO.mapRequired("MajorSubsystemVersion", PH.Header.MajorSubsystemVersion); + IO.mapRequired("MinorSubsystemVersion", PH.Header.MinorSubsystemVersion); + IO.mapRequired("Subsystem", NWS->Subsystem); + IO.mapRequired("DLLCharacteristics", NDC->Characteristics); + IO.mapRequired("SizeOfStackReserve", PH.Header.SizeOfStackReserve); + IO.mapRequired("SizeOfStackCommit", PH.Header.SizeOfStackCommit); + IO.mapRequired("SizeOfHeapReserve", PH.Header.SizeOfHeapReserve); + IO.mapRequired("SizeOfHeapCommit", PH.Header.SizeOfHeapCommit); + + IO.mapOptional("ExportTable", PH.DataDirectories[COFF::EXPORT_TABLE]); + IO.mapOptional("ImportTable", PH.DataDirectories[COFF::IMPORT_TABLE]); + IO.mapOptional("ResourceTable", PH.DataDirectories[COFF::RESOURCE_TABLE]); + IO.mapOptional("ExceptionTable", PH.DataDirectories[COFF::EXCEPTION_TABLE]); + IO.mapOptional("CertificateTable", PH.DataDirectories[COFF::CERTIFICATE_TABLE]); + IO.mapOptional("BaseRelocationTable", + PH.DataDirectories[COFF::BASE_RELOCATION_TABLE]); + IO.mapOptional("Debug", PH.DataDirectories[COFF::DEBUG]); + IO.mapOptional("Architecture", PH.DataDirectories[COFF::ARCHITECTURE]); + IO.mapOptional("GlobalPtr", PH.DataDirectories[COFF::GLOBAL_PTR]); + IO.mapOptional("TlsTable", PH.DataDirectories[COFF::TLS_TABLE]); + IO.mapOptional("LoadConfigTable", + PH.DataDirectories[COFF::LOAD_CONFIG_TABLE]); + IO.mapOptional("BoundImport", PH.DataDirectories[COFF::BOUND_IMPORT]); + IO.mapOptional("IAT", PH.DataDirectories[COFF::IAT]); + IO.mapOptional("DelayImportDescriptor", + PH.DataDirectories[COFF::DELAY_IMPORT_DESCRIPTOR]); + IO.mapOptional("ClrRuntimeHeader", + PH.DataDirectories[COFF::CLR_RUNTIME_HEADER]); +} + void MappingTraits<COFF::header>::mapping(IO &IO, COFF::header &H) { MappingNormalization<NMachine, uint16_t> NM(IO, H.Machine); MappingNormalization<NHeaderCharacteristics, uint16_t> NC(IO, @@ -380,12 +483,15 @@ void MappingTraits<COFFYAML::Section>::mapping(IO &IO, COFFYAML::Section &Sec) { IO, Sec.Header.Characteristics); IO.mapRequired("Name", Sec.Name); IO.mapRequired("Characteristics", NC->Characteristics); + IO.mapOptional("VirtualAddress", Sec.Header.VirtualAddress, 0U); + IO.mapOptional("VirtualSize", Sec.Header.VirtualSize, 0U); IO.mapOptional("Alignment", Sec.Alignment); IO.mapRequired("SectionData", Sec.SectionData); IO.mapOptional("Relocations", Sec.Relocations); } void MappingTraits<COFFYAML::Object>::mapping(IO &IO, COFFYAML::Object &Obj) { + IO.mapOptional("OptionalHeader", Obj.OptionalHeader); IO.mapRequired("header", Obj.Header); IO.mapRequired("sections", Obj.Sections); IO.mapRequired("symbols", Obj.Symbols); diff --git a/lib/Object/ELF.cpp b/lib/Object/ELF.cpp index df4dd5e..11099bd 100644 --- a/lib/Object/ELF.cpp +++ b/lib/Object/ELF.cpp @@ -223,6 +223,8 @@ StringRef getELFRelocationTypeName(uint32_t Machine, uint32_t Type) { LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_AARCH64_LDST32_ABS_LO12_NC); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_AARCH64_LDST64_ABS_LO12_NC); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_AARCH64_LDST128_ABS_LO12_NC); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_AARCH64_GOTREL64); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_AARCH64_GOTREL32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_AARCH64_ADR_GOT_PAGE); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_AARCH64_LD64_GOT_LO12_NC); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_AARCH64_TLSLD_MOVW_DTPREL_G2); @@ -266,6 +268,15 @@ StringRef getELFRelocationTypeName(uint32_t Machine, uint32_t Type) { LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_AARCH64_TLSDESC_LD64_LO12_NC); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_AARCH64_TLSDESC_ADD_LO12_NC); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_AARCH64_TLSDESC_CALL); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_AARCH64_COPY); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_AARCH64_GLOB_DAT); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_AARCH64_JUMP_SLOT); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_AARCH64_RELATIVE); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_AARCH64_TLS_DTPREL64); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_AARCH64_TLS_DTPMOD64); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_AARCH64_TLS_TPREL64); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_AARCH64_TLSDESC); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_AARCH64_IRELATIVE); default: break; } @@ -519,6 +530,7 @@ StringRef getELFRelocationTypeName(uint32_t Machine, uint32_t Type) { LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_PPC_GOT16_LO); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_PPC_GOT16_HI); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_PPC_GOT16_HA); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_PPC_PLTREL24); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_PPC_REL32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_PPC_TLS); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_PPC_DTPMOD32); diff --git a/lib/Object/ELFObjectFile.cpp b/lib/Object/ELFObjectFile.cpp index 4f0f60b..8ccb253 100644 --- a/lib/Object/ELFObjectFile.cpp +++ b/lib/Object/ELFObjectFile.cpp @@ -17,61 +17,56 @@ namespace llvm { using namespace object; -ErrorOr<ObjectFile *> -ObjectFile::createELFObjectFile(std::unique_ptr<MemoryBuffer> &Obj) { +ELFObjectFileBase::ELFObjectFileBase(unsigned int Type, MemoryBufferRef Source) + : ObjectFile(Type, Source) {} + +ErrorOr<std::unique_ptr<ObjectFile>> +ObjectFile::createELFObjectFile(MemoryBufferRef Obj) { std::pair<unsigned char, unsigned char> Ident = - getElfArchType(Obj->getBuffer()); + getElfArchType(Obj.getBuffer()); std::size_t MaxAlignment = - 1ULL << countTrailingZeros(uintptr_t(Obj->getBufferStart())); + 1ULL << countTrailingZeros(uintptr_t(Obj.getBufferStart())); std::error_code EC; std::unique_ptr<ObjectFile> R; if (Ident.first == ELF::ELFCLASS32 && Ident.second == ELF::ELFDATA2LSB) #if !LLVM_IS_UNALIGNED_ACCESS_FAST if (MaxAlignment >= 4) - R.reset(new ELFObjectFile<ELFType<support::little, 4, false>>( - std::move(Obj), EC)); + R.reset(new ELFObjectFile<ELFType<support::little, 4, false>>(Obj, EC)); else #endif if (MaxAlignment >= 2) - R.reset(new ELFObjectFile<ELFType<support::little, 2, false>>( - std::move(Obj), EC)); + R.reset(new ELFObjectFile<ELFType<support::little, 2, false>>(Obj, EC)); else return object_error::parse_failed; else if (Ident.first == ELF::ELFCLASS32 && Ident.second == ELF::ELFDATA2MSB) #if !LLVM_IS_UNALIGNED_ACCESS_FAST if (MaxAlignment >= 4) - R.reset(new ELFObjectFile<ELFType<support::big, 4, false>>(std::move(Obj), - EC)); + R.reset(new ELFObjectFile<ELFType<support::big, 4, false>>(Obj, EC)); else #endif if (MaxAlignment >= 2) - R.reset(new ELFObjectFile<ELFType<support::big, 2, false>>(std::move(Obj), - EC)); + R.reset(new ELFObjectFile<ELFType<support::big, 2, false>>(Obj, EC)); else return object_error::parse_failed; else if (Ident.first == ELF::ELFCLASS64 && Ident.second == ELF::ELFDATA2MSB) #if !LLVM_IS_UNALIGNED_ACCESS_FAST if (MaxAlignment >= 8) - R.reset(new ELFObjectFile<ELFType<support::big, 8, true>>(std::move(Obj), - EC)); + R.reset(new ELFObjectFile<ELFType<support::big, 8, true>>(Obj, EC)); else #endif if (MaxAlignment >= 2) - R.reset(new ELFObjectFile<ELFType<support::big, 2, true>>(std::move(Obj), - EC)); + R.reset(new ELFObjectFile<ELFType<support::big, 2, true>>(Obj, EC)); else return object_error::parse_failed; else if (Ident.first == ELF::ELFCLASS64 && Ident.second == ELF::ELFDATA2LSB) { #if !LLVM_IS_UNALIGNED_ACCESS_FAST if (MaxAlignment >= 8) - R.reset(new ELFObjectFile<ELFType<support::little, 8, true>>( - std::move(Obj), EC)); + R.reset(new ELFObjectFile<ELFType<support::little, 8, true>>(Obj, EC)); else #endif if (MaxAlignment >= 2) - R.reset(new ELFObjectFile<ELFType<support::little, 2, true>>( - std::move(Obj), EC)); + R.reset(new ELFObjectFile<ELFType<support::little, 2, true>>(Obj, EC)); else return object_error::parse_failed; } @@ -80,7 +75,7 @@ ObjectFile::createELFObjectFile(std::unique_ptr<MemoryBuffer> &Obj) { if (EC) return EC; - return R.release(); + return std::move(R); } } // end namespace llvm diff --git a/lib/Object/ELFYAML.cpp b/lib/Object/ELFYAML.cpp index dc3d467..f513c11 100644 --- a/lib/Object/ELFYAML.cpp +++ b/lib/Object/ELFYAML.cpp @@ -264,6 +264,7 @@ void ScalarBitSetTraits<ELFYAML::ELF_EF>::bitset(IO &IO, BCase(EF_MIPS_CPIC) BCase(EF_MIPS_ABI2) BCase(EF_MIPS_32BITMODE) + BCase(EF_MIPS_NAN2008) BCase(EF_MIPS_ABI_O32) BCase(EF_MIPS_MICROMIPS) BCase(EF_MIPS_ARCH_ASE_M16) @@ -298,6 +299,8 @@ void ScalarBitSetTraits<ELFYAML::ELF_EF>::bitset(IO &IO, void ScalarEnumerationTraits<ELFYAML::ELF_SHT>::enumeration( IO &IO, ELFYAML::ELF_SHT &Value) { + const auto *Object = static_cast<ELFYAML::Object *>(IO.getContext()); + assert(Object && "The IO context is not initialized"); #define ECase(X) IO.enumCase(Value, #X, ELF::X); ECase(SHT_NULL) ECase(SHT_PROGBITS) @@ -325,15 +328,29 @@ void ScalarEnumerationTraits<ELFYAML::ELF_SHT>::enumeration( ECase(SHT_GNU_versym) ECase(SHT_HIOS) ECase(SHT_LOPROC) - ECase(SHT_ARM_EXIDX) - ECase(SHT_ARM_PREEMPTMAP) - ECase(SHT_ARM_ATTRIBUTES) - ECase(SHT_ARM_DEBUGOVERLAY) - ECase(SHT_ARM_OVERLAYSECTION) - ECase(SHT_HEX_ORDERED) - ECase(SHT_X86_64_UNWIND) - ECase(SHT_MIPS_REGINFO) - ECase(SHT_MIPS_OPTIONS) + switch (Object->Header.Machine) { + case ELF::EM_ARM: + ECase(SHT_ARM_EXIDX) + ECase(SHT_ARM_PREEMPTMAP) + ECase(SHT_ARM_ATTRIBUTES) + ECase(SHT_ARM_DEBUGOVERLAY) + ECase(SHT_ARM_OVERLAYSECTION) + break; + case ELF::EM_HEXAGON: + ECase(SHT_HEX_ORDERED) + break; + case ELF::EM_X86_64: + ECase(SHT_X86_64_UNWIND) + break; + case ELF::EM_MIPS: + ECase(SHT_MIPS_REGINFO) + ECase(SHT_MIPS_OPTIONS) + ECase(SHT_MIPS_ABIFLAGS) + break; + default: + // Nothing to do. + break; + } #undef ECase } @@ -378,6 +395,25 @@ void ScalarEnumerationTraits<ELFYAML::ELF_STV>::enumeration( #undef ECase } +void ScalarBitSetTraits<ELFYAML::ELF_STO>::bitset(IO &IO, + ELFYAML::ELF_STO &Value) { + const auto *Object = static_cast<ELFYAML::Object *>(IO.getContext()); + assert(Object && "The IO context is not initialized"); +#define BCase(X) IO.bitSetCase(Value, #X, ELF::X); + switch (Object->Header.Machine) { + case ELF::EM_MIPS: + BCase(STO_MIPS_OPTIONAL) + BCase(STO_MIPS_PLT) + BCase(STO_MIPS_PIC) + BCase(STO_MIPS_MICROMIPS) + break; + default: + break; // Nothing to do + } +#undef BCase +#undef BCaseMask +} + void ScalarEnumerationTraits<ELFYAML::ELF_REL>::enumeration( IO &IO, ELFYAML::ELF_REL &Value) { const auto *Object = static_cast<ELFYAML::Object *>(IO.getContext()); @@ -636,6 +672,92 @@ void ScalarEnumerationTraits<ELFYAML::ELF_REL>::enumeration( ECase(R_386_IRELATIVE) ECase(R_386_NUM) break; + case ELF::EM_AARCH64: + ECase(R_AARCH64_NONE) + ECase(R_AARCH64_ABS64) + ECase(R_AARCH64_ABS32) + ECase(R_AARCH64_ABS16) + ECase(R_AARCH64_PREL64) + ECase(R_AARCH64_PREL32) + ECase(R_AARCH64_PREL16) + ECase(R_AARCH64_MOVW_UABS_G0) + ECase(R_AARCH64_MOVW_UABS_G0_NC) + ECase(R_AARCH64_MOVW_UABS_G1) + ECase(R_AARCH64_MOVW_UABS_G1_NC) + ECase(R_AARCH64_MOVW_UABS_G2) + ECase(R_AARCH64_MOVW_UABS_G2_NC) + ECase(R_AARCH64_MOVW_UABS_G3) + ECase(R_AARCH64_MOVW_SABS_G0) + ECase(R_AARCH64_MOVW_SABS_G1) + ECase(R_AARCH64_MOVW_SABS_G2) + ECase(R_AARCH64_LD_PREL_LO19) + ECase(R_AARCH64_ADR_PREL_LO21) + ECase(R_AARCH64_ADR_PREL_PG_HI21) + ECase(R_AARCH64_ADD_ABS_LO12_NC) + ECase(R_AARCH64_LDST8_ABS_LO12_NC) + ECase(R_AARCH64_TSTBR14) + ECase(R_AARCH64_CONDBR19) + ECase(R_AARCH64_JUMP26) + ECase(R_AARCH64_CALL26) + ECase(R_AARCH64_LDST16_ABS_LO12_NC) + ECase(R_AARCH64_LDST32_ABS_LO12_NC) + ECase(R_AARCH64_LDST64_ABS_LO12_NC) + ECase(R_AARCH64_LDST128_ABS_LO12_NC) + ECase(R_AARCH64_GOTREL64) + ECase(R_AARCH64_GOTREL32) + ECase(R_AARCH64_ADR_GOT_PAGE) + ECase(R_AARCH64_LD64_GOT_LO12_NC) + ECase(R_AARCH64_TLSLD_MOVW_DTPREL_G2) + ECase(R_AARCH64_TLSLD_MOVW_DTPREL_G1) + ECase(R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC) + ECase(R_AARCH64_TLSLD_MOVW_DTPREL_G0) + ECase(R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC) + ECase(R_AARCH64_TLSLD_ADD_DTPREL_HI12) + ECase(R_AARCH64_TLSLD_ADD_DTPREL_LO12) + ECase(R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC) + ECase(R_AARCH64_TLSLD_LDST8_DTPREL_LO12) + ECase(R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC) + ECase(R_AARCH64_TLSLD_LDST16_DTPREL_LO12) + ECase(R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC) + ECase(R_AARCH64_TLSLD_LDST32_DTPREL_LO12) + ECase(R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC) + ECase(R_AARCH64_TLSLD_LDST64_DTPREL_LO12) + ECase(R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC) + ECase(R_AARCH64_TLSIE_MOVW_GOTTPREL_G1) + ECase(R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC) + ECase(R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) + ECase(R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC) + ECase(R_AARCH64_TLSIE_LD_GOTTPREL_PREL19) + ECase(R_AARCH64_TLSLE_MOVW_TPREL_G2) + ECase(R_AARCH64_TLSLE_MOVW_TPREL_G1) + ECase(R_AARCH64_TLSLE_MOVW_TPREL_G1_NC) + ECase(R_AARCH64_TLSLE_MOVW_TPREL_G0) + ECase(R_AARCH64_TLSLE_MOVW_TPREL_G0_NC) + ECase(R_AARCH64_TLSLE_ADD_TPREL_HI12) + ECase(R_AARCH64_TLSLE_ADD_TPREL_LO12) + ECase(R_AARCH64_TLSLE_ADD_TPREL_LO12_NC) + ECase(R_AARCH64_TLSLE_LDST8_TPREL_LO12) + ECase(R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC) + ECase(R_AARCH64_TLSLE_LDST16_TPREL_LO12) + ECase(R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC) + ECase(R_AARCH64_TLSLE_LDST32_TPREL_LO12) + ECase(R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC) + ECase(R_AARCH64_TLSLE_LDST64_TPREL_LO12) + ECase(R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC) + ECase(R_AARCH64_TLSDESC_ADR_PAGE) + ECase(R_AARCH64_TLSDESC_LD64_LO12_NC) + ECase(R_AARCH64_TLSDESC_ADD_LO12_NC) + ECase(R_AARCH64_TLSDESC_CALL) + ECase(R_AARCH64_COPY) + ECase(R_AARCH64_GLOB_DAT) + ECase(R_AARCH64_JUMP_SLOT) + ECase(R_AARCH64_RELATIVE) + ECase(R_AARCH64_TLS_DTPREL64) + ECase(R_AARCH64_TLS_DTPMOD64) + ECase(R_AARCH64_TLS_TPREL64) + ECase(R_AARCH64_TLSDESC) + ECase(R_AARCH64_IRELATIVE) + break; default: llvm_unreachable("Unsupported architecture"); } @@ -653,13 +775,30 @@ void MappingTraits<ELFYAML::FileHeader>::mapping(IO &IO, IO.mapOptional("Entry", FileHdr.Entry, Hex64(0)); } +namespace { +struct NormalizedOther { + NormalizedOther(IO &) + : Visibility(ELFYAML::ELF_STV(0)), Other(ELFYAML::ELF_STO(0)) {} + NormalizedOther(IO &, uint8_t Original) + : Visibility(Original & 0x3), Other(Original & ~0x3) {} + + uint8_t denormalize(IO &) { return Visibility | Other; } + + ELFYAML::ELF_STV Visibility; + ELFYAML::ELF_STO Other; +}; +} + void MappingTraits<ELFYAML::Symbol>::mapping(IO &IO, ELFYAML::Symbol &Symbol) { IO.mapOptional("Name", Symbol.Name, StringRef()); IO.mapOptional("Type", Symbol.Type, ELFYAML::ELF_STT(0)); IO.mapOptional("Section", Symbol.Section, StringRef()); IO.mapOptional("Value", Symbol.Value, Hex64(0)); IO.mapOptional("Size", Symbol.Size, Hex64(0)); - IO.mapOptional("Visibility", Symbol.Visibility, ELFYAML::ELF_STV(0)); + + MappingNormalization<NormalizedOther, uint8_t> Keys(IO, Symbol.Other); + IO.mapOptional("Visibility", Keys->Visibility, ELFYAML::ELF_STV(0)); + IO.mapOptional("Other", Keys->Other, ELFYAML::ELF_STO(0)); } void MappingTraits<ELFYAML::LocalGlobalWeakSymbols>::mapping( diff --git a/lib/Object/Error.cpp b/lib/Object/Error.cpp index 9d25269..d2daab7 100644 --- a/lib/Object/Error.cpp +++ b/lib/Object/Error.cpp @@ -13,6 +13,7 @@ #include "llvm/Object/Error.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ManagedStatic.h" using namespace llvm; using namespace object; @@ -25,7 +26,7 @@ public: }; } -const char *_object_error_category::name() const { +const char *_object_error_category::name() const LLVM_NOEXCEPT { return "llvm.object"; } @@ -41,12 +42,15 @@ std::string _object_error_category::message(int EV) const { return "Invalid data was encountered while parsing the file"; case object_error::unexpected_eof: return "The end of the file was unexpectedly encountered"; + case object_error::bitcode_section_not_found: + return "Bitcode section not found in object file"; } llvm_unreachable("An enumerator of object_error does not have a message " "defined."); } +static ManagedStatic<_object_error_category> error_category; + const std::error_category &object::object_category() { - static _object_error_category o; - return o; + return *error_category; } diff --git a/lib/Object/IRObjectFile.cpp b/lib/Object/IRObjectFile.cpp index 5323d92..7256a2f 100644 --- a/lib/Object/IRObjectFile.cpp +++ b/lib/Object/IRObjectFile.cpp @@ -25,6 +25,7 @@ #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCTargetAsmParser.h" #include "llvm/MC/MCParser/MCAsmParser.h" +#include "llvm/Object/ObjectFile.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetRegistry.h" @@ -32,9 +33,8 @@ using namespace llvm; using namespace object; -IRObjectFile::IRObjectFile(std::unique_ptr<MemoryBuffer> Object, - std::unique_ptr<Module> Mod) - : SymbolicFile(Binary::ID_IR, std::move(Object)), M(std::move(Mod)) { +IRObjectFile::IRObjectFile(MemoryBufferRef Object, std::unique_ptr<Module> Mod) + : SymbolicFile(Binary::ID_IR, Object), M(std::move(Mod)) { // If we have a DataLayout, setup a mangler. const DataLayout *DL = M->getDataLayout(); if (!DL) @@ -76,7 +76,7 @@ IRObjectFile::IRObjectFile(std::unique_ptr<MemoryBuffer> Object, std::unique_ptr<MemoryBuffer> Buffer(MemoryBuffer::getMemBuffer(InlineAsm)); SourceMgr SrcMgr; - SrcMgr.AddNewSourceBuffer(Buffer.release(), SMLoc()); + SrcMgr.AddNewSourceBuffer(std::move(Buffer), SMLoc()); std::unique_ptr<MCAsmParser> Parser( createMCAsmParser(SrcMgr, MCCtx, *Streamer, *MAI)); @@ -114,9 +114,6 @@ IRObjectFile::IRObjectFile(std::unique_ptr<MemoryBuffer> Object, } IRObjectFile::~IRObjectFile() { - GVMaterializer *GVM = M->getMaterializer(); - if (GVM) - GVM->releaseBuffer(); } static const GlobalValue *getGV(DataRefImpl &Symb) { @@ -207,16 +204,6 @@ std::error_code IRObjectFile::printSymbolName(raw_ostream &OS, return object_error::success; } -static bool isDeclaration(const GlobalValue &V) { - if (V.hasAvailableExternallyLinkage()) - return true; - - if (V.isMaterializable()) - return false; - - return V.isDeclaration(); -} - uint32_t IRObjectFile::getSymbolFlags(DataRefImpl Symb) const { const GlobalValue *GV = getGV(Symb); @@ -227,7 +214,7 @@ uint32_t IRObjectFile::getSymbolFlags(DataRefImpl Symb) const { } uint32_t Res = BasicSymbolRef::SF_None; - if (isDeclaration(*GV)) + if (GV->isDeclarationForLinker()) Res |= BasicSymbolRef::SF_Undefined; if (GV->hasPrivateLinkage()) Res |= BasicSymbolRef::SF_FormatSpecific; @@ -268,12 +255,55 @@ basic_symbol_iterator IRObjectFile::symbol_end_impl() const { return basic_symbol_iterator(BasicSymbolRef(Ret, this)); } -ErrorOr<IRObjectFile *> llvm::object::IRObjectFile::createIRObjectFile( - std::unique_ptr<MemoryBuffer> Object, LLVMContext &Context) { - ErrorOr<Module *> MOrErr = getLazyBitcodeModule(Object.get(), Context); +ErrorOr<MemoryBufferRef> IRObjectFile::findBitcodeInObject(const ObjectFile &Obj) { + for (const SectionRef &Sec : Obj.sections()) { + StringRef SecName; + if (std::error_code EC = Sec.getName(SecName)) + return EC; + if (SecName == ".llvmbc") { + StringRef SecContents; + if (std::error_code EC = Sec.getContents(SecContents)) + return EC; + return MemoryBufferRef(SecContents, Obj.getFileName()); + } + } + + return object_error::bitcode_section_not_found; +} + +ErrorOr<MemoryBufferRef> IRObjectFile::findBitcodeInMemBuffer(MemoryBufferRef Object) { + sys::fs::file_magic Type = sys::fs::identify_magic(Object.getBuffer()); + switch (Type) { + case sys::fs::file_magic::bitcode: + return Object; + case sys::fs::file_magic::elf_relocatable: + case sys::fs::file_magic::macho_object: + case sys::fs::file_magic::coff_object: { + ErrorOr<std::unique_ptr<ObjectFile>> ObjFile = + ObjectFile::createObjectFile(Object, Type); + if (!ObjFile) + return ObjFile.getError(); + return findBitcodeInObject(*ObjFile->get()); + } + default: + return object_error::invalid_file_type; + } +} + +ErrorOr<std::unique_ptr<IRObjectFile>> +llvm::object::IRObjectFile::createIRObjectFile(MemoryBufferRef Object, + LLVMContext &Context) { + ErrorOr<MemoryBufferRef> BCOrErr = findBitcodeInMemBuffer(Object); + if (!BCOrErr) + return BCOrErr.getError(); + + std::unique_ptr<MemoryBuffer> Buff( + MemoryBuffer::getMemBuffer(BCOrErr.get(), false)); + + ErrorOr<Module *> MOrErr = getLazyBitcodeModule(std::move(Buff), Context); if (std::error_code EC = MOrErr.getError()) return EC; std::unique_ptr<Module> M(MOrErr.get()); - return new IRObjectFile(std::move(Object), std::move(M)); + return llvm::make_unique<IRObjectFile>(Object, std::move(M)); } diff --git a/lib/Object/LLVMBuild.txt b/lib/Object/LLVMBuild.txt index 8acacba..bae578c 100644 --- a/lib/Object/LLVMBuild.txt +++ b/lib/Object/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Library name = Object parent = Libraries -required_libraries = BitReader Core Support MC MCParser +required_libraries = BitReader Core MC MCParser Support diff --git a/lib/Object/MachOObjectFile.cpp b/lib/Object/MachOObjectFile.cpp index 4919114..bbef639 100644 --- a/lib/Object/MachOObjectFile.cpp +++ b/lib/Object/MachOObjectFile.cpp @@ -14,10 +14,14 @@ #include "llvm/Object/MachO.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/Format.h" #include "llvm/Support/Host.h" +#include "llvm/Support/LEB128.h" +#include "llvm/Support/MachO.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include <cctype> @@ -27,220 +31,19 @@ using namespace llvm; using namespace object; -namespace llvm { - -namespace object { - -struct nlist_base { - uint32_t n_strx; - uint8_t n_type; - uint8_t n_sect; - uint16_t n_desc; -}; - -struct section_base { - char sectname[16]; - char segname[16]; -}; - -template<typename T> -static void SwapStruct(T &Value); - -template<> -void SwapStruct(MachO::any_relocation_info &H) { - sys::swapByteOrder(H.r_word0); - sys::swapByteOrder(H.r_word1); -} - -template<> -void SwapStruct(MachO::load_command &L) { - sys::swapByteOrder(L.cmd); - sys::swapByteOrder(L.cmdsize); -} - -template<> -void SwapStruct(nlist_base &S) { - sys::swapByteOrder(S.n_strx); - sys::swapByteOrder(S.n_desc); -} - -template<> -void SwapStruct(MachO::section &S) { - sys::swapByteOrder(S.addr); - sys::swapByteOrder(S.size); - sys::swapByteOrder(S.offset); - sys::swapByteOrder(S.align); - sys::swapByteOrder(S.reloff); - sys::swapByteOrder(S.nreloc); - sys::swapByteOrder(S.flags); - sys::swapByteOrder(S.reserved1); - sys::swapByteOrder(S.reserved2); -} - -template<> -void SwapStruct(MachO::section_64 &S) { - sys::swapByteOrder(S.addr); - sys::swapByteOrder(S.size); - sys::swapByteOrder(S.offset); - sys::swapByteOrder(S.align); - sys::swapByteOrder(S.reloff); - sys::swapByteOrder(S.nreloc); - sys::swapByteOrder(S.flags); - sys::swapByteOrder(S.reserved1); - sys::swapByteOrder(S.reserved2); - sys::swapByteOrder(S.reserved3); -} - -template<> -void SwapStruct(MachO::nlist &S) { - sys::swapByteOrder(S.n_strx); - sys::swapByteOrder(S.n_desc); - sys::swapByteOrder(S.n_value); -} - -template<> -void SwapStruct(MachO::nlist_64 &S) { - sys::swapByteOrder(S.n_strx); - sys::swapByteOrder(S.n_desc); - sys::swapByteOrder(S.n_value); -} - -template<> -void SwapStruct(MachO::mach_header &H) { - sys::swapByteOrder(H.magic); - sys::swapByteOrder(H.cputype); - sys::swapByteOrder(H.cpusubtype); - sys::swapByteOrder(H.filetype); - sys::swapByteOrder(H.ncmds); - sys::swapByteOrder(H.sizeofcmds); - sys::swapByteOrder(H.flags); -} - -template<> -void SwapStruct(MachO::mach_header_64 &H) { - sys::swapByteOrder(H.magic); - sys::swapByteOrder(H.cputype); - sys::swapByteOrder(H.cpusubtype); - sys::swapByteOrder(H.filetype); - sys::swapByteOrder(H.ncmds); - sys::swapByteOrder(H.sizeofcmds); - sys::swapByteOrder(H.flags); - sys::swapByteOrder(H.reserved); -} - -template<> -void SwapStruct(MachO::symtab_command &C) { - sys::swapByteOrder(C.cmd); - sys::swapByteOrder(C.cmdsize); - sys::swapByteOrder(C.symoff); - sys::swapByteOrder(C.nsyms); - sys::swapByteOrder(C.stroff); - sys::swapByteOrder(C.strsize); -} - -template<> -void SwapStruct(MachO::dysymtab_command &C) { - sys::swapByteOrder(C.cmd); - sys::swapByteOrder(C.cmdsize); - sys::swapByteOrder(C.ilocalsym); - sys::swapByteOrder(C.nlocalsym); - sys::swapByteOrder(C.iextdefsym); - sys::swapByteOrder(C.nextdefsym); - sys::swapByteOrder(C.iundefsym); - sys::swapByteOrder(C.nundefsym); - sys::swapByteOrder(C.tocoff); - sys::swapByteOrder(C.ntoc); - sys::swapByteOrder(C.modtaboff); - sys::swapByteOrder(C.nmodtab); - sys::swapByteOrder(C.extrefsymoff); - sys::swapByteOrder(C.nextrefsyms); - sys::swapByteOrder(C.indirectsymoff); - sys::swapByteOrder(C.nindirectsyms); - sys::swapByteOrder(C.extreloff); - sys::swapByteOrder(C.nextrel); - sys::swapByteOrder(C.locreloff); - sys::swapByteOrder(C.nlocrel); -} - -template<> -void SwapStruct(MachO::linkedit_data_command &C) { - sys::swapByteOrder(C.cmd); - sys::swapByteOrder(C.cmdsize); - sys::swapByteOrder(C.dataoff); - sys::swapByteOrder(C.datasize); -} - -template<> -void SwapStruct(MachO::segment_command &C) { - sys::swapByteOrder(C.cmd); - sys::swapByteOrder(C.cmdsize); - sys::swapByteOrder(C.vmaddr); - sys::swapByteOrder(C.vmsize); - sys::swapByteOrder(C.fileoff); - sys::swapByteOrder(C.filesize); - sys::swapByteOrder(C.maxprot); - sys::swapByteOrder(C.initprot); - sys::swapByteOrder(C.nsects); - sys::swapByteOrder(C.flags); -} - -template<> -void SwapStruct(MachO::segment_command_64 &C) { - sys::swapByteOrder(C.cmd); - sys::swapByteOrder(C.cmdsize); - sys::swapByteOrder(C.vmaddr); - sys::swapByteOrder(C.vmsize); - sys::swapByteOrder(C.fileoff); - sys::swapByteOrder(C.filesize); - sys::swapByteOrder(C.maxprot); - sys::swapByteOrder(C.initprot); - sys::swapByteOrder(C.nsects); - sys::swapByteOrder(C.flags); -} - -template<> -void SwapStruct(uint32_t &C) { - sys::swapByteOrder(C); -} - -template<> -void SwapStruct(MachO::linker_options_command &C) { - sys::swapByteOrder(C.cmd); - sys::swapByteOrder(C.cmdsize); - sys::swapByteOrder(C.count); -} - -template<> -void SwapStruct(MachO::version_min_command&C) { - sys::swapByteOrder(C.cmd); - sys::swapByteOrder(C.cmdsize); - sys::swapByteOrder(C.version); - sys::swapByteOrder(C.reserved); -} - -template<> -void SwapStruct(MachO::dylib_command&C) { - sys::swapByteOrder(C.cmd); - sys::swapByteOrder(C.cmdsize); - sys::swapByteOrder(C.dylib.name); - sys::swapByteOrder(C.dylib.timestamp); - sys::swapByteOrder(C.dylib.current_version); - sys::swapByteOrder(C.dylib.compatibility_version); -} - -template<> -void SwapStruct(MachO::data_in_code_entry &C) { - sys::swapByteOrder(C.offset); - sys::swapByteOrder(C.length); - sys::swapByteOrder(C.kind); +namespace { + struct section_base { + char sectname[16]; + char segname[16]; + }; } template<typename T> -T getStruct(const MachOObjectFile *O, const char *P) { +static T getStruct(const MachOObjectFile *O, const char *P) { T Cmd; memcpy(&Cmd, P, sizeof(T)); if (O->isLittleEndian() != sys::IsLittleEndianHost) - SwapStruct(Cmd); + MachO::swapStruct(Cmd); return Cmd; } @@ -255,6 +58,17 @@ getSegmentLoadCommandNumSections(const MachOObjectFile *O, return S.nsects; } +static bool isPageZeroSegment(const MachOObjectFile *O, + const MachOObjectFile::LoadCommandInfo &L) { + if (O->is64Bit()) { + MachO::segment_command_64 S = O->getSegment64LoadCommand(L); + return StringRef("__PAGEZERO").equals(S.segname); + } + MachO::segment_command S = O->getSegmentLoadCommand(L); + return StringRef("__PAGEZERO").equals(S.segname); +} + + static const char * getSectionPtr(const MachOObjectFile *O, MachOObjectFile::LoadCommandInfo L, unsigned Sec) { @@ -274,10 +88,10 @@ static const char *getPtr(const MachOObjectFile *O, size_t Offset) { return O->getData().substr(Offset, 1).data(); } -static nlist_base +static MachO::nlist_base getSymbolTableEntryBase(const MachOObjectFile *O, DataRefImpl DRI) { const char *P = reinterpret_cast<const char *>(DRI.p); - return getStruct<nlist_base>(O, P); + return getStruct<MachO::nlist_base>(O, P); } static StringRef parseSegmentOrSectionName(const char *P) { @@ -330,11 +144,9 @@ static void printRelocationTargetName(const MachOObjectFile *O, // to find a section beginning instead. for (const SectionRef &Section : O->sections()) { std::error_code ec; - uint64_t Addr; - StringRef Name; - if ((ec = Section.getAddress(Addr))) - report_fatal_error(ec.message()); + StringRef Name; + uint64_t Addr = Section.getAddress(); if (Addr != Val) continue; if ((ec = Section.getName(Name))) @@ -407,11 +219,6 @@ static unsigned getPlainRelocationType(const MachOObjectFile *O, return RE.r_word1 & 0xf; } -static unsigned -getScatteredRelocationType(const MachO::any_relocation_info &RE) { - return (RE.r_word0 >> 24) & 0xf; -} - static uint32_t getSectionFlags(const MachOObjectFile *O, DataRefImpl Sec) { if (O->is64Bit()) { @@ -422,12 +229,12 @@ static uint32_t getSectionFlags(const MachOObjectFile *O, return Sect.flags; } -MachOObjectFile::MachOObjectFile(std::unique_ptr<MemoryBuffer> Object, - bool IsLittleEndian, bool Is64bits, - std::error_code &EC) - : ObjectFile(getMachOType(IsLittleEndian, Is64bits), std::move(Object)), +MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, + bool Is64bits, std::error_code &EC) + : ObjectFile(getMachOType(IsLittleEndian, Is64bits), Object), SymtabLoadCmd(nullptr), DysymtabLoadCmd(nullptr), - DataInCodeLoadCmd(nullptr) { + DataInCodeLoadCmd(nullptr), DyldInfoLoadCmd(nullptr), + UuidLoadCmd(nullptr), HasPageZeroSegment(false) { uint32_t LoadCommandCount = this->getHeader().ncmds; MachO::LoadCommandType SegmentLoadType = is64Bit() ? MachO::LC_SEGMENT_64 : MachO::LC_SEGMENT; @@ -435,20 +242,49 @@ MachOObjectFile::MachOObjectFile(std::unique_ptr<MemoryBuffer> Object, MachOObjectFile::LoadCommandInfo Load = getFirstLoadCommandInfo(); for (unsigned I = 0; ; ++I) { if (Load.C.cmd == MachO::LC_SYMTAB) { - assert(!SymtabLoadCmd && "Multiple symbol tables"); + // Multiple symbol tables + if (SymtabLoadCmd) { + EC = object_error::parse_failed; + return; + } SymtabLoadCmd = Load.Ptr; } else if (Load.C.cmd == MachO::LC_DYSYMTAB) { - assert(!DysymtabLoadCmd && "Multiple dynamic symbol tables"); + // Multiple dynamic symbol tables + if (DysymtabLoadCmd) { + EC = object_error::parse_failed; + return; + } DysymtabLoadCmd = Load.Ptr; } else if (Load.C.cmd == MachO::LC_DATA_IN_CODE) { - assert(!DataInCodeLoadCmd && "Multiple data in code tables"); + // Multiple data in code tables + if (DataInCodeLoadCmd) { + EC = object_error::parse_failed; + return; + } DataInCodeLoadCmd = Load.Ptr; + } else if (Load.C.cmd == MachO::LC_DYLD_INFO || + Load.C.cmd == MachO::LC_DYLD_INFO_ONLY) { + // Multiple dyldinfo load commands + if (DyldInfoLoadCmd) { + EC = object_error::parse_failed; + return; + } + DyldInfoLoadCmd = Load.Ptr; + } else if (Load.C.cmd == MachO::LC_UUID) { + // Multiple UUID load commands + if (UuidLoadCmd) { + EC = object_error::parse_failed; + return; + } + UuidLoadCmd = Load.Ptr; } else if (Load.C.cmd == SegmentLoadType) { uint32_t NumSections = getSegmentLoadCommandNumSections(this, Load); for (unsigned J = 0; J < NumSections; ++J) { const char *Sec = getSectionPtr(this, Load, J); Sections.push_back(Sec); } + if (isPageZeroSegment(this, Load)) + HasPageZeroSegment = true; } else if (Load.C.cmd == MachO::LC_LOAD_DYLIB || Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB || Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB || @@ -474,7 +310,7 @@ void MachOObjectFile::moveSymbolNext(DataRefImpl &Symb) const { std::error_code MachOObjectFile::getSymbolName(DataRefImpl Symb, StringRef &Res) const { StringRef StringTable = getStringTableData(); - nlist_base Entry = getSymbolTableEntryBase(this, Symb); + MachO::nlist_base Entry = getSymbolTableEntryBase(this, Symb); const char *Start = &StringTable.data()[Entry.n_strx]; Res = StringRef(Start); return object_error::success; @@ -528,7 +364,7 @@ std::error_code MachOObjectFile::getSymbolAlignment(DataRefImpl DRI, uint32_t &Result) const { uint32_t flags = getSymbolFlags(DRI); if (flags & SymbolRef::SF_Common) { - nlist_base Entry = getSymbolTableEntryBase(this, DRI); + MachO::nlist_base Entry = getSymbolTableEntryBase(this, DRI); Result = 1 << MachO::GET_COMM_ALIGN(Entry.n_desc); } else { Result = 0; @@ -542,7 +378,7 @@ std::error_code MachOObjectFile::getSymbolSize(DataRefImpl DRI, uint64_t EndOffset = 0; uint8_t SectionIndex; - nlist_base Entry = getSymbolTableEntryBase(this, DRI); + MachO::nlist_base Entry = getSymbolTableEntryBase(this, DRI); uint64_t Value; getSymbolAddress(DRI, Value); if (Value == UnknownAddressOrSize) { @@ -574,11 +410,10 @@ std::error_code MachOObjectFile::getSymbolSize(DataRefImpl DRI, EndOffset = Value; } if (!EndOffset) { - uint64_t Size; DataRefImpl Sec; Sec.d.a = SectionIndex-1; - getSectionSize(Sec, Size); - getSectionAddress(Sec, EndOffset); + uint64_t Size = getSectionSize(Sec); + EndOffset = getSectionAddress(Sec); EndOffset += Size; } Result = EndOffset - BeginOffset; @@ -587,7 +422,7 @@ std::error_code MachOObjectFile::getSymbolSize(DataRefImpl DRI, std::error_code MachOObjectFile::getSymbolType(DataRefImpl Symb, SymbolRef::Type &Res) const { - nlist_base Entry = getSymbolTableEntryBase(this, Symb); + MachO::nlist_base Entry = getSymbolTableEntryBase(this, Symb); uint8_t n_type = Entry.n_type; Res = SymbolRef::ST_Other; @@ -610,7 +445,7 @@ std::error_code MachOObjectFile::getSymbolType(DataRefImpl Symb, } uint32_t MachOObjectFile::getSymbolFlags(DataRefImpl DRI) const { - nlist_base Entry = getSymbolTableEntryBase(this, DRI); + MachO::nlist_base Entry = getSymbolTableEntryBase(this, DRI); uint8_t MachOType = Entry.n_type; uint16_t MachOFlags = Entry.n_desc; @@ -639,6 +474,9 @@ uint32_t MachOObjectFile::getSymbolFlags(DataRefImpl DRI) const { if (MachOFlags & (MachO::N_WEAK_REF | MachO::N_WEAK_DEF)) Result |= SymbolRef::SF_Weak; + if (MachOFlags & (MachO::N_ARM_THUMB_DEF)) + Result |= SymbolRef::SF_Thumb; + if ((MachOType & MachO::N_TYPE) == MachO::N_ABS) Result |= SymbolRef::SF_Absolute; @@ -647,7 +485,7 @@ uint32_t MachOObjectFile::getSymbolFlags(DataRefImpl DRI) const { std::error_code MachOObjectFile::getSymbolSection(DataRefImpl Symb, section_iterator &Res) const { - nlist_base Entry = getSymbolTableEntryBase(this, Symb); + MachO::nlist_base Entry = getSymbolTableEntryBase(this, Symb); uint8_t index = Entry.n_sect; if (index == 0) { @@ -672,29 +510,16 @@ std::error_code MachOObjectFile::getSectionName(DataRefImpl Sec, return object_error::success; } -std::error_code MachOObjectFile::getSectionAddress(DataRefImpl Sec, - uint64_t &Res) const { - if (is64Bit()) { - MachO::section_64 Sect = getSection64(Sec); - Res = Sect.addr; - } else { - MachO::section Sect = getSection(Sec); - Res = Sect.addr; - } - return object_error::success; +uint64_t MachOObjectFile::getSectionAddress(DataRefImpl Sec) const { + if (is64Bit()) + return getSection64(Sec).addr; + return getSection(Sec).addr; } -std::error_code MachOObjectFile::getSectionSize(DataRefImpl Sec, - uint64_t &Res) const { - if (is64Bit()) { - MachO::section_64 Sect = getSection64(Sec); - Res = Sect.size; - } else { - MachO::section Sect = getSection(Sec); - Res = Sect.size; - } - - return object_error::success; +uint64_t MachOObjectFile::getSectionSize(DataRefImpl Sec) const { + if (is64Bit()) + return getSection64(Sec).size; + return getSection(Sec).size; } std::error_code MachOObjectFile::getSectionContents(DataRefImpl Sec, @@ -716,8 +541,7 @@ std::error_code MachOObjectFile::getSectionContents(DataRefImpl Sec, return object_error::success; } -std::error_code MachOObjectFile::getSectionAlignment(DataRefImpl Sec, - uint64_t &Res) const { +uint64_t MachOObjectFile::getSectionAlignment(DataRefImpl Sec) const { uint32_t Align; if (is64Bit()) { MachO::section_64 Sect = getSection64(Sec); @@ -727,92 +551,70 @@ std::error_code MachOObjectFile::getSectionAlignment(DataRefImpl Sec, Align = Sect.align; } - Res = uint64_t(1) << Align; - return object_error::success; + return uint64_t(1) << Align; } -std::error_code MachOObjectFile::isSectionText(DataRefImpl Sec, - bool &Res) const { +bool MachOObjectFile::isSectionText(DataRefImpl Sec) const { uint32_t Flags = getSectionFlags(this, Sec); - Res = Flags & MachO::S_ATTR_PURE_INSTRUCTIONS; - return object_error::success; + return Flags & MachO::S_ATTR_PURE_INSTRUCTIONS; } -std::error_code MachOObjectFile::isSectionData(DataRefImpl Sec, - bool &Result) const { +bool MachOObjectFile::isSectionData(DataRefImpl Sec) const { uint32_t Flags = getSectionFlags(this, Sec); unsigned SectionType = Flags & MachO::SECTION_TYPE; - Result = !(Flags & MachO::S_ATTR_PURE_INSTRUCTIONS) && - !(SectionType == MachO::S_ZEROFILL || - SectionType == MachO::S_GB_ZEROFILL); - return object_error::success; + return !(Flags & MachO::S_ATTR_PURE_INSTRUCTIONS) && + !(SectionType == MachO::S_ZEROFILL || + SectionType == MachO::S_GB_ZEROFILL); } -std::error_code MachOObjectFile::isSectionBSS(DataRefImpl Sec, - bool &Result) const { +bool MachOObjectFile::isSectionBSS(DataRefImpl Sec) const { uint32_t Flags = getSectionFlags(this, Sec); unsigned SectionType = Flags & MachO::SECTION_TYPE; - Result = !(Flags & MachO::S_ATTR_PURE_INSTRUCTIONS) && - (SectionType == MachO::S_ZEROFILL || - SectionType == MachO::S_GB_ZEROFILL); - return object_error::success; + return !(Flags & MachO::S_ATTR_PURE_INSTRUCTIONS) && + (SectionType == MachO::S_ZEROFILL || + SectionType == MachO::S_GB_ZEROFILL); } -std::error_code -MachOObjectFile::isSectionRequiredForExecution(DataRefImpl Sec, - bool &Result) const { +bool MachOObjectFile::isSectionRequiredForExecution(DataRefImpl Sect) const { // FIXME: Unimplemented. - Result = true; - return object_error::success; + return true; } -std::error_code MachOObjectFile::isSectionVirtual(DataRefImpl Sec, - bool &Result) const { +bool MachOObjectFile::isSectionVirtual(DataRefImpl Sec) const { // FIXME: Unimplemented. - Result = false; - return object_error::success; + return false; } -std::error_code MachOObjectFile::isSectionZeroInit(DataRefImpl Sec, - bool &Res) const { +bool MachOObjectFile::isSectionZeroInit(DataRefImpl Sec) const { uint32_t Flags = getSectionFlags(this, Sec); unsigned SectionType = Flags & MachO::SECTION_TYPE; - Res = SectionType == MachO::S_ZEROFILL || - SectionType == MachO::S_GB_ZEROFILL; - return object_error::success; + return SectionType == MachO::S_ZEROFILL || + SectionType == MachO::S_GB_ZEROFILL; } -std::error_code MachOObjectFile::isSectionReadOnlyData(DataRefImpl Sec, - bool &Result) const { +bool MachOObjectFile::isSectionReadOnlyData(DataRefImpl Sec) const { // Consider using the code from isSectionText to look for __const sections. // Alternately, emit S_ATTR_PURE_INSTRUCTIONS and/or S_ATTR_SOME_INSTRUCTIONS // to use section attributes to distinguish code from data. // FIXME: Unimplemented. - Result = false; - return object_error::success; + return false; } -std::error_code MachOObjectFile::sectionContainsSymbol(DataRefImpl Sec, - DataRefImpl Symb, - bool &Result) const { +bool MachOObjectFile::sectionContainsSymbol(DataRefImpl Sec, + DataRefImpl Symb) const { SymbolRef::Type ST; this->getSymbolType(Symb, ST); - if (ST == SymbolRef::ST_Unknown) { - Result = false; - return object_error::success; - } + if (ST == SymbolRef::ST_Unknown) + return false; - uint64_t SectBegin, SectEnd; - getSectionAddress(Sec, SectBegin); - getSectionSize(Sec, SectEnd); + uint64_t SectBegin = getSectionAddress(Sec); + uint64_t SectEnd = getSectionSize(Sec); SectEnd += SectBegin; uint64_t SymAddr; getSymbolAddress(Symb, SymAddr); - Result = (SymAddr >= SectBegin) && (SymAddr < SectEnd); - - return object_error::success; + return (SymAddr >= SectBegin) && (SymAddr < SectEnd); } relocation_iterator MachOObjectFile::section_rel_begin(DataRefImpl Sec) const { @@ -850,8 +652,7 @@ std::error_code MachOObjectFile::getRelocationAddress(DataRefImpl Rel, DataRefImpl Sec; Sec.d.a = Rel.d.a; - uint64_t SecAddress; - getSectionAddress(Sec, SecAddress); + uint64_t SecAddress = getSectionAddress(Sec); Res = SecAddress + Offset; return object_error::success; } @@ -956,7 +757,6 @@ MachOObjectFile::getRelocationTypeName(DataRefImpl Rel, res = Table[RType]; break; } - case Triple::arm64: case Triple::aarch64: { static const char *const Table[] = { "ARM64_RELOC_UNSIGNED", "ARM64_RELOC_SUBTRACTOR", @@ -1210,16 +1010,6 @@ std::error_code MachOObjectFile::getRelocationHidden(DataRefImpl Rel, return object_error::success; } -std::error_code MachOObjectFile::getLibraryNext(DataRefImpl LibData, - LibraryRef &Res) const { - report_fatal_error("Needed libraries unimplemented in MachOObjectFile"); -} - -std::error_code MachOObjectFile::getLibraryPath(DataRefImpl LibData, - StringRef &Res) const { - report_fatal_error("Needed libraries unimplemented in MachOObjectFile"); -} - // // guessLibraryShortName() is passed a name of a dynamic library and returns a // guess on what the short name is. Then name is returned as a substring of the @@ -1368,31 +1158,26 @@ guess_qtx: // It is passed the index (0 - based) of the library as translated from // GET_LIBRARY_ORDINAL (1 - based). std::error_code MachOObjectFile::getLibraryShortNameByIndex(unsigned Index, - StringRef &Res) { + StringRef &Res) const { if (Index >= Libraries.size()) return object_error::parse_failed; - MachO::dylib_command D = - getStruct<MachO::dylib_command>(this, Libraries[Index]); - if (D.dylib.name >= D.cmdsize) - return object_error::parse_failed; - // If the cache of LibrariesShortNames is not built up do that first for // all the Libraries. if (LibrariesShortNames.size() == 0) { for (unsigned i = 0; i < Libraries.size(); i++) { MachO::dylib_command D = getStruct<MachO::dylib_command>(this, Libraries[i]); - if (D.dylib.name >= D.cmdsize) { - LibrariesShortNames.push_back(StringRef()); - continue; - } + if (D.dylib.name >= D.cmdsize) + return object_error::parse_failed; const char *P = (const char *)(Libraries[i]) + D.dylib.name; StringRef Name = StringRef(P); + if (D.dylib.name+Name.size() >= D.cmdsize) + return object_error::parse_failed; StringRef Suffix; bool isFramework; StringRef shortName = guessLibraryShortName(Name, isFramework, Suffix); - if (shortName == StringRef()) + if (shortName.empty()) LibrariesShortNames.push_back(Name); else LibrariesShortNames.push_back(shortName); @@ -1447,16 +1232,6 @@ section_iterator MachOObjectFile::section_end() const { return section_iterator(SectionRef(DRI, this)); } -library_iterator MachOObjectFile::needed_library_begin() const { - // TODO: implement - report_fatal_error("Needed libraries unimplemented in MachOObjectFile"); -} - -library_iterator MachOObjectFile::needed_library_end() const { - // TODO: implement - report_fatal_error("Needed libraries unimplemented in MachOObjectFile"); -} - uint8_t MachOObjectFile::getBytesInAddress() const { return is64Bit() ? 8 : 4; } @@ -1472,17 +1247,10 @@ StringRef MachOObjectFile::getFileFormatName() const { case llvm::MachO::CPU_TYPE_POWERPC: return "Mach-O 32-bit ppc"; default: - assert((CPUType & llvm::MachO::CPU_ARCH_ABI64) == 0 && - "64-bit object file when we're not 64-bit?"); return "Mach-O 32-bit unknown"; } } - // Make sure the cpu type has the correct mask. - assert((CPUType & llvm::MachO::CPU_ARCH_ABI64) - == llvm::MachO::CPU_ARCH_ABI64 && - "32-bit object file when we're 64-bit?"); - switch (CPUType) { case llvm::MachO::CPU_TYPE_X86_64: return "Mach-O 64-bit x86-64"; @@ -1504,7 +1272,7 @@ Triple::ArchType MachOObjectFile::getArch(uint32_t CPUType) { case llvm::MachO::CPU_TYPE_ARM: return Triple::arm; case llvm::MachO::CPU_TYPE_ARM64: - return Triple::arm64; + return Triple::aarch64; case llvm::MachO::CPU_TYPE_POWERPC: return Triple::ppc; case llvm::MachO::CPU_TYPE_POWERPC64: @@ -1514,7 +1282,11 @@ Triple::ArchType MachOObjectFile::getArch(uint32_t CPUType) { } } -Triple MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType) { +Triple MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType, + const char **McpuDefault) { + if (McpuDefault) + *McpuDefault = nullptr; + switch (CPUType) { case MachO::CPU_TYPE_I386: switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { @@ -1538,15 +1310,25 @@ Triple MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType) { return Triple("armv4t-apple-darwin"); case MachO::CPU_SUBTYPE_ARM_V5TEJ: return Triple("armv5e-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_XSCALE: + return Triple("xscale-apple-darwin"); case MachO::CPU_SUBTYPE_ARM_V6: return Triple("armv6-apple-darwin"); case MachO::CPU_SUBTYPE_ARM_V6M: + if (McpuDefault) + *McpuDefault = "cortex-m0"; return Triple("armv6m-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V7: + return Triple("armv7-apple-darwin"); case MachO::CPU_SUBTYPE_ARM_V7EM: + if (McpuDefault) + *McpuDefault = "cortex-m4"; return Triple("armv7em-apple-darwin"); case MachO::CPU_SUBTYPE_ARM_V7K: return Triple("armv7k-apple-darwin"); case MachO::CPU_SUBTYPE_ARM_V7M: + if (McpuDefault) + *McpuDefault = "cortex-m3"; return Triple("armv7m-apple-darwin"); case MachO::CPU_SUBTYPE_ARM_V7S: return Triple("armv7s-apple-darwin"); @@ -1579,50 +1361,102 @@ Triple MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType) { } } +Triple MachOObjectFile::getThumbArch(uint32_t CPUType, uint32_t CPUSubType, + const char **McpuDefault) { + if (McpuDefault) + *McpuDefault = nullptr; + + switch (CPUType) { + case MachO::CPU_TYPE_ARM: + switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { + case MachO::CPU_SUBTYPE_ARM_V4T: + return Triple("thumbv4t-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V5TEJ: + return Triple("thumbv5e-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_XSCALE: + return Triple("xscale-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V6: + return Triple("thumbv6-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V6M: + if (McpuDefault) + *McpuDefault = "cortex-m0"; + return Triple("thumbv6m-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V7: + return Triple("thumbv7-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V7EM: + if (McpuDefault) + *McpuDefault = "cortex-m4"; + return Triple("thumbv7em-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V7K: + return Triple("thumbv7k-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V7M: + if (McpuDefault) + *McpuDefault = "cortex-m3"; + return Triple("thumbv7m-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V7S: + return Triple("thumbv7s-apple-darwin"); + default: + return Triple(); + } + default: + return Triple(); + } +} + +Triple MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType, + const char **McpuDefault, + Triple *ThumbTriple) { + Triple T = MachOObjectFile::getArch(CPUType, CPUSubType, McpuDefault); + *ThumbTriple = MachOObjectFile::getThumbArch(CPUType, CPUSubType, + McpuDefault); + return T; +} + Triple MachOObjectFile::getHostArch() { return Triple(sys::getDefaultTargetTriple()); } -Triple MachOObjectFile::getArch(StringRef ArchFlag) { - if (ArchFlag == "i386") - return Triple("i386-apple-darwin"); - else if (ArchFlag == "x86_64") - return Triple("x86_64-apple-darwin"); - else if (ArchFlag == "x86_64h") - return Triple("x86_64h-apple-darwin"); - else if (ArchFlag == "armv4t" || ArchFlag == "arm") - return Triple("armv4t-apple-darwin"); - else if (ArchFlag == "armv5e") - return Triple("armv5e-apple-darwin"); - else if (ArchFlag == "armv6") - return Triple("armv6-apple-darwin"); - else if (ArchFlag == "armv6m") - return Triple("armv6m-apple-darwin"); - else if (ArchFlag == "armv7em") - return Triple("armv7em-apple-darwin"); - else if (ArchFlag == "armv7k") - return Triple("armv7k-apple-darwin"); - else if (ArchFlag == "armv7k") - return Triple("armv7m-apple-darwin"); - else if (ArchFlag == "armv7s") - return Triple("armv7s-apple-darwin"); - else if (ArchFlag == "arm64") - return Triple("arm64-apple-darwin"); - else if (ArchFlag == "ppc") - return Triple("ppc-apple-darwin"); - else if (ArchFlag == "ppc64") - return Triple("ppc64-apple-darwin"); - else - return Triple(); +bool MachOObjectFile::isValidArch(StringRef ArchFlag) { + return StringSwitch<bool>(ArchFlag) + .Case("i386", true) + .Case("x86_64", true) + .Case("x86_64h", true) + .Case("armv4t", true) + .Case("arm", true) + .Case("armv5e", true) + .Case("armv6", true) + .Case("armv6m", true) + .Case("armv7em", true) + .Case("armv7k", true) + .Case("armv7m", true) + .Case("armv7s", true) + .Case("arm64", true) + .Case("ppc", true) + .Case("ppc64", true) + .Default(false); } unsigned MachOObjectFile::getArch() const { return getArch(getCPUType(this)); } -StringRef MachOObjectFile::getLoadName() const { - // TODO: Implement - report_fatal_error("get_load_name() unimplemented in MachOObjectFile"); +Triple MachOObjectFile::getArch(const char **McpuDefault, + Triple *ThumbTriple) const { + Triple T; + if (is64Bit()) { + MachO::mach_header_64 H_64; + H_64 = getHeader64(); + T = MachOObjectFile::getArch(H_64.cputype, H_64.cpusubtype, McpuDefault); + *ThumbTriple = MachOObjectFile::getThumbArch(H_64.cputype, H_64.cpusubtype, + McpuDefault); + } else { + MachO::mach_header H; + H = getHeader(); + T = MachOObjectFile::getArch(H.cputype, H.cpusubtype, McpuDefault); + *ThumbTriple = MachOObjectFile::getThumbArch(H.cputype, H.cpusubtype, + McpuDefault); + } + return T; } relocation_iterator MachOObjectFile::section_rel_begin(unsigned Index) const { @@ -1658,6 +1492,620 @@ dice_iterator MachOObjectFile::end_dices() const { return dice_iterator(DiceRef(DRI, this)); } +ExportEntry::ExportEntry(ArrayRef<uint8_t> T) + : Trie(T), Malformed(false), Done(false) { } + +void ExportEntry::moveToFirst() { + pushNode(0); + pushDownUntilBottom(); +} + +void ExportEntry::moveToEnd() { + Stack.clear(); + Done = true; +} + +bool ExportEntry::operator==(const ExportEntry &Other) const { + // Common case, one at end, other iterating from begin. + if (Done || Other.Done) + return (Done == Other.Done); + // Not equal if different stack sizes. + if (Stack.size() != Other.Stack.size()) + return false; + // Not equal if different cumulative strings. + if (!CumulativeString.str().equals(Other.CumulativeString.str())) + return false; + // Equal if all nodes in both stacks match. + for (unsigned i=0; i < Stack.size(); ++i) { + if (Stack[i].Start != Other.Stack[i].Start) + return false; + } + return true; +} + +uint64_t ExportEntry::readULEB128(const uint8_t *&Ptr) { + unsigned Count; + uint64_t Result = decodeULEB128(Ptr, &Count); + Ptr += Count; + if (Ptr > Trie.end()) { + Ptr = Trie.end(); + Malformed = true; + } + return Result; +} + +StringRef ExportEntry::name() const { + return CumulativeString.str(); +} + +uint64_t ExportEntry::flags() const { + return Stack.back().Flags; +} + +uint64_t ExportEntry::address() const { + return Stack.back().Address; +} + +uint64_t ExportEntry::other() const { + return Stack.back().Other; +} + +StringRef ExportEntry::otherName() const { + const char* ImportName = Stack.back().ImportName; + if (ImportName) + return StringRef(ImportName); + return StringRef(); +} + +uint32_t ExportEntry::nodeOffset() const { + return Stack.back().Start - Trie.begin(); +} + +ExportEntry::NodeState::NodeState(const uint8_t *Ptr) + : Start(Ptr), Current(Ptr), Flags(0), Address(0), Other(0), + ImportName(nullptr), ChildCount(0), NextChildIndex(0), + ParentStringLength(0), IsExportNode(false) { +} + +void ExportEntry::pushNode(uint64_t offset) { + const uint8_t *Ptr = Trie.begin() + offset; + NodeState State(Ptr); + uint64_t ExportInfoSize = readULEB128(State.Current); + State.IsExportNode = (ExportInfoSize != 0); + const uint8_t* Children = State.Current + ExportInfoSize; + if (State.IsExportNode) { + State.Flags = readULEB128(State.Current); + if (State.Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT) { + State.Address = 0; + State.Other = readULEB128(State.Current); // dylib ordinal + State.ImportName = reinterpret_cast<const char*>(State.Current); + } else { + State.Address = readULEB128(State.Current); + if (State.Flags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) + State.Other = readULEB128(State.Current); + } + } + State.ChildCount = *Children; + State.Current = Children + 1; + State.NextChildIndex = 0; + State.ParentStringLength = CumulativeString.size(); + Stack.push_back(State); +} + +void ExportEntry::pushDownUntilBottom() { + while (Stack.back().NextChildIndex < Stack.back().ChildCount) { + NodeState &Top = Stack.back(); + CumulativeString.resize(Top.ParentStringLength); + for (;*Top.Current != 0; Top.Current++) { + char C = *Top.Current; + CumulativeString.push_back(C); + } + Top.Current += 1; + uint64_t childNodeIndex = readULEB128(Top.Current); + Top.NextChildIndex += 1; + pushNode(childNodeIndex); + } + if (!Stack.back().IsExportNode) { + Malformed = true; + moveToEnd(); + } +} + +// We have a trie data structure and need a way to walk it that is compatible +// with the C++ iterator model. The solution is a non-recursive depth first +// traversal where the iterator contains a stack of parent nodes along with a +// string that is the accumulation of all edge strings along the parent chain +// to this point. +// +// There is one "export" node for each exported symbol. But because some +// symbols may be a prefix of another symbol (e.g. _dup and _dup2), an export +// node may have child nodes too. +// +// The algorithm for moveNext() is to keep moving down the leftmost unvisited +// child until hitting a node with no children (which is an export node or +// else the trie is malformed). On the way down, each node is pushed on the +// stack ivar. If there is no more ways down, it pops up one and tries to go +// down a sibling path until a childless node is reached. +void ExportEntry::moveNext() { + if (Stack.empty() || !Stack.back().IsExportNode) { + Malformed = true; + moveToEnd(); + return; + } + + Stack.pop_back(); + while (!Stack.empty()) { + NodeState &Top = Stack.back(); + if (Top.NextChildIndex < Top.ChildCount) { + pushDownUntilBottom(); + // Now at the next export node. + return; + } else { + if (Top.IsExportNode) { + // This node has no children but is itself an export node. + CumulativeString.resize(Top.ParentStringLength); + return; + } + Stack.pop_back(); + } + } + Done = true; +} + +iterator_range<export_iterator> +MachOObjectFile::exports(ArrayRef<uint8_t> Trie) { + ExportEntry Start(Trie); + Start.moveToFirst(); + + ExportEntry Finish(Trie); + Finish.moveToEnd(); + + return iterator_range<export_iterator>(export_iterator(Start), + export_iterator(Finish)); +} + +iterator_range<export_iterator> MachOObjectFile::exports() const { + return exports(getDyldInfoExportsTrie()); +} + + +MachORebaseEntry::MachORebaseEntry(ArrayRef<uint8_t> Bytes, bool is64Bit) + : Opcodes(Bytes), Ptr(Bytes.begin()), SegmentOffset(0), SegmentIndex(0), + RemainingLoopCount(0), AdvanceAmount(0), RebaseType(0), + PointerSize(is64Bit ? 8 : 4), Malformed(false), Done(false) {} + +void MachORebaseEntry::moveToFirst() { + Ptr = Opcodes.begin(); + moveNext(); +} + +void MachORebaseEntry::moveToEnd() { + Ptr = Opcodes.end(); + RemainingLoopCount = 0; + Done = true; +} + +void MachORebaseEntry::moveNext() { + // If in the middle of some loop, move to next rebasing in loop. + SegmentOffset += AdvanceAmount; + if (RemainingLoopCount) { + --RemainingLoopCount; + return; + } + if (Ptr == Opcodes.end()) { + Done = true; + return; + } + bool More = true; + while (More && !Malformed) { + // Parse next opcode and set up next loop. + uint8_t Byte = *Ptr++; + uint8_t ImmValue = Byte & MachO::REBASE_IMMEDIATE_MASK; + uint8_t Opcode = Byte & MachO::REBASE_OPCODE_MASK; + switch (Opcode) { + case MachO::REBASE_OPCODE_DONE: + More = false; + Done = true; + moveToEnd(); + DEBUG_WITH_TYPE("mach-o-rebase", llvm::dbgs() << "REBASE_OPCODE_DONE\n"); + break; + case MachO::REBASE_OPCODE_SET_TYPE_IMM: + RebaseType = ImmValue; + DEBUG_WITH_TYPE( + "mach-o-rebase", + llvm::dbgs() << "REBASE_OPCODE_SET_TYPE_IMM: " + << "RebaseType=" << (int) RebaseType << "\n"); + break; + case MachO::REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: + SegmentIndex = ImmValue; + SegmentOffset = readULEB128(); + DEBUG_WITH_TYPE( + "mach-o-rebase", + llvm::dbgs() << "REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: " + << "SegmentIndex=" << SegmentIndex << ", " + << format("SegmentOffset=0x%06X", SegmentOffset) + << "\n"); + break; + case MachO::REBASE_OPCODE_ADD_ADDR_ULEB: + SegmentOffset += readULEB128(); + DEBUG_WITH_TYPE("mach-o-rebase", + llvm::dbgs() << "REBASE_OPCODE_ADD_ADDR_ULEB: " + << format("SegmentOffset=0x%06X", + SegmentOffset) << "\n"); + break; + case MachO::REBASE_OPCODE_ADD_ADDR_IMM_SCALED: + SegmentOffset += ImmValue * PointerSize; + DEBUG_WITH_TYPE("mach-o-rebase", + llvm::dbgs() << "REBASE_OPCODE_ADD_ADDR_IMM_SCALED: " + << format("SegmentOffset=0x%06X", + SegmentOffset) << "\n"); + break; + case MachO::REBASE_OPCODE_DO_REBASE_IMM_TIMES: + AdvanceAmount = PointerSize; + RemainingLoopCount = ImmValue - 1; + DEBUG_WITH_TYPE( + "mach-o-rebase", + llvm::dbgs() << "REBASE_OPCODE_DO_REBASE_IMM_TIMES: " + << format("SegmentOffset=0x%06X", SegmentOffset) + << ", AdvanceAmount=" << AdvanceAmount + << ", RemainingLoopCount=" << RemainingLoopCount + << "\n"); + return; + case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES: + AdvanceAmount = PointerSize; + RemainingLoopCount = readULEB128() - 1; + DEBUG_WITH_TYPE( + "mach-o-rebase", + llvm::dbgs() << "REBASE_OPCODE_DO_REBASE_ULEB_TIMES: " + << format("SegmentOffset=0x%06X", SegmentOffset) + << ", AdvanceAmount=" << AdvanceAmount + << ", RemainingLoopCount=" << RemainingLoopCount + << "\n"); + return; + case MachO::REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB: + AdvanceAmount = readULEB128() + PointerSize; + RemainingLoopCount = 0; + DEBUG_WITH_TYPE( + "mach-o-rebase", + llvm::dbgs() << "REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB: " + << format("SegmentOffset=0x%06X", SegmentOffset) + << ", AdvanceAmount=" << AdvanceAmount + << ", RemainingLoopCount=" << RemainingLoopCount + << "\n"); + return; + case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: + RemainingLoopCount = readULEB128() - 1; + AdvanceAmount = readULEB128() + PointerSize; + DEBUG_WITH_TYPE( + "mach-o-rebase", + llvm::dbgs() << "REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: " + << format("SegmentOffset=0x%06X", SegmentOffset) + << ", AdvanceAmount=" << AdvanceAmount + << ", RemainingLoopCount=" << RemainingLoopCount + << "\n"); + return; + default: + Malformed = true; + } + } +} + +uint64_t MachORebaseEntry::readULEB128() { + unsigned Count; + uint64_t Result = decodeULEB128(Ptr, &Count); + Ptr += Count; + if (Ptr > Opcodes.end()) { + Ptr = Opcodes.end(); + Malformed = true; + } + return Result; +} + +uint32_t MachORebaseEntry::segmentIndex() const { return SegmentIndex; } + +uint64_t MachORebaseEntry::segmentOffset() const { return SegmentOffset; } + +StringRef MachORebaseEntry::typeName() const { + switch (RebaseType) { + case MachO::REBASE_TYPE_POINTER: + return "pointer"; + case MachO::REBASE_TYPE_TEXT_ABSOLUTE32: + return "text abs32"; + case MachO::REBASE_TYPE_TEXT_PCREL32: + return "text rel32"; + } + return "unknown"; +} + +bool MachORebaseEntry::operator==(const MachORebaseEntry &Other) const { + assert(Opcodes == Other.Opcodes && "compare iterators of different files"); + return (Ptr == Other.Ptr) && + (RemainingLoopCount == Other.RemainingLoopCount) && + (Done == Other.Done); +} + +iterator_range<rebase_iterator> +MachOObjectFile::rebaseTable(ArrayRef<uint8_t> Opcodes, bool is64) { + MachORebaseEntry Start(Opcodes, is64); + Start.moveToFirst(); + + MachORebaseEntry Finish(Opcodes, is64); + Finish.moveToEnd(); + + return iterator_range<rebase_iterator>(rebase_iterator(Start), + rebase_iterator(Finish)); +} + +iterator_range<rebase_iterator> MachOObjectFile::rebaseTable() const { + return rebaseTable(getDyldInfoRebaseOpcodes(), is64Bit()); +} + + +MachOBindEntry::MachOBindEntry(ArrayRef<uint8_t> Bytes, bool is64Bit, + Kind BK) + : Opcodes(Bytes), Ptr(Bytes.begin()), SegmentOffset(0), SegmentIndex(0), + Ordinal(0), Flags(0), Addend(0), RemainingLoopCount(0), AdvanceAmount(0), + BindType(0), PointerSize(is64Bit ? 8 : 4), + TableKind(BK), Malformed(false), Done(false) {} + +void MachOBindEntry::moveToFirst() { + Ptr = Opcodes.begin(); + moveNext(); +} + +void MachOBindEntry::moveToEnd() { + Ptr = Opcodes.end(); + RemainingLoopCount = 0; + Done = true; +} + +void MachOBindEntry::moveNext() { + // If in the middle of some loop, move to next binding in loop. + SegmentOffset += AdvanceAmount; + if (RemainingLoopCount) { + --RemainingLoopCount; + return; + } + if (Ptr == Opcodes.end()) { + Done = true; + return; + } + bool More = true; + while (More && !Malformed) { + // Parse next opcode and set up next loop. + uint8_t Byte = *Ptr++; + uint8_t ImmValue = Byte & MachO::BIND_IMMEDIATE_MASK; + uint8_t Opcode = Byte & MachO::BIND_OPCODE_MASK; + int8_t SignExtended; + const uint8_t *SymStart; + switch (Opcode) { + case MachO::BIND_OPCODE_DONE: + if (TableKind == Kind::Lazy) { + // Lazying bindings have a DONE opcode between entries. Need to ignore + // it to advance to next entry. But need not if this is last entry. + bool NotLastEntry = false; + for (const uint8_t *P = Ptr; P < Opcodes.end(); ++P) { + if (*P) { + NotLastEntry = true; + } + } + if (NotLastEntry) + break; + } + More = false; + Done = true; + moveToEnd(); + DEBUG_WITH_TYPE("mach-o-bind", llvm::dbgs() << "BIND_OPCODE_DONE\n"); + break; + case MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: + Ordinal = ImmValue; + DEBUG_WITH_TYPE( + "mach-o-bind", + llvm::dbgs() << "BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: " + << "Ordinal=" << Ordinal << "\n"); + break; + case MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: + Ordinal = readULEB128(); + DEBUG_WITH_TYPE( + "mach-o-bind", + llvm::dbgs() << "BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: " + << "Ordinal=" << Ordinal << "\n"); + break; + case MachO::BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: + if (ImmValue) { + SignExtended = MachO::BIND_OPCODE_MASK | ImmValue; + Ordinal = SignExtended; + } else + Ordinal = 0; + DEBUG_WITH_TYPE( + "mach-o-bind", + llvm::dbgs() << "BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: " + << "Ordinal=" << Ordinal << "\n"); + break; + case MachO::BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: + Flags = ImmValue; + SymStart = Ptr; + while (*Ptr) { + ++Ptr; + } + SymbolName = StringRef(reinterpret_cast<const char*>(SymStart), + Ptr-SymStart); + ++Ptr; + DEBUG_WITH_TYPE( + "mach-o-bind", + llvm::dbgs() << "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: " + << "SymbolName=" << SymbolName << "\n"); + if (TableKind == Kind::Weak) { + if (ImmValue & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) + return; + } + break; + case MachO::BIND_OPCODE_SET_TYPE_IMM: + BindType = ImmValue; + DEBUG_WITH_TYPE( + "mach-o-bind", + llvm::dbgs() << "BIND_OPCODE_SET_TYPE_IMM: " + << "BindType=" << (int)BindType << "\n"); + break; + case MachO::BIND_OPCODE_SET_ADDEND_SLEB: + Addend = readSLEB128(); + if (TableKind == Kind::Lazy) + Malformed = true; + DEBUG_WITH_TYPE( + "mach-o-bind", + llvm::dbgs() << "BIND_OPCODE_SET_ADDEND_SLEB: " + << "Addend=" << Addend << "\n"); + break; + case MachO::BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: + SegmentIndex = ImmValue; + SegmentOffset = readULEB128(); + DEBUG_WITH_TYPE( + "mach-o-bind", + llvm::dbgs() << "BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: " + << "SegmentIndex=" << SegmentIndex << ", " + << format("SegmentOffset=0x%06X", SegmentOffset) + << "\n"); + break; + case MachO::BIND_OPCODE_ADD_ADDR_ULEB: + SegmentOffset += readULEB128(); + DEBUG_WITH_TYPE("mach-o-bind", + llvm::dbgs() << "BIND_OPCODE_ADD_ADDR_ULEB: " + << format("SegmentOffset=0x%06X", + SegmentOffset) << "\n"); + break; + case MachO::BIND_OPCODE_DO_BIND: + AdvanceAmount = PointerSize; + RemainingLoopCount = 0; + DEBUG_WITH_TYPE("mach-o-bind", + llvm::dbgs() << "BIND_OPCODE_DO_BIND: " + << format("SegmentOffset=0x%06X", + SegmentOffset) << "\n"); + return; + case MachO::BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: + AdvanceAmount = readULEB128() + PointerSize; + RemainingLoopCount = 0; + if (TableKind == Kind::Lazy) + Malformed = true; + DEBUG_WITH_TYPE( + "mach-o-bind", + llvm::dbgs() << "BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: " + << format("SegmentOffset=0x%06X", SegmentOffset) + << ", AdvanceAmount=" << AdvanceAmount + << ", RemainingLoopCount=" << RemainingLoopCount + << "\n"); + return; + case MachO::BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: + AdvanceAmount = ImmValue * PointerSize + PointerSize; + RemainingLoopCount = 0; + if (TableKind == Kind::Lazy) + Malformed = true; + DEBUG_WITH_TYPE("mach-o-bind", + llvm::dbgs() + << "BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: " + << format("SegmentOffset=0x%06X", + SegmentOffset) << "\n"); + return; + case MachO::BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: + RemainingLoopCount = readULEB128() - 1; + AdvanceAmount = readULEB128() + PointerSize; + if (TableKind == Kind::Lazy) + Malformed = true; + DEBUG_WITH_TYPE( + "mach-o-bind", + llvm::dbgs() << "BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: " + << format("SegmentOffset=0x%06X", SegmentOffset) + << ", AdvanceAmount=" << AdvanceAmount + << ", RemainingLoopCount=" << RemainingLoopCount + << "\n"); + return; + default: + Malformed = true; + } + } +} + +uint64_t MachOBindEntry::readULEB128() { + unsigned Count; + uint64_t Result = decodeULEB128(Ptr, &Count); + Ptr += Count; + if (Ptr > Opcodes.end()) { + Ptr = Opcodes.end(); + Malformed = true; + } + return Result; +} + +int64_t MachOBindEntry::readSLEB128() { + unsigned Count; + int64_t Result = decodeSLEB128(Ptr, &Count); + Ptr += Count; + if (Ptr > Opcodes.end()) { + Ptr = Opcodes.end(); + Malformed = true; + } + return Result; +} + + +uint32_t MachOBindEntry::segmentIndex() const { return SegmentIndex; } + +uint64_t MachOBindEntry::segmentOffset() const { return SegmentOffset; } + +StringRef MachOBindEntry::typeName() const { + switch (BindType) { + case MachO::BIND_TYPE_POINTER: + return "pointer"; + case MachO::BIND_TYPE_TEXT_ABSOLUTE32: + return "text abs32"; + case MachO::BIND_TYPE_TEXT_PCREL32: + return "text rel32"; + } + return "unknown"; +} + +StringRef MachOBindEntry::symbolName() const { return SymbolName; } + +int64_t MachOBindEntry::addend() const { return Addend; } + +uint32_t MachOBindEntry::flags() const { return Flags; } + +int MachOBindEntry::ordinal() const { return Ordinal; } + +bool MachOBindEntry::operator==(const MachOBindEntry &Other) const { + assert(Opcodes == Other.Opcodes && "compare iterators of different files"); + return (Ptr == Other.Ptr) && + (RemainingLoopCount == Other.RemainingLoopCount) && + (Done == Other.Done); +} + +iterator_range<bind_iterator> +MachOObjectFile::bindTable(ArrayRef<uint8_t> Opcodes, bool is64, + MachOBindEntry::Kind BKind) { + MachOBindEntry Start(Opcodes, is64, BKind); + Start.moveToFirst(); + + MachOBindEntry Finish(Opcodes, is64, BKind); + Finish.moveToEnd(); + + return iterator_range<bind_iterator>(bind_iterator(Start), + bind_iterator(Finish)); +} + +iterator_range<bind_iterator> MachOObjectFile::bindTable() const { + return bindTable(getDyldInfoBindOpcodes(), is64Bit(), + MachOBindEntry::Kind::Regular); +} + +iterator_range<bind_iterator> MachOObjectFile::lazyBindTable() const { + return bindTable(getDyldInfoLazyBindOpcodes(), is64Bit(), + MachOBindEntry::Kind::Lazy); +} + +iterator_range<bind_iterator> MachOObjectFile::weakBindTable() const { + return bindTable(getDyldInfoWeakBindOpcodes(), is64Bit(), + MachOBindEntry::Kind::Weak); +} + StringRef MachOObjectFile::getSectionFinalSegmentName(DataRefImpl Sec) const { ArrayRef<char> Raw = getSectionRawFinalSegmentName(Sec); @@ -1668,14 +2116,14 @@ ArrayRef<char> MachOObjectFile::getSectionRawName(DataRefImpl Sec) const { const section_base *Base = reinterpret_cast<const section_base *>(Sections[Sec.d.a]); - return ArrayRef<char>(Base->sectname); + return makeArrayRef(Base->sectname); } ArrayRef<char> MachOObjectFile::getSectionRawFinalSegmentName(DataRefImpl Sec) const { const section_base *Base = reinterpret_cast<const section_base *>(Sections[Sec.d.a]); - return ArrayRef<char>(Base->segname); + return makeArrayRef(Base->segname); } bool @@ -1710,6 +2158,11 @@ uint32_t MachOObjectFile::getScatteredRelocationValue( return RE.r_word1; } +uint32_t MachOObjectFile::getScatteredRelocationType( + const MachO::any_relocation_info &RE) const { + return (RE.r_word0 >> 24) & 0xf; +} + unsigned MachOObjectFile::getAnyRelocationAddress( const MachO::any_relocation_info &RE) const { if (isRelocationScattered(RE)) @@ -1831,6 +2284,31 @@ MachOObjectFile::getDylibIDLoadCommand(const LoadCommandInfo &L) const { return getStruct<MachO::dylib_command>(this, L.Ptr); } +MachO::dyld_info_command +MachOObjectFile::getDyldInfoLoadCommand(const LoadCommandInfo &L) const { + return getStruct<MachO::dyld_info_command>(this, L.Ptr); +} + +MachO::dylinker_command +MachOObjectFile::getDylinkerCommand(const LoadCommandInfo &L) const { + return getStruct<MachO::dylinker_command>(this, L.Ptr); +} + +MachO::uuid_command +MachOObjectFile::getUuidCommand(const LoadCommandInfo &L) const { + return getStruct<MachO::uuid_command>(this, L.Ptr); +} + +MachO::source_version_command +MachOObjectFile::getSourceVersionCommand(const LoadCommandInfo &L) const { + return getStruct<MachO::source_version_command>(this, L.Ptr); +} + +MachO::entry_point_command +MachOObjectFile::getEntryPointCommand(const LoadCommandInfo &L) const { + return getStruct<MachO::entry_point_command>(this, L.Ptr); +} + MachO::any_relocation_info MachOObjectFile::getRelocation(DataRefImpl Rel) const { @@ -1880,11 +2358,47 @@ MachOObjectFile::getDataInCodeTableEntry(uint32_t DataOffset, } MachO::symtab_command MachOObjectFile::getSymtabLoadCommand() const { - return getStruct<MachO::symtab_command>(this, SymtabLoadCmd); + if (SymtabLoadCmd) + return getStruct<MachO::symtab_command>(this, SymtabLoadCmd); + + // If there is no SymtabLoadCmd return a load command with zero'ed fields. + MachO::symtab_command Cmd; + Cmd.cmd = MachO::LC_SYMTAB; + Cmd.cmdsize = sizeof(MachO::symtab_command); + Cmd.symoff = 0; + Cmd.nsyms = 0; + Cmd.stroff = 0; + Cmd.strsize = 0; + return Cmd; } MachO::dysymtab_command MachOObjectFile::getDysymtabLoadCommand() const { - return getStruct<MachO::dysymtab_command>(this, DysymtabLoadCmd); + if (DysymtabLoadCmd) + return getStruct<MachO::dysymtab_command>(this, DysymtabLoadCmd); + + // If there is no DysymtabLoadCmd return a load command with zero'ed fields. + MachO::dysymtab_command Cmd; + Cmd.cmd = MachO::LC_DYSYMTAB; + Cmd.cmdsize = sizeof(MachO::dysymtab_command); + Cmd.ilocalsym = 0; + Cmd.nlocalsym = 0; + Cmd.iextdefsym = 0; + Cmd.nextdefsym = 0; + Cmd.iundefsym = 0; + Cmd.nundefsym = 0; + Cmd.tocoff = 0; + Cmd.ntoc = 0; + Cmd.modtaboff = 0; + Cmd.nmodtab = 0; + Cmd.extrefsymoff = 0; + Cmd.nextrefsyms = 0; + Cmd.indirectsymoff = 0; + Cmd.nindirectsyms = 0; + Cmd.extreloff = 0; + Cmd.nextrel = 0; + Cmd.locreloff = 0; + Cmd.nlocrel = 0; + return Cmd; } MachO::linkedit_data_command @@ -1901,6 +2415,69 @@ MachOObjectFile::getDataInCodeLoadCommand() const { return Cmd; } +ArrayRef<uint8_t> MachOObjectFile::getDyldInfoRebaseOpcodes() const { + if (!DyldInfoLoadCmd) + return ArrayRef<uint8_t>(); + + MachO::dyld_info_command DyldInfo + = getStruct<MachO::dyld_info_command>(this, DyldInfoLoadCmd); + const uint8_t *Ptr = reinterpret_cast<const uint8_t*>( + getPtr(this, DyldInfo.rebase_off)); + return ArrayRef<uint8_t>(Ptr, DyldInfo.rebase_size); +} + +ArrayRef<uint8_t> MachOObjectFile::getDyldInfoBindOpcodes() const { + if (!DyldInfoLoadCmd) + return ArrayRef<uint8_t>(); + + MachO::dyld_info_command DyldInfo + = getStruct<MachO::dyld_info_command>(this, DyldInfoLoadCmd); + const uint8_t *Ptr = reinterpret_cast<const uint8_t*>( + getPtr(this, DyldInfo.bind_off)); + return ArrayRef<uint8_t>(Ptr, DyldInfo.bind_size); +} + +ArrayRef<uint8_t> MachOObjectFile::getDyldInfoWeakBindOpcodes() const { + if (!DyldInfoLoadCmd) + return ArrayRef<uint8_t>(); + + MachO::dyld_info_command DyldInfo + = getStruct<MachO::dyld_info_command>(this, DyldInfoLoadCmd); + const uint8_t *Ptr = reinterpret_cast<const uint8_t*>( + getPtr(this, DyldInfo.weak_bind_off)); + return ArrayRef<uint8_t>(Ptr, DyldInfo.weak_bind_size); +} + +ArrayRef<uint8_t> MachOObjectFile::getDyldInfoLazyBindOpcodes() const { + if (!DyldInfoLoadCmd) + return ArrayRef<uint8_t>(); + + MachO::dyld_info_command DyldInfo + = getStruct<MachO::dyld_info_command>(this, DyldInfoLoadCmd); + const uint8_t *Ptr = reinterpret_cast<const uint8_t*>( + getPtr(this, DyldInfo.lazy_bind_off)); + return ArrayRef<uint8_t>(Ptr, DyldInfo.lazy_bind_size); +} + +ArrayRef<uint8_t> MachOObjectFile::getDyldInfoExportsTrie() const { + if (!DyldInfoLoadCmd) + return ArrayRef<uint8_t>(); + + MachO::dyld_info_command DyldInfo + = getStruct<MachO::dyld_info_command>(this, DyldInfoLoadCmd); + const uint8_t *Ptr = reinterpret_cast<const uint8_t*>( + getPtr(this, DyldInfo.export_off)); + return ArrayRef<uint8_t>(Ptr, DyldInfo.export_size); +} + +ArrayRef<uint8_t> MachOObjectFile::getUuid() const { + if (!UuidLoadCmd) + return ArrayRef<uint8_t>(); + // Returning a pointer is fine as uuid doesn't need endian swapping. + const char *Ptr = UuidLoadCmd + offsetof(MachO::uuid_command, uuid); + return ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(Ptr), 16); +} + StringRef MachOObjectFile::getStringTableData() const { MachO::symtab_command S = getSymtabLoadCommand(); return getData().substr(S.stroff, S.strsize); @@ -1908,7 +2485,7 @@ StringRef MachOObjectFile::getStringTableData() const { bool MachOObjectFile::is64Bit() const { return getType() == getMachOType(false, true) || - getType() == getMachOType(true, true); + getType() == getMachOType(true, true); } void MachOObjectFile::ReadULEB128s(uint64_t Index, @@ -1923,30 +2500,28 @@ void MachOObjectFile::ReadULEB128s(uint64_t Index, } } -const char *MachOObjectFile::getSectionPointer(DataRefImpl Rel) const { - return Sections[Rel.d.a]; +bool MachOObjectFile::isRelocatableObject() const { + return getHeader().filetype == MachO::MH_OBJECT; } -ErrorOr<ObjectFile *> -ObjectFile::createMachOObjectFile(std::unique_ptr<MemoryBuffer> &Buffer) { - StringRef Magic = Buffer->getBuffer().slice(0, 4); +ErrorOr<std::unique_ptr<MachOObjectFile>> +ObjectFile::createMachOObjectFile(MemoryBufferRef Buffer) { + StringRef Magic = Buffer.getBuffer().slice(0, 4); std::error_code EC; std::unique_ptr<MachOObjectFile> Ret; if (Magic == "\xFE\xED\xFA\xCE") - Ret.reset(new MachOObjectFile(std::move(Buffer), false, false, EC)); + Ret.reset(new MachOObjectFile(Buffer, false, false, EC)); else if (Magic == "\xCE\xFA\xED\xFE") - Ret.reset(new MachOObjectFile(std::move(Buffer), true, false, EC)); + Ret.reset(new MachOObjectFile(Buffer, true, false, EC)); else if (Magic == "\xFE\xED\xFA\xCF") - Ret.reset(new MachOObjectFile(std::move(Buffer), false, true, EC)); + Ret.reset(new MachOObjectFile(Buffer, false, true, EC)); else if (Magic == "\xCF\xFA\xED\xFE") - Ret.reset(new MachOObjectFile(std::move(Buffer), true, true, EC)); + Ret.reset(new MachOObjectFile(Buffer, true, true, EC)); else return object_error::parse_failed; if (EC) return EC; - return Ret.release(); + return std::move(Ret); } -} // end namespace object -} // end namespace llvm diff --git a/lib/Object/MachOUniversal.cpp b/lib/Object/MachOUniversal.cpp index 4ba5d96..77aeb63 100644 --- a/lib/Object/MachOUniversal.cpp +++ b/lib/Object/MachOUniversal.cpp @@ -67,14 +67,13 @@ MachOUniversalBinary::ObjectForArch::ObjectForArch( } } -ErrorOr<std::unique_ptr<ObjectFile>> +ErrorOr<std::unique_ptr<MachOObjectFile>> MachOUniversalBinary::ObjectForArch::getAsObjectFile() const { if (Parent) { StringRef ParentData = Parent->getData(); StringRef ObjectData = ParentData.substr(Header.offset, Header.size); - std::string ObjectName = Parent->getFileName().str(); - std::unique_ptr<MemoryBuffer> ObjBuffer( - MemoryBuffer::getMemBuffer(ObjectData, ObjectName, false)); + StringRef ObjectName = Parent->getFileName(); + MemoryBufferRef ObjBuffer(ObjectData, ObjectName); return ObjectFile::createMachOObjectFile(ObjBuffer); } return object_error::parse_failed; @@ -85,13 +84,12 @@ std::error_code MachOUniversalBinary::ObjectForArch::getAsArchive( if (Parent) { StringRef ParentData = Parent->getData(); StringRef ObjectData = ParentData.substr(Header.offset, Header.size); - std::string ObjectName = Parent->getFileName().str(); - std::unique_ptr<MemoryBuffer> ObjBuffer( - MemoryBuffer::getMemBuffer(ObjectData, ObjectName, false)); - ErrorOr<Archive *> Obj = Archive::create(std::move(ObjBuffer)); + StringRef ObjectName = Parent->getFileName(); + MemoryBufferRef ObjBuffer(ObjectData, ObjectName); + ErrorOr<std::unique_ptr<Archive>> Obj = Archive::create(ObjBuffer); if (std::error_code EC = Obj.getError()) return EC; - Result.reset(Obj.get()); + Result = std::move(Obj.get()); return object_error::success; } return object_error::parse_failed; @@ -99,21 +97,20 @@ std::error_code MachOUniversalBinary::ObjectForArch::getAsArchive( void MachOUniversalBinary::anchor() { } -ErrorOr<MachOUniversalBinary *> -MachOUniversalBinary::create(std::unique_ptr<MemoryBuffer> Source) { +ErrorOr<std::unique_ptr<MachOUniversalBinary>> +MachOUniversalBinary::create(MemoryBufferRef Source) { std::error_code EC; std::unique_ptr<MachOUniversalBinary> Ret( - new MachOUniversalBinary(std::move(Source), EC)); + new MachOUniversalBinary(Source, EC)); if (EC) return EC; - return Ret.release(); + return std::move(Ret); } -MachOUniversalBinary::MachOUniversalBinary(std::unique_ptr<MemoryBuffer> Source, +MachOUniversalBinary::MachOUniversalBinary(MemoryBufferRef Source, std::error_code &ec) - : Binary(Binary::ID_MachOUniversalBinary, std::move(Source)), - NumberOfObjects(0) { - if (Data->getBufferSize() < sizeof(MachO::fat_header)) { + : Binary(Binary::ID_MachOUniversalBinary, Source), NumberOfObjects(0) { + if (Data.getBufferSize() < sizeof(MachO::fat_header)) { ec = object_error::invalid_file_type; return; } @@ -142,7 +139,7 @@ static bool getCTMForArch(Triple::ArchType Arch, MachO::CPUType &CTM) { } } -ErrorOr<std::unique_ptr<ObjectFile>> +ErrorOr<std::unique_ptr<MachOObjectFile>> MachOUniversalBinary::getObjectForArch(Triple::ArchType Arch) const { MachO::CPUType CTM; if (!getCTMForArch(Arch, CTM)) diff --git a/lib/Object/Object.cpp b/lib/Object/Object.cpp index 567d87f..84a5df0 100644 --- a/lib/Object/Object.cpp +++ b/lib/Object/Object.cpp @@ -19,12 +19,13 @@ using namespace llvm; using namespace object; -inline ObjectFile *unwrap(LLVMObjectFileRef OF) { - return reinterpret_cast<ObjectFile*>(OF); +inline OwningBinary<ObjectFile> *unwrap(LLVMObjectFileRef OF) { + return reinterpret_cast<OwningBinary<ObjectFile> *>(OF); } -inline LLVMObjectFileRef wrap(const ObjectFile *OF) { - return reinterpret_cast<LLVMObjectFileRef>(const_cast<ObjectFile*>(OF)); +inline LLVMObjectFileRef wrap(const OwningBinary<ObjectFile> *OF) { + return reinterpret_cast<LLVMObjectFileRef>( + const_cast<OwningBinary<ObjectFile> *>(OF)); } inline section_iterator *unwrap(LLVMSectionIteratorRef SI) { @@ -60,10 +61,14 @@ wrap(const relocation_iterator *SI) { // ObjectFile creation LLVMObjectFileRef LLVMCreateObjectFile(LLVMMemoryBufferRef MemBuf) { std::unique_ptr<MemoryBuffer> Buf(unwrap(MemBuf)); - ErrorOr<ObjectFile *> ObjOrErr(ObjectFile::createObjectFile(Buf)); - Buf.release(); - ObjectFile *Obj = ObjOrErr ? ObjOrErr.get() : nullptr; - return wrap(Obj); + ErrorOr<std::unique_ptr<ObjectFile>> ObjOrErr( + ObjectFile::createObjectFile(Buf->getMemBufferRef())); + std::unique_ptr<ObjectFile> Obj; + if (!ObjOrErr) + return nullptr; + + auto *Ret = new OwningBinary<ObjectFile>(std::move(ObjOrErr.get()), std::move(Buf)); + return wrap(Ret); } void LLVMDisposeObjectFile(LLVMObjectFileRef ObjectFile) { @@ -71,8 +76,9 @@ void LLVMDisposeObjectFile(LLVMObjectFileRef ObjectFile) { } // ObjectFile Section iterators -LLVMSectionIteratorRef LLVMGetSections(LLVMObjectFileRef ObjectFile) { - section_iterator SI = unwrap(ObjectFile)->section_begin(); +LLVMSectionIteratorRef LLVMGetSections(LLVMObjectFileRef OF) { + OwningBinary<ObjectFile> *OB = unwrap(OF); + section_iterator SI = OB->getBinary()->section_begin(); return wrap(new section_iterator(SI)); } @@ -80,9 +86,10 @@ void LLVMDisposeSectionIterator(LLVMSectionIteratorRef SI) { delete unwrap(SI); } -LLVMBool LLVMIsSectionIteratorAtEnd(LLVMObjectFileRef ObjectFile, - LLVMSectionIteratorRef SI) { - return (*unwrap(SI) == unwrap(ObjectFile)->section_end()) ? 1 : 0; +LLVMBool LLVMIsSectionIteratorAtEnd(LLVMObjectFileRef OF, + LLVMSectionIteratorRef SI) { + OwningBinary<ObjectFile> *OB = unwrap(OF); + return (*unwrap(SI) == OB->getBinary()->section_end()) ? 1 : 0; } void LLVMMoveToNextSection(LLVMSectionIteratorRef SI) { @@ -96,8 +103,9 @@ void LLVMMoveToContainingSection(LLVMSectionIteratorRef Sect, } // ObjectFile Symbol iterators -LLVMSymbolIteratorRef LLVMGetSymbols(LLVMObjectFileRef ObjectFile) { - symbol_iterator SI = unwrap(ObjectFile)->symbol_begin(); +LLVMSymbolIteratorRef LLVMGetSymbols(LLVMObjectFileRef OF) { + OwningBinary<ObjectFile> *OB = unwrap(OF); + symbol_iterator SI = OB->getBinary()->symbol_begin(); return wrap(new symbol_iterator(SI)); } @@ -105,9 +113,10 @@ void LLVMDisposeSymbolIterator(LLVMSymbolIteratorRef SI) { delete unwrap(SI); } -LLVMBool LLVMIsSymbolIteratorAtEnd(LLVMObjectFileRef ObjectFile, - LLVMSymbolIteratorRef SI) { - return (*unwrap(SI) == unwrap(ObjectFile)->symbol_end()) ? 1 : 0; +LLVMBool LLVMIsSymbolIteratorAtEnd(LLVMObjectFileRef OF, + LLVMSymbolIteratorRef SI) { + OwningBinary<ObjectFile> *OB = unwrap(OF); + return (*unwrap(SI) == OB->getBinary()->symbol_end()) ? 1 : 0; } void LLVMMoveToNextSymbol(LLVMSymbolIteratorRef SI) { @@ -123,10 +132,7 @@ const char *LLVMGetSectionName(LLVMSectionIteratorRef SI) { } uint64_t LLVMGetSectionSize(LLVMSectionIteratorRef SI) { - uint64_t ret; - if (std::error_code ec = (*unwrap(SI))->getSize(ret)) - report_fatal_error(ec.message()); - return ret; + return (*unwrap(SI))->getSize(); } const char *LLVMGetSectionContents(LLVMSectionIteratorRef SI) { @@ -137,18 +143,12 @@ const char *LLVMGetSectionContents(LLVMSectionIteratorRef SI) { } uint64_t LLVMGetSectionAddress(LLVMSectionIteratorRef SI) { - uint64_t ret; - if (std::error_code ec = (*unwrap(SI))->getAddress(ret)) - report_fatal_error(ec.message()); - return ret; + return (*unwrap(SI))->getAddress(); } LLVMBool LLVMGetSectionContainsSymbol(LLVMSectionIteratorRef SI, LLVMSymbolIteratorRef Sym) { - bool ret; - if (std::error_code ec = (*unwrap(SI))->containsSymbol(**unwrap(Sym), ret)) - report_fatal_error(ec.message()); - return ret; + return (*unwrap(SI))->containsSymbol(**unwrap(Sym)); } // Section Relocation iterators diff --git a/lib/Object/ObjectFile.cpp b/lib/Object/ObjectFile.cpp index f5488c6..fd78271 100644 --- a/lib/Object/ObjectFile.cpp +++ b/lib/Object/ObjectFile.cpp @@ -11,6 +11,8 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Object/COFF.h" +#include "llvm/Object/MachO.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" @@ -23,8 +25,8 @@ using namespace object; void ObjectFile::anchor() { } -ObjectFile::ObjectFile(unsigned int Type, std::unique_ptr<MemoryBuffer> Source) - : SymbolicFile(Type, std::move(Source)) {} +ObjectFile::ObjectFile(unsigned int Type, MemoryBufferRef Source) + : SymbolicFile(Type, Source) {} std::error_code ObjectFile::printSymbolName(raw_ostream &OS, DataRefImpl Symb) const { @@ -45,11 +47,11 @@ section_iterator ObjectFile::getRelocatedSection(DataRefImpl Sec) const { return section_iterator(SectionRef(Sec, this)); } -ErrorOr<ObjectFile *> -ObjectFile::createObjectFile(std::unique_ptr<MemoryBuffer> &Object, - sys::fs::file_magic Type) { +ErrorOr<std::unique_ptr<ObjectFile>> +ObjectFile::createObjectFile(MemoryBufferRef Object, sys::fs::file_magic Type) { + StringRef Data = Object.getBuffer(); if (Type == sys::fs::file_magic::unknown) - Type = sys::fs::identify_magic(Object->getBuffer()); + Type = sys::fs::identify_magic(Data); switch (Type) { case sys::fs::file_magic::unknown: @@ -58,6 +60,7 @@ ObjectFile::createObjectFile(std::unique_ptr<MemoryBuffer> &Object, case sys::fs::file_magic::macho_universal_binary: case sys::fs::file_magic::windows_resource: return object_error::invalid_file_type; + case sys::fs::file_magic::elf: case sys::fs::file_magic::elf_relocatable: case sys::fs::file_magic::elf_executable: case sys::fs::file_magic::elf_shared_object: @@ -77,15 +80,24 @@ ObjectFile::createObjectFile(std::unique_ptr<MemoryBuffer> &Object, case sys::fs::file_magic::coff_object: case sys::fs::file_magic::coff_import_library: case sys::fs::file_magic::pecoff_executable: - return createCOFFObjectFile(std::move(Object)); + return createCOFFObjectFile(Object); } llvm_unreachable("Unexpected Object File Type"); } -ErrorOr<ObjectFile *> ObjectFile::createObjectFile(StringRef ObjectPath) { +ErrorOr<OwningBinary<ObjectFile>> +ObjectFile::createObjectFile(StringRef ObjectPath) { ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr = MemoryBuffer::getFile(ObjectPath); if (std::error_code EC = FileOrErr.getError()) return EC; - return createObjectFile(FileOrErr.get()); + std::unique_ptr<MemoryBuffer> Buffer = std::move(FileOrErr.get()); + + ErrorOr<std::unique_ptr<ObjectFile>> ObjOrErr = + createObjectFile(Buffer->getMemBufferRef()); + if (std::error_code EC = ObjOrErr.getError()) + return EC; + std::unique_ptr<ObjectFile> Obj = std::move(ObjOrErr.get()); + + return OwningBinary<ObjectFile>(std::move(Obj), std::move(Buffer)); } diff --git a/lib/Object/RecordStreamer.h b/lib/Object/RecordStreamer.h index 10e70ef..7dacbdf 100644 --- a/lib/Object/RecordStreamer.h +++ b/lib/Object/RecordStreamer.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_OBJECT_RECORD_STREAMER -#define LLVM_OBJECT_RECORD_STREAMER +#ifndef LLVM_LIB_OBJECT_RECORDSTREAMER_H +#define LLVM_LIB_OBJECT_RECORDSTREAMER_H #include "llvm/MC/MCStreamer.h" diff --git a/lib/Object/SymbolicFile.cpp b/lib/Object/SymbolicFile.cpp index 30cf1a0..ffd3dbc 100644 --- a/lib/Object/SymbolicFile.cpp +++ b/lib/Object/SymbolicFile.cpp @@ -19,34 +19,31 @@ using namespace llvm; using namespace object; -SymbolicFile::SymbolicFile(unsigned int Type, - std::unique_ptr<MemoryBuffer> Source) - : Binary(Type, std::move(Source)) {} +SymbolicFile::SymbolicFile(unsigned int Type, MemoryBufferRef Source) + : Binary(Type, Source) {} SymbolicFile::~SymbolicFile() {} -ErrorOr<SymbolicFile *> -SymbolicFile::createSymbolicFile(std::unique_ptr<MemoryBuffer> &Object, - sys::fs::file_magic Type, - LLVMContext *Context) { +ErrorOr<std::unique_ptr<SymbolicFile>> SymbolicFile::createSymbolicFile( + MemoryBufferRef Object, sys::fs::file_magic Type, LLVMContext *Context) { + StringRef Data = Object.getBuffer(); if (Type == sys::fs::file_magic::unknown) - Type = sys::fs::identify_magic(Object->getBuffer()); + Type = sys::fs::identify_magic(Data); switch (Type) { case sys::fs::file_magic::bitcode: if (Context) - return IRObjectFile::createIRObjectFile(std::move(Object), *Context); + return IRObjectFile::createIRObjectFile(Object, *Context); // Fallthrough case sys::fs::file_magic::unknown: case sys::fs::file_magic::archive: case sys::fs::file_magic::macho_universal_binary: case sys::fs::file_magic::windows_resource: return object_error::invalid_file_type; - case sys::fs::file_magic::elf_relocatable: + case sys::fs::file_magic::elf: case sys::fs::file_magic::elf_executable: case sys::fs::file_magic::elf_shared_object: case sys::fs::file_magic::elf_core: - case sys::fs::file_magic::macho_object: case sys::fs::file_magic::macho_executable: case sys::fs::file_magic::macho_fixed_virtual_memory_shared_lib: case sys::fs::file_magic::macho_core: @@ -56,10 +53,26 @@ SymbolicFile::createSymbolicFile(std::unique_ptr<MemoryBuffer> &Object, case sys::fs::file_magic::macho_bundle: case sys::fs::file_magic::macho_dynamically_linked_shared_lib_stub: case sys::fs::file_magic::macho_dsym_companion: - case sys::fs::file_magic::coff_object: case sys::fs::file_magic::coff_import_library: case sys::fs::file_magic::pecoff_executable: return ObjectFile::createObjectFile(Object, Type); + case sys::fs::file_magic::elf_relocatable: + case sys::fs::file_magic::macho_object: + case sys::fs::file_magic::coff_object: { + ErrorOr<std::unique_ptr<ObjectFile>> Obj = + ObjectFile::createObjectFile(Object, Type); + if (!Obj || !Context) + return std::move(Obj); + + ErrorOr<MemoryBufferRef> BCData = + IRObjectFile::findBitcodeInObject(*Obj->get()); + if (!BCData) + return std::move(Obj); + + return IRObjectFile::createIRObjectFile( + MemoryBufferRef(BCData->getBuffer(), Object.getBufferIdentifier()), + *Context); + } } llvm_unreachable("Unexpected Binary File Type"); } |