diff options
author | Stephen Hines <srhines@google.com> | 2013-08-07 15:07:10 -0700 |
---|---|---|
committer | Stephen Hines <srhines@google.com> | 2013-08-07 15:07:10 -0700 |
commit | fab2daa4a1127ecb217abe2b07c1769122b6fee1 (patch) | |
tree | 268ebfd1963fd98ba412e76819afdf95a7d4267b /lib/Object | |
parent | 8197ac1c1a0a91baa70c4dea8cb488f254ef974c (diff) | |
parent | 10251753b6897adcd22cc981c0cc42f348c109de (diff) | |
download | external_llvm-fab2daa4a1127ecb217abe2b07c1769122b6fee1.zip external_llvm-fab2daa4a1127ecb217abe2b07c1769122b6fee1.tar.gz external_llvm-fab2daa4a1127ecb217abe2b07c1769122b6fee1.tar.bz2 |
Merge commit '10251753b6897adcd22cc981c0cc42f348c109de' into merge-20130807
Conflicts:
lib/Archive/ArchiveReader.cpp
lib/Support/Unix/PathV2.inc
Change-Id: I29d8c1e321a4a380b6013f00bac6a8e4b593cc4e
Diffstat (limited to 'lib/Object')
-rw-r--r-- | lib/Object/Archive.cpp | 275 | ||||
-rw-r--r-- | lib/Object/Binary.cpp | 22 | ||||
-rw-r--r-- | lib/Object/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/Object/COFFObjectFile.cpp | 155 | ||||
-rw-r--r-- | lib/Object/ELFYAML.cpp | 112 | ||||
-rw-r--r-- | lib/Object/Error.cpp | 10 | ||||
-rw-r--r-- | lib/Object/MachOObjectFile.cpp | 56 | ||||
-rw-r--r-- | lib/Object/MachOUniversal.cpp | 139 | ||||
-rw-r--r-- | lib/Object/ObjectFile.cpp | 6 | ||||
-rw-r--r-- | lib/Object/YAML.cpp | 5 |
10 files changed, 622 insertions, 159 deletions
diff --git a/lib/Object/Archive.cpp b/lib/Object/Archive.cpp index be35924..71efca2 100644 --- a/lib/Object/Archive.cpp +++ b/lib/Object/Archive.cpp @@ -13,33 +13,110 @@ #include "llvm/Object/Archive.h" #include "llvm/ADT/APInt.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Twine.h" #include "llvm/Support/Endian.h" #include "llvm/Support/MemoryBuffer.h" using namespace llvm; using namespace object; -static const char *Magic = "!<arch>\n"; +static const char *const Magic = "!<arch>\n"; -static bool isInternalMember(const ArchiveMemberHeader &amh) { - static const char *const internals[] = { - "/", - "//", - "#_LLVM_SYM_TAB_#" - }; +void Archive::anchor() { } + +StringRef ArchiveMemberHeader::getName() const { + char EndCond; + if (Name[0] == '/' || Name[0] == '#') + EndCond = ' '; + else + EndCond = '/'; + llvm::StringRef::size_type end = + llvm::StringRef(Name, sizeof(Name)).find(EndCond); + if (end == llvm::StringRef::npos) + end = sizeof(Name); + assert(end <= sizeof(Name) && end > 0); + // Don't include the EndCond if there is one. + return llvm::StringRef(Name, end); +} + +uint32_t ArchiveMemberHeader::getSize() const { + uint32_t Ret; + if (llvm::StringRef(Size, sizeof(Size)).rtrim(" ").getAsInteger(10, Ret)) + llvm_unreachable("Size is not a decimal number."); + return Ret; +} + +sys::fs::perms ArchiveMemberHeader::getAccessMode() const { + unsigned Ret; + if (StringRef(AccessMode, sizeof(AccessMode)).rtrim(" ").getAsInteger(8, Ret)) + llvm_unreachable("Access mode is not an octal number."); + return static_cast<sys::fs::perms>(Ret); +} - StringRef name = amh.getName(); - for (std::size_t i = 0; i < sizeof(internals) / sizeof(*internals); ++i) { - if (name == internals[i]) - return true; +sys::TimeValue ArchiveMemberHeader::getLastModified() const { + unsigned Seconds; + if (StringRef(LastModified, sizeof(LastModified)).rtrim(" ") + .getAsInteger(10, Seconds)) + llvm_unreachable("Last modified time not a decimal number."); + + sys::TimeValue Ret; + Ret.fromEpochTime(Seconds); + return Ret; +} + +unsigned ArchiveMemberHeader::getUID() const { + unsigned Ret; + if (StringRef(UID, sizeof(UID)).rtrim(" ").getAsInteger(10, Ret)) + llvm_unreachable("UID time not a decimal number."); + return Ret; +} + +unsigned ArchiveMemberHeader::getGID() const { + unsigned Ret; + if (StringRef(GID, sizeof(GID)).rtrim(" ").getAsInteger(10, Ret)) + llvm_unreachable("GID time not a decimal number."); + return Ret; +} + +Archive::Child::Child(const Archive *Parent, const char *Start) + : Parent(Parent) { + if (!Start) + return; + + const ArchiveMemberHeader *Header = + reinterpret_cast<const ArchiveMemberHeader *>(Start); + Data = StringRef(Start, sizeof(ArchiveMemberHeader) + Header->getSize()); + + // Setup StartOfFile and PaddingBytes. + StartOfFile = sizeof(ArchiveMemberHeader); + // Don't include attached name. + StringRef Name = Header->getName(); + if (Name.startswith("#1/")) { + uint64_t NameSize; + if (Name.substr(3).rtrim(" ").getAsInteger(10, NameSize)) + llvm_unreachable("Long name length is not an integer"); + StartOfFile += NameSize; } - return false; } -void Archive::anchor() { } +Archive::Child Archive::Child::getNext() const { + size_t SpaceToSkip = Data.size(); + // If it's odd, add 1 to make it even. + if (SpaceToSkip & 1) + ++SpaceToSkip; + + const char *NextLoc = Data.data() + SpaceToSkip; + + // Check to see if this is past the end of the archive. + if (NextLoc >= Parent->Data->getBufferEnd()) + return Child(Parent, NULL); + + return Child(Parent, NextLoc); +} error_code Archive::Child::getName(StringRef &Result) const { - StringRef name = ToHeader(Data.data())->getName(); + StringRef name = getRawName(); // Check if it's a special name. if (name[0] == '/') { if (name.size() == 1) { // Linker member. @@ -79,7 +156,8 @@ error_code Archive::Child::getName(StringRef &Result) const { uint64_t name_size; if (name.substr(3).rtrim(" ").getAsInteger(10, name_size)) llvm_unreachable("Long name length is not an ingeter"); - Result = Data.substr(sizeof(ArchiveMemberHeader), name_size); + Result = Data.substr(sizeof(ArchiveMemberHeader), name_size) + .rtrim(StringRef("\0", 1)); return object_error::success; } // It's a simple name. @@ -90,6 +168,20 @@ error_code Archive::Child::getName(StringRef &Result) const { return object_error::success; } +error_code Archive::Child::getMemoryBuffer(OwningPtr<MemoryBuffer> &Result, + bool FullPath) const { + StringRef Name; + if (error_code ec = getName(Name)) + return ec; + SmallString<128> Path; + Result.reset(MemoryBuffer::getMemBuffer( + getBuffer(), FullPath ? (Twine(Parent->getFileName()) + "(" + Name + ")") + .toStringRef(Path) + : Name, + false)); + return error_code::success(); +} + error_code Archive::Child::getAsBinary(OwningPtr<Binary> &Result) const { OwningPtr<Binary> ret; OwningPtr<MemoryBuffer> Buff; @@ -102,11 +194,11 @@ error_code Archive::Child::getAsBinary(OwningPtr<Binary> &Result) const { } Archive::Archive(MemoryBuffer *source, error_code &ec) - : Binary(Binary::ID_Archive, source) { + : Binary(Binary::ID_Archive, source), SymbolTable(end_children()) { // Check for sufficient magic. - if (!source || source->getBufferSize() - < (8 + sizeof(ArchiveMemberHeader) + 2) // Smallest archive. - || StringRef(source->getBufferStart(), 8) != Magic) { + assert(source); + if (source->getBufferSize() < 8 || + StringRef(source->getBufferStart(), 8) != Magic) { ec = object_error::invalid_file_type; return; } @@ -115,19 +207,22 @@ Archive::Archive(MemoryBuffer *source, error_code &ec) child_iterator i = begin_children(false); child_iterator e = end_children(); - StringRef name; - if ((ec = i->getName(name))) + if (i == e) { + ec = object_error::success; return; + } + + StringRef Name = i->getRawName(); // Below is the pattern that is used to figure out the archive format // GNU archive format - // First member : / (points to the symbol table ) + // First member : / (may exist, if it exists, points to the symbol table ) // Second member : // (may exist, if it exists, points to the string table) // Note : The string table is used if the filename exceeds 15 characters // BSD archive format - // First member : __.SYMDEF (points to the symbol table) - // There is no string table, if the filename exceeds 15 characters or has a - // embedded space, the filename has #1/<size>, The size represents the size + // First member : __.SYMDEF or "__.SYMDEF SORTED" (the symbol table) + // There is no string table, if the filename exceeds 15 characters or has a + // embedded space, the filename has #1/<size>, The size represents the size // of the filename that needs to be read after the archive header // COFF archive format // First member : / @@ -137,56 +232,97 @@ Archive::Archive(MemoryBuffer *source, error_code &ec) // even if the string table is empty. However, lib.exe does not in fact // seem to create the third member if there's no member whose filename // exceeds 15 characters. So the third member is optional. - if (name == "/") { + + if (Name == "__.SYMDEF") { + Format = K_BSD; SymbolTable = i; - StringTable = e; - if (i != e) ++i; - if (i == e) { - ec = object_error::parse_failed; - return; - } - if ((ec = i->getName(name))) + ++i; + FirstRegular = i; + ec = object_error::success; + return; + } + + if (Name.startswith("#1/")) { + Format = K_BSD; + // We know this is BSD, so getName will work since there is no string table. + ec = i->getName(Name); + if (ec) return; - if (name[0] != '/') { - Format = K_GNU; - } else if ((name.size() > 1) && (name == "//")) { - Format = K_GNU; - StringTable = i; + if (Name == "__.SYMDEF SORTED") { + SymbolTable = i; ++i; - } else { - Format = K_COFF; - if (i != e) { - SymbolTable = i; - ++i; - } - if (i != e) { - if ((ec = i->getName(name))) - return; - if (name == "//") - StringTable = i; - } } - } else if (name == "__.SYMDEF") { - Format = K_BSD; + FirstRegular = i; + return; + } + + if (Name == "/") { SymbolTable = i; - StringTable = e; - } + + ++i; + if (i == e) { + ec = object_error::parse_failed; + return; + } + Name = i->getRawName(); + } + + if (Name == "//") { + Format = K_GNU; + StringTable = i; + ++i; + FirstRegular = i; + ec = object_error::success; + return; + } + + if (Name[0] != '/') { + Format = K_GNU; + FirstRegular = i; + ec = object_error::success; + return; + } + + if (Name != "/") { + ec = object_error::parse_failed; + return; + } + + Format = K_COFF; + SymbolTable = i; + + ++i; + if (i == e) { + FirstRegular = i; + ec = object_error::success; + return; + } + + Name = i->getRawName(); + + if (Name == "//") { + StringTable = i; + ++i; + } + + FirstRegular = i; ec = object_error::success; } -Archive::child_iterator Archive::begin_children(bool skip_internal) const { +Archive::child_iterator Archive::begin_children(bool SkipInternal) const { + if (Data->getBufferSize() == 8) // empty archive. + return end_children(); + + if (SkipInternal) + return FirstRegular; + const char *Loc = Data->getBufferStart() + strlen(Magic); - size_t Size = sizeof(ArchiveMemberHeader) + - ToHeader(Loc)->getSize(); - Child c(this, StringRef(Loc, Size)); - // Skip internals at the beginning of an archive. - if (skip_internal && isInternalMember(*ToHeader(Loc))) - return c.getNext(); + Child c(this, Loc); return c; } Archive::child_iterator Archive::end_children() const { - return Child(this, StringRef(0, 0)); + return Child(this, NULL); } error_code Archive::Symbol::getName(StringRef &Result) const { @@ -234,9 +370,7 @@ error_code Archive::Symbol::getMember(child_iterator &Result) const { } const char *Loc = Parent->getData().begin() + Offset; - size_t Size = sizeof(ArchiveMemberHeader) + - ToHeader(Loc)->getSize(); - Result = Child(Parent, StringRef(Loc, Size)); + Result = Child(Parent, Loc); return object_error::success; } @@ -251,6 +385,9 @@ Archive::Symbol Archive::Symbol::getNext() const { } Archive::symbol_iterator Archive::begin_symbols() const { + if (!hasSymbolTable()) + return symbol_iterator(Symbol(this, 0, 0)); + const char *buf = SymbolTable->getBuffer().begin(); if (kind() == K_GNU) { uint32_t symbol_count = 0; @@ -271,11 +408,13 @@ Archive::symbol_iterator Archive::begin_symbols() const { } Archive::symbol_iterator Archive::end_symbols() const { + if (!hasSymbolTable()) + return symbol_iterator(Symbol(this, 0, 0)); + const char *buf = SymbolTable->getBuffer().begin(); uint32_t symbol_count = 0; if (kind() == K_GNU) { symbol_count = *reinterpret_cast<const support::ubig32_t*>(buf); - buf += sizeof(uint32_t) + (symbol_count * (sizeof(uint32_t))); } else if (kind() == K_BSD) { llvm_unreachable("BSD archive format is not supported"); } else { @@ -305,3 +444,7 @@ Archive::child_iterator Archive::findSym(StringRef name) const { } return end_children(); } + +bool Archive::hasSymbolTable() const { + return SymbolTable != end_children(); +} diff --git a/lib/Object/Binary.cpp b/lib/Object/Binary.cpp index 201899f..fd9d3b4 100644 --- a/lib/Object/Binary.cpp +++ b/lib/Object/Binary.cpp @@ -20,6 +20,7 @@ // Include headers for createBinary. #include "llvm/Object/Archive.h" #include "llvm/Object/COFF.h" +#include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" using namespace llvm; @@ -74,7 +75,8 @@ error_code object::createBinary(MemoryBuffer *Source, case sys::fs::file_magic::macho_dynamically_linked_shared_lib: case sys::fs::file_magic::macho_dynamic_linker: case sys::fs::file_magic::macho_bundle: - case sys::fs::file_magic::macho_dynamically_linked_shared_lib_stub: { + case sys::fs::file_magic::macho_dynamically_linked_shared_lib_stub: + case sys::fs::file_magic::macho_dsym_companion: { OwningPtr<Binary> ret( ObjectFile::createMachOObjectFile(scopedSource.take())); if (!ret) @@ -82,16 +84,28 @@ error_code object::createBinary(MemoryBuffer *Source, Result.swap(ret); return object_error::success; } + case sys::fs::file_magic::macho_universal_binary: { + OwningPtr<Binary> ret(new MachOUniversalBinary(scopedSource.take(), ec)); + if (ec) return ec; + Result.swap(ret); + return object_error::success; + } case sys::fs::file_magic::coff_object: case sys::fs::file_magic::pecoff_executable: { - OwningPtr<Binary> ret(new COFFObjectFile(scopedSource.take(), ec)); - if (ec) return ec; + OwningPtr<Binary> ret( + ObjectFile::createCOFFObjectFile(scopedSource.take())); + if (!ret) + return object_error::invalid_file_type; Result.swap(ret); return object_error::success; } - default: // Unrecognized object file format. + case sys::fs::file_magic::unknown: + case sys::fs::file_magic::bitcode: { + // Unrecognized object file format. return object_error::invalid_file_type; + } } + llvm_unreachable("Unexpected Binary File Type"); } error_code object::createBinary(StringRef Path, OwningPtr<Binary> &Result) { diff --git a/lib/Object/CMakeLists.txt b/lib/Object/CMakeLists.txt index cec0e28..2c2cc8e 100644 --- a/lib/Object/CMakeLists.txt +++ b/lib/Object/CMakeLists.txt @@ -7,6 +7,7 @@ add_llvm_library(LLVMObject ELFYAML.cpp Error.cpp MachOObjectFile.cpp + MachOUniversal.cpp Object.cpp ObjectFile.cpp YAML.cpp diff --git a/lib/Object/COFFObjectFile.cpp b/lib/Object/COFFObjectFile.cpp index 269d873..cb029f9 100644 --- a/lib/Object/COFFObjectFile.cpp +++ b/lib/Object/COFFObjectFile.cpp @@ -39,18 +39,19 @@ bool checkSize(const MemoryBuffer *m, error_code &ec, uint64_t size) { return true; } -// Returns false if any bytes in [addr, addr + size) fall outsize of m. -bool checkAddr(const MemoryBuffer *m, - error_code &ec, - uintptr_t addr, - uint64_t size) { - if (addr + size < addr || - addr + size < size || - addr + size > uintptr_t(m->getBufferEnd())) { - ec = object_error::unexpected_eof; - return false; +// Sets Obj unless any bytes in [addr, addr + size) fall outsize of m. +// Returns unexpected_eof if error. +template<typename T> +error_code getObject(const T *&Obj, const MemoryBuffer *M, const uint8_t *Ptr, + const size_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; } - return true; + Obj = reinterpret_cast<const T *>(Addr); + return object_error::success; } } @@ -60,12 +61,12 @@ const coff_symbol *COFFObjectFile::toSymb(DataRefImpl Symb) const { # 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 < Header->PointerToSymbolTable - || offset >= Header->PointerToSymbolTable - + (Header->NumberOfSymbols * sizeof(coff_symbol))) + if (offset < COFFHeader->PointerToSymbolTable + || offset >= COFFHeader->PointerToSymbolTable + + (COFFHeader->NumberOfSymbols * sizeof(coff_symbol))) report_fatal_error("Symbol was outside of symbol table."); - assert((offset - Header->PointerToSymbolTable) % sizeof(coff_symbol) + assert((offset - COFFHeader->PointerToSymbolTable) % sizeof(coff_symbol) == 0 && "Symbol did not point to the beginning of a symbol"); # endif @@ -78,7 +79,7 @@ const coff_section *COFFObjectFile::toSec(DataRefImpl Sec) const { # ifndef NDEBUG // Verify that the section points to a valid entry in the section table. if (addr < SectionTable - || addr >= (SectionTable + Header->NumberOfSections)) + || addr >= (SectionTable + COFFHeader->NumberOfSections)) report_fatal_error("Section was outside of section table."); uintptr_t offset = uintptr_t(addr) - uintptr_t(SectionTable); @@ -432,7 +433,9 @@ relocation_iterator COFFObjectFile::getSectionRelEnd(DataRefImpl Sec) const { COFFObjectFile::COFFObjectFile(MemoryBuffer *Object, error_code &ec) : ObjectFile(Binary::ID_COFF, Object) - , Header(0) + , COFFHeader(0) + , PE32Header(0) + , DataDirectory(0) , SectionTable(0) , SymbolTable(0) , StringTable(0) @@ -440,55 +443,71 @@ COFFObjectFile::COFFObjectFile(MemoryBuffer *Object, error_code &ec) // Check that we at least have enough room for a header. if (!checkSize(Data, ec, sizeof(coff_file_header))) return; - // The actual starting location of the COFF header in the file. This can be - // non-zero in PE/COFF files. - uint64_t HeaderStart = 0; + // The current location in the file where we are looking at. + uint64_t CurPtr = 0; + + // PE header is optional and is present only in executables. If it exists, + // it is placed right after COFF header. + bool hasPEHeader = false; // Check if this is a PE/COFF file. if (base()[0] == 0x4d && base()[1] == 0x5a) { // 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; - HeaderStart = *reinterpret_cast<const ulittle16_t *>(base() + 0x3c); - // Check the PE header. ("PE\0\0") - if (std::memcmp(base() + HeaderStart, "PE\0\0", 4) != 0) { + 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; } - HeaderStart += 4; // Skip the PE Header. + CurPtr += 4; // Skip the PE magic bytes. + hasPEHeader = true; } - Header = reinterpret_cast<const coff_file_header *>(base() + HeaderStart); - if (!checkAddr(Data, ec, uintptr_t(Header), sizeof(coff_file_header))) + if ((ec = getObject(COFFHeader, Data, base() + CurPtr))) return; + CurPtr += sizeof(coff_file_header); - SectionTable = - reinterpret_cast<const coff_section *>( base() - + HeaderStart - + sizeof(coff_file_header) - + Header->SizeOfOptionalHeader); - if (!checkAddr(Data, ec, uintptr_t(SectionTable), - Header->NumberOfSections * sizeof(coff_section))) + if (hasPEHeader) { + if ((ec = getObject(PE32Header, Data, base() + CurPtr))) + return; + if (PE32Header->Magic != 0x10b) { + // We only support PE32. If this is PE32 (not PE32+), the magic byte + // should be 0x10b. If this is not PE32, continue as if there's no PE + // header in this file. + PE32Header = 0; + } else if (PE32Header->NumberOfRvaAndSize > 0) { + const uint8_t *addr = base() + CurPtr + sizeof(pe32_header); + uint64_t size = sizeof(data_directory) * PE32Header->NumberOfRvaAndSize; + if ((ec = getObject(DataDirectory, Data, addr, size))) + return; + } + CurPtr += COFFHeader->SizeOfOptionalHeader; + } + + if ((ec = getObject(SectionTable, Data, base() + CurPtr, + COFFHeader->NumberOfSections * sizeof(coff_section)))) return; - if (Header->PointerToSymbolTable != 0) { - SymbolTable = - reinterpret_cast<const coff_symbol *>(base() - + Header->PointerToSymbolTable); - if (!checkAddr(Data, ec, uintptr_t(SymbolTable), - Header->NumberOfSymbols * sizeof(coff_symbol))) + if (COFFHeader->PointerToSymbolTable != 0) { + if ((ec = getObject(SymbolTable, Data, + base() + COFFHeader->PointerToSymbolTable, + COFFHeader->NumberOfSymbols * sizeof(coff_symbol)))) return; - // Find string table. - StringTable = reinterpret_cast<const char *>(base()) - + Header->PointerToSymbolTable - + Header->NumberOfSymbols * sizeof(coff_symbol); - if (!checkAddr(Data, ec, uintptr_t(StringTable), sizeof(ulittle32_t))) + // 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); + const ulittle32_t *StringTableSizePtr; + if ((ec = getObject(StringTableSizePtr, Data, StringTableAddr))) return; - - StringTableSize = *reinterpret_cast<const ulittle32_t *>(StringTable); - if (!checkAddr(Data, ec, uintptr_t(StringTable), StringTableSize)) + StringTableSize = *StringTableSizePtr; + if ((ec = getObject(StringTable, Data, StringTableAddr, StringTableSize))) return; + // Check that the string table is null terminated if has any in it. if (StringTableSize < 4 || (StringTableSize > 4 && StringTable[StringTableSize - 1] != 0)) { @@ -547,7 +566,7 @@ section_iterator COFFObjectFile::begin_sections() const { section_iterator COFFObjectFile::end_sections() const { DataRefImpl ret; - ret.p = reinterpret_cast<intptr_t>(SectionTable + Header->NumberOfSections); + ret.p = reinterpret_cast<intptr_t>(SectionTable + COFFHeader->NumberOfSections); return section_iterator(SectionRef(ret, this)); } @@ -556,7 +575,7 @@ uint8_t COFFObjectFile::getBytesInAddress() const { } StringRef COFFObjectFile::getFileFormatName() const { - switch(Header->Machine) { + switch(COFFHeader->Machine) { case COFF::IMAGE_FILE_MACHINE_I386: return "COFF-i386"; case COFF::IMAGE_FILE_MACHINE_AMD64: @@ -567,7 +586,7 @@ StringRef COFFObjectFile::getFileFormatName() const { } unsigned COFFObjectFile::getArch() const { - switch(Header->Machine) { + switch(COFFHeader->Machine) { case COFF::IMAGE_FILE_MACHINE_I386: return Triple::x86; case COFF::IMAGE_FILE_MACHINE_AMD64: @@ -577,8 +596,28 @@ 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. error_code COFFObjectFile::getHeader(const coff_file_header *&Res) const { - Res = Header; + return getCOFFHeader(Res); +} + +error_code COFFObjectFile::getCOFFHeader(const coff_file_header *&Res) const { + Res = COFFHeader; + return object_error::success; +} + +error_code COFFObjectFile::getPE32Header(const pe32_header *&Res) const { + Res = PE32Header; + return object_error::success; +} + +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 || index > PE32Header->NumberOfRvaAndSize) + return object_error::parse_failed; + Res = &DataDirectory[index]; return object_error::success; } @@ -589,7 +628,7 @@ error_code COFFObjectFile::getSection(int32_t index, index == COFF::IMAGE_SYM_ABSOLUTE || index == COFF::IMAGE_SYM_DEBUG) Result = NULL; - else if (index > 0 && index <= Header->NumberOfSections) + else if (index > 0 && index <= COFFHeader->NumberOfSections) // We already verified the section table data, so no need to check again. Result = SectionTable + (index - 1); else @@ -610,7 +649,7 @@ error_code COFFObjectFile::getString(uint32_t offset, error_code COFFObjectFile::getSymbol(uint32_t index, const coff_symbol *&Result) const { - if (index < Header->NumberOfSymbols) + if (index < COFFHeader->NumberOfSymbols) Result = SymbolTable + index; else return object_error::parse_failed; @@ -646,12 +685,12 @@ ArrayRef<uint8_t> COFFObjectFile::getSymbolAuxData( # 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 < Header->PointerToSymbolTable - || offset >= Header->PointerToSymbolTable - + (Header->NumberOfSymbols * sizeof(coff_symbol))) + if (offset < COFFHeader->PointerToSymbolTable + || offset >= COFFHeader->PointerToSymbolTable + + (COFFHeader->NumberOfSymbols * sizeof(coff_symbol))) report_fatal_error("Aux Symbol data was outside of symbol table."); - assert((offset - Header->PointerToSymbolTable) % sizeof(coff_symbol) + assert((offset - COFFHeader->PointerToSymbolTable) % sizeof(coff_symbol) == 0 && "Aux Symbol data did not point to the beginning of a symbol"); # endif } @@ -748,7 +787,7 @@ error_code COFFObjectFile::getRelocationTypeName(DataRefImpl Rel, SmallVectorImpl<char> &Result) const { const coff_relocation *reloc = toRel(Rel); StringRef res; - switch (Header->Machine) { + switch (COFFHeader->Machine) { case COFF::IMAGE_FILE_MACHINE_AMD64: switch (reloc->Type) { LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ABSOLUTE); diff --git a/lib/Object/ELFYAML.cpp b/lib/Object/ELFYAML.cpp index 967fd2b..e530d3d 100644 --- a/lib/Object/ELFYAML.cpp +++ b/lib/Object/ELFYAML.cpp @@ -176,7 +176,6 @@ ScalarEnumerationTraits<ELFYAML::ELF_EM>::enumeration(IO &IO, ECase(EM_STM8) ECase(EM_TILE64) ECase(EM_TILEPRO) - ECase(EM_MICROBLAZE) ECase(EM_CUDA) ECase(EM_TILEGX) ECase(EM_CLOUDSHIELD) @@ -188,7 +187,6 @@ ScalarEnumerationTraits<ELFYAML::ELF_EM>::enumeration(IO &IO, ECase(EM_VIDEOCORE5) ECase(EM_78KOR) ECase(EM_56800EX) - ECase(EM_MBLAZE) #undef ECase } @@ -212,17 +210,127 @@ void ScalarEnumerationTraits<ELFYAML::ELF_ELFDATA>::enumeration( #undef ECase } +void ScalarEnumerationTraits<ELFYAML::ELF_ELFOSABI>::enumeration( + IO &IO, ELFYAML::ELF_ELFOSABI &Value) { +#define ECase(X) IO.enumCase(Value, #X, ELF::X); + ECase(ELFOSABI_NONE) + ECase(ELFOSABI_HPUX) + ECase(ELFOSABI_NETBSD) + ECase(ELFOSABI_GNU) + ECase(ELFOSABI_GNU) + ECase(ELFOSABI_HURD) + ECase(ELFOSABI_SOLARIS) + ECase(ELFOSABI_AIX) + ECase(ELFOSABI_IRIX) + ECase(ELFOSABI_FREEBSD) + ECase(ELFOSABI_TRU64) + ECase(ELFOSABI_MODESTO) + ECase(ELFOSABI_OPENBSD) + ECase(ELFOSABI_OPENVMS) + ECase(ELFOSABI_NSK) + ECase(ELFOSABI_AROS) + ECase(ELFOSABI_FENIXOS) + ECase(ELFOSABI_C6000_ELFABI) + ECase(ELFOSABI_C6000_LINUX) + ECase(ELFOSABI_ARM) + ECase(ELFOSABI_STANDALONE) +#undef ECase +} + +void ScalarEnumerationTraits<ELFYAML::ELF_SHT>::enumeration( + IO &IO, ELFYAML::ELF_SHT &Value) { +#define ECase(X) IO.enumCase(Value, #X, ELF::X); + ECase(SHT_NULL) + ECase(SHT_PROGBITS) + // No SHT_SYMTAB. Use the top-level `Symbols` key instead. + // FIXME: Issue a diagnostic with this information. + ECase(SHT_STRTAB) + ECase(SHT_RELA) + ECase(SHT_HASH) + ECase(SHT_DYNAMIC) + ECase(SHT_NOTE) + ECase(SHT_NOBITS) + ECase(SHT_REL) + ECase(SHT_SHLIB) + ECase(SHT_DYNSYM) + ECase(SHT_INIT_ARRAY) + ECase(SHT_FINI_ARRAY) + ECase(SHT_PREINIT_ARRAY) + ECase(SHT_GROUP) + ECase(SHT_SYMTAB_SHNDX) +#undef ECase +} + +void ScalarBitSetTraits<ELFYAML::ELF_SHF>::bitset(IO &IO, + ELFYAML::ELF_SHF &Value) { +#define BCase(X) IO.bitSetCase(Value, #X, ELF::X); + BCase(SHF_WRITE) + BCase(SHF_ALLOC) + BCase(SHF_EXECINSTR) + BCase(SHF_MERGE) + BCase(SHF_STRINGS) + BCase(SHF_INFO_LINK) + BCase(SHF_LINK_ORDER) + BCase(SHF_OS_NONCONFORMING) + BCase(SHF_GROUP) + BCase(SHF_TLS) +#undef BCase +} + +void ScalarEnumerationTraits<ELFYAML::ELF_STT>::enumeration( + IO &IO, ELFYAML::ELF_STT &Value) { +#define ECase(X) IO.enumCase(Value, #X, ELF::X); + ECase(STT_NOTYPE) + ECase(STT_OBJECT) + ECase(STT_FUNC) + ECase(STT_SECTION) + ECase(STT_FILE) + ECase(STT_COMMON) + ECase(STT_TLS) + ECase(STT_GNU_IFUNC) +#undef ECase +} + void MappingTraits<ELFYAML::FileHeader>::mapping(IO &IO, ELFYAML::FileHeader &FileHdr) { IO.mapRequired("Class", FileHdr.Class); IO.mapRequired("Data", FileHdr.Data); + IO.mapOptional("OSABI", FileHdr.OSABI, ELFYAML::ELF_ELFOSABI(0)); IO.mapRequired("Type", FileHdr.Type); IO.mapRequired("Machine", FileHdr.Machine); IO.mapOptional("Entry", FileHdr.Entry, Hex64(0)); } +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)); +} + +void MappingTraits<ELFYAML::LocalGlobalWeakSymbols>::mapping( + IO &IO, ELFYAML::LocalGlobalWeakSymbols &Symbols) { + IO.mapOptional("Local", Symbols.Local); + IO.mapOptional("Global", Symbols.Global); + IO.mapOptional("Weak", Symbols.Weak); +} + +void MappingTraits<ELFYAML::Section>::mapping(IO &IO, + ELFYAML::Section &Section) { + IO.mapOptional("Name", Section.Name, StringRef()); + IO.mapRequired("Type", Section.Type); + IO.mapOptional("Flags", Section.Flags, ELFYAML::ELF_SHF(0)); + IO.mapOptional("Address", Section.Address, Hex64(0)); + IO.mapOptional("Content", Section.Content); + IO.mapOptional("Link", Section.Link); + IO.mapOptional("AddressAlign", Section.AddressAlign, Hex64(0)); +} + void MappingTraits<ELFYAML::Object>::mapping(IO &IO, ELFYAML::Object &Object) { IO.mapRequired("FileHeader", Object.Header); + IO.mapOptional("Sections", Object.Sections); + IO.mapOptional("Symbols", Object.Symbols); } } // end namespace yaml diff --git a/lib/Object/Error.cpp b/lib/Object/Error.cpp index 2594625..47ce38c 100644 --- a/lib/Object/Error.cpp +++ b/lib/Object/Error.cpp @@ -31,18 +31,20 @@ const char *_object_error_category::name() const { } std::string _object_error_category::message(int ev) const { - switch (ev) { + object_error::Impl E = static_cast<object_error::Impl>(ev); + switch (E) { case object_error::success: return "Success"; + case object_error::arch_not_found: + return "No object file for requested architecture"; case object_error::invalid_file_type: return "The file was not recognized as a valid object file"; case object_error::parse_failed: return "Invalid data was encountered while parsing the file"; case object_error::unexpected_eof: return "The end of the file was unexpectedly encountered"; - default: - llvm_unreachable("An enumerator of object_error does not have a message " - "defined."); } + llvm_unreachable("An enumerator of object_error does not have a message " + "defined."); } error_condition _object_error_category::default_error_condition(int ev) const { diff --git a/lib/Object/MachOObjectFile.cpp b/lib/Object/MachOObjectFile.cpp index e62b5a4..5d0399e 100644 --- a/lib/Object/MachOObjectFile.cpp +++ b/lib/Object/MachOObjectFile.cpp @@ -1181,7 +1181,7 @@ MachOObjectFile::getRelocationHidden(DataRefImpl Rel, bool &Result) const { if (Type == macho::RIT_Pair) Result = true; } else if (Arch == Triple::x86_64) { // On x86_64, X86_64_RELOC_UNSIGNED is hidden only when it follows - // an X864_64_RELOC_SUBTRACTOR. + // an X86_64_RELOC_SUBTRACTOR. if (Type == macho::RIT_X86_64_Unsigned && Rel.d.a > 0) { DataRefImpl RelPrev = Rel; RelPrev.d.a--; @@ -1284,8 +1284,8 @@ StringRef MachOObjectFile::getFileFormatName() const { // Make sure the cpu type has the correct mask. assert((CPUType & llvm::MachO::CPUArchABI64) - == llvm::MachO::CPUArchABI64 && - "32-bit object file when we're 64-bit?"); + == llvm::MachO::CPUArchABI64 && + "32-bit object file when we're 64-bit?"); switch (CPUType) { case llvm::MachO::CPUTypeX86_64: @@ -1297,8 +1297,8 @@ StringRef MachOObjectFile::getFileFormatName() const { } } -unsigned MachOObjectFile::getArch() const { - switch (getCPUType(this)) { +Triple::ArchType MachOObjectFile::getArch(uint32_t CPUType) { + switch (CPUType) { case llvm::MachO::CPUTypeI386: return Triple::x86; case llvm::MachO::CPUTypeX86_64: @@ -1314,6 +1314,10 @@ unsigned MachOObjectFile::getArch() const { } } +unsigned MachOObjectFile::getArch() const { + return getArch(getCPUType(this)); +} + StringRef MachOObjectFile::getLoadName() const { // TODO: Implement report_fatal_error("get_load_name() unimplemented in MachOObjectFile"); @@ -1380,30 +1384,32 @@ MachOObjectFile::isRelocationScattered(const macho::RelocationEntry &RE) return getPlainRelocationAddress(RE) & macho::RF_Scattered; } -unsigned MachOObjectFile::getPlainRelocationSymbolNum(const macho::RelocationEntry &RE) const { +unsigned MachOObjectFile::getPlainRelocationSymbolNum( + const macho::RelocationEntry &RE) const { if (isLittleEndian()) return RE.Word1 & 0xffffff; return RE.Word1 >> 8; } -bool MachOObjectFile::getPlainRelocationExternal(const macho::RelocationEntry &RE) const { +bool MachOObjectFile::getPlainRelocationExternal( + const macho::RelocationEntry &RE) const { if (isLittleEndian()) return (RE.Word1 >> 27) & 1; return (RE.Word1 >> 4) & 1; } -bool -MachOObjectFile::getScatteredRelocationScattered(const macho::RelocationEntry &RE) const { +bool MachOObjectFile::getScatteredRelocationScattered( + const macho::RelocationEntry &RE) const { return RE.Word0 >> 31; } -uint32_t -MachOObjectFile::getScatteredRelocationValue(const macho::RelocationEntry &RE) const { +uint32_t MachOObjectFile::getScatteredRelocationValue( + const macho::RelocationEntry &RE) const { return RE.Word1; } -unsigned -MachOObjectFile::getAnyRelocationAddress(const macho::RelocationEntry &RE) const { +unsigned MachOObjectFile::getAnyRelocationAddress( + const macho::RelocationEntry &RE) const { if (isRelocationScattered(RE)) return getScatteredRelocationAddress(RE); return getPlainRelocationAddress(RE); @@ -1416,8 +1422,8 @@ MachOObjectFile::getAnyRelocationPCRel(const macho::RelocationEntry &RE) const { return getPlainRelocationPCRel(this, RE); } -unsigned -MachOObjectFile::getAnyRelocationLength(const macho::RelocationEntry &RE) const { +unsigned MachOObjectFile::getAnyRelocationLength( + const macho::RelocationEntry &RE) const { if (isRelocationScattered(RE)) return getScatteredRelocationLength(RE); return getPlainRelocationLength(this, RE); @@ -1490,8 +1496,8 @@ MachOObjectFile::getSymbol64TableEntry(DataRefImpl DRI) const { return getStruct<macho::Symbol64TableEntry>(this, P); } -macho::LinkeditDataLoadCommand -MachOObjectFile::getLinkeditDataLoadCommand(const MachOObjectFile::LoadCommandInfo &L) const { +macho::LinkeditDataLoadCommand MachOObjectFile::getLinkeditDataLoadCommand( + const MachOObjectFile::LoadCommandInfo &L) const { return getStruct<macho::LinkeditDataLoadCommand>(this, L.Ptr); } @@ -1593,21 +1599,23 @@ void MachOObjectFile::ReadULEB128s(uint64_t Index, ObjectFile *ObjectFile::createMachOObjectFile(MemoryBuffer *Buffer) { StringRef Magic = Buffer->getBuffer().slice(0, 4); error_code ec; - ObjectFile *Ret; + OwningPtr<ObjectFile> Ret; if (Magic == "\xFE\xED\xFA\xCE") - Ret = new MachOObjectFile(Buffer, false, false, ec); + Ret.reset(new MachOObjectFile(Buffer, false, false, ec)); else if (Magic == "\xCE\xFA\xED\xFE") - Ret = new MachOObjectFile(Buffer, true, false, ec); + Ret.reset(new MachOObjectFile(Buffer, true, false, ec)); else if (Magic == "\xFE\xED\xFA\xCF") - Ret = new MachOObjectFile(Buffer, false, true, ec); + Ret.reset(new MachOObjectFile(Buffer, false, true, ec)); else if (Magic == "\xCF\xFA\xED\xFE") - Ret = new MachOObjectFile(Buffer, true, true, ec); - else + Ret.reset(new MachOObjectFile(Buffer, true, true, ec)); + else { + delete Buffer; return NULL; + } if (ec) return NULL; - return Ret; + return Ret.take(); } } // end namespace object diff --git a/lib/Object/MachOUniversal.cpp b/lib/Object/MachOUniversal.cpp new file mode 100644 index 0000000..b76f10e --- /dev/null +++ b/lib/Object/MachOUniversal.cpp @@ -0,0 +1,139 @@ +//===- MachOUniversal.cpp - Mach-O universal binary -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the MachOUniversalBinary class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/MachOUniversal.h" + +#include "llvm/Object/MachO.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/MemoryBuffer.h" + +using namespace llvm; +using namespace object; + +template<typename T> +static void SwapValue(T &Value) { + Value = sys::SwapByteOrder(Value); +} + +template<typename T> +static void SwapStruct(T &Value); + +template<> +void SwapStruct(macho::FatHeader &H) { + SwapValue(H.Magic); + SwapValue(H.NumFatArch); +} + +template<> +void SwapStruct(macho::FatArchHeader &H) { + SwapValue(H.CPUType); + SwapValue(H.CPUSubtype); + SwapValue(H.Offset); + SwapValue(H.Size); + SwapValue(H.Align); +} + +template<typename T> +static T getUniversalBinaryStruct(const char *Ptr) { + T Res; + memcpy(&Res, Ptr, sizeof(T)); + // Universal binary headers have big-endian byte order. + if (sys::IsLittleEndianHost) + SwapStruct(Res); + return Res; +} + +MachOUniversalBinary::ObjectForArch::ObjectForArch( + const MachOUniversalBinary *Parent, uint32_t Index) + : Parent(Parent), Index(Index) { + if (Parent == 0 || Index > Parent->getNumberOfObjects()) { + clear(); + } else { + // Parse object header. + StringRef ParentData = Parent->getData(); + const char *HeaderPos = ParentData.begin() + macho::FatHeaderSize + + Index * macho::FatArchHeaderSize; + Header = getUniversalBinaryStruct<macho::FatArchHeader>(HeaderPos); + if (ParentData.size() < Header.Offset + Header.Size) { + clear(); + } + } +} + +error_code MachOUniversalBinary::ObjectForArch::getAsObjectFile( + OwningPtr<ObjectFile> &Result) const { + if (Parent) { + StringRef ParentData = Parent->getData(); + StringRef ObjectData = ParentData.substr(Header.Offset, Header.Size); + std::string ObjectName = + Parent->getFileName().str() + ":" + + Triple::getArchTypeName(MachOObjectFile::getArch(Header.CPUType)); + MemoryBuffer *ObjBuffer = MemoryBuffer::getMemBuffer( + ObjectData, ObjectName, false); + if (ObjectFile *Obj = ObjectFile::createMachOObjectFile(ObjBuffer)) { + Result.reset(Obj); + return object_error::success; + } + } + return object_error::parse_failed; +} + +void MachOUniversalBinary::anchor() { } + +MachOUniversalBinary::MachOUniversalBinary(MemoryBuffer *Source, + error_code &ec) + : Binary(Binary::ID_MachOUniversalBinary, Source), + NumberOfObjects(0) { + if (Source->getBufferSize() < macho::FatHeaderSize) { + ec = object_error::invalid_file_type; + return; + } + // Check for magic value and sufficient header size. + StringRef Buf = getData(); + macho::FatHeader H = getUniversalBinaryStruct<macho::FatHeader>(Buf.begin()); + NumberOfObjects = H.NumFatArch; + uint32_t MinSize = macho::FatHeaderSize + + macho::FatArchHeaderSize * NumberOfObjects; + if (H.Magic != macho::HM_Universal || Buf.size() < MinSize) { + ec = object_error::parse_failed; + return; + } + ec = object_error::success; +} + +static bool getCTMForArch(Triple::ArchType Arch, mach::CPUTypeMachine &CTM) { + switch (Arch) { + case Triple::x86: CTM = mach::CTM_i386; return true; + case Triple::x86_64: CTM = mach::CTM_x86_64; return true; + case Triple::arm: CTM = mach::CTM_ARM; return true; + case Triple::sparc: CTM = mach::CTM_SPARC; return true; + case Triple::ppc: CTM = mach::CTM_PowerPC; return true; + case Triple::ppc64: CTM = mach::CTM_PowerPC64; return true; + default: return false; + } +} + +error_code +MachOUniversalBinary::getObjectForArch(Triple::ArchType Arch, + OwningPtr<ObjectFile> &Result) const { + mach::CPUTypeMachine CTM; + if (!getCTMForArch(Arch, CTM)) + return object_error::arch_not_found; + for (object_iterator I = begin_objects(), E = end_objects(); I != E; ++I) { + if (I->getCPUType() == static_cast<uint32_t>(CTM)) + return I->getAsObjectFile(Result); + } + return object_error::arch_not_found; +} diff --git a/lib/Object/ObjectFile.cpp b/lib/Object/ObjectFile.cpp index 3ec29bf..1d1dafd 100644 --- a/lib/Object/ObjectFile.cpp +++ b/lib/Object/ObjectFile.cpp @@ -38,14 +38,18 @@ section_iterator ObjectFile::getRelocatedSection(DataRefImpl Sec) const { } ObjectFile *ObjectFile::createObjectFile(MemoryBuffer *Object) { - if (!Object || Object->getBufferSize() < 64) + if (Object->getBufferSize() < 64) { + delete Object; return 0; + } sys::fs::file_magic Type = sys::fs::identify_magic(Object->getBuffer()); switch (Type) { case sys::fs::file_magic::unknown: case sys::fs::file_magic::bitcode: case sys::fs::file_magic::archive: + case sys::fs::file_magic::macho_universal_binary: + delete Object; return 0; case sys::fs::file_magic::elf_relocatable: case sys::fs::file_magic::elf_executable: diff --git a/lib/Object/YAML.cpp b/lib/Object/YAML.cpp index 4e7f089..21bacb8 100644 --- a/lib/Object/YAML.cpp +++ b/lib/Object/YAML.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Object/YAML.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -49,6 +50,10 @@ void BinaryRef::writeAsBinary(raw_ostream &OS) const { } void BinaryRef::writeAsHex(raw_ostream &OS) const { + if (binary_size() == 0) { + OS << "\"\""; + return; + } if (DataIsHexString) { OS.write((const char *)Data.data(), Data.size()); return; |