X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FObject%2FArchive.cpp;h=60c6d21f48237484e2b1493f1d04909844c2ec45;hb=55804a089e7ac26d5a07a9ac38e5dcedad3f2754;hp=95eba625edfdaf2a0666a5eca37e31db642c55f4;hpb=e92800dd533988c46e58b0f4226df76a3bb1cb0c;p=oota-llvm.git diff --git a/lib/Object/Archive.cpp b/lib/Object/Archive.cpp index 95eba625edf..60c6d21f482 100644 --- a/lib/Object/Archive.cpp +++ b/lib/Object/Archive.cpp @@ -13,8 +13,9 @@ #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/ErrorHandling.h" #include "llvm/Support/MemoryBuffer.h" using namespace llvm; @@ -22,49 +23,10 @@ using namespace object; static const char *Magic = "!\n"; -namespace { -struct ArchiveMemberHeader { - char Name[16]; - char LastModified[12]; - char UID[6]; - char GID[6]; - char AccessMode[8]; - char Size[10]; ///< Size of data, not including header or padding. - char Terminator[2]; - - ///! Get the name without looking up long names. - StringRef getName() const { - char EndCond; - if (Name[0] == '/' || Name[0] == '#') - EndCond = ' '; - else - EndCond = '/'; - StringRef::size_type end = StringRef(Name, sizeof(Name)).find(EndCond); - if (end == StringRef::npos) - end = sizeof(Name); - assert(end <= sizeof(Name) && end > 0); - // Don't include the EndCond if there is one. - return StringRef(Name, end); - } - - uint64_t getSize() const { - uint64_t ret; - StringRef(Size, sizeof(Size)).getAsInteger(10, ret); - return ret; - } -}; -} - -static const ArchiveMemberHeader *ToHeader(const char *base) { - return reinterpret_cast(base); -} - - static bool isInternalMember(const ArchiveMemberHeader &amh) { static const char *const internals[] = { "/", - "//", - "#_LLVM_SYM_TAB_#" + "//" }; StringRef name = amh.getName(); @@ -77,9 +39,86 @@ static bool isInternalMember(const ArchiveMemberHeader &amh) { 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(Ret); +} + +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; +} + +static const ArchiveMemberHeader *toHeader(const char *base) { + return reinterpret_cast(base); +} + +Archive::Child::Child(const Archive *Parent, const char *Start) + : Parent(Parent) { + if (!Start) + return; + + const ArchiveMemberHeader *Header = toHeader(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; + } +} + Archive::Child Archive::Child::getNext() const { - size_t SpaceToSkip = sizeof(ArchiveMemberHeader) + - ToHeader(Data.data())->getSize(); + size_t SpaceToSkip = Data.size(); // If it's odd, add 1 to make it even. if (SpaceToSkip & 1) ++SpaceToSkip; @@ -88,16 +127,13 @@ Archive::Child Archive::Child::getNext() const { // Check to see if this is past the end of the archive. if (NextLoc >= Parent->Data->getBufferEnd()) - return Child(Parent, StringRef(0, 0)); + return Child(Parent, NULL); - size_t NextSize = sizeof(ArchiveMemberHeader) + - ToHeader(NextLoc)->getSize(); - - return Child(Parent, StringRef(NextLoc, NextSize)); + 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. @@ -110,8 +146,9 @@ error_code Archive::Child::getName(StringRef &Result) const { } // It's a long name. // Get the offset. - uint64_t offset; - name.substr(1).getAsInteger(10, offset); + std::size_t offset; + if (name.substr(1).rtrim(" ").getAsInteger(10, offset)) + llvm_unreachable("Long name offset is not an integer"); const char *addr = Parent->StringTable->Data.begin() + sizeof(ArchiveMemberHeader) + offset; @@ -134,8 +171,9 @@ error_code Archive::Child::getName(StringRef &Result) const { return object_error::success; } else if (name.startswith("#1/")) { uint64_t name_size; - name.substr(3).getAsInteger(10, name_size); - Result = Data.substr(0, 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); return object_error::success; } // It's a simple name. @@ -146,46 +184,36 @@ error_code Archive::Child::getName(StringRef &Result) const { return object_error::success; } -uint64_t Archive::Child::getSize() const { - uint64_t size = ToHeader(Data.data())->getSize(); - // Don't include attached name. - StringRef name = ToHeader(Data.data())->getName(); - if (name.startswith("#1/")) { - uint64_t name_size; - name.substr(3).getAsInteger(10, name_size); - size -= name_size; - } - return size; -} - -MemoryBuffer *Archive::Child::getBuffer() const { - StringRef name; - if (getName(name)) return NULL; - int size = sizeof(ArchiveMemberHeader); - if (name.startswith("#1/")) { - uint64_t name_size; - name.substr(3).getAsInteger(10, name_size); - size += name_size; - } - return MemoryBuffer::getMemBuffer(Data.substr(size, getSize()), - name, - false); +error_code Archive::Child::getMemoryBuffer(OwningPtr &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 &Result) const { OwningPtr ret; - if (error_code ec = - createBinary(getBuffer(), ret)) + OwningPtr Buff; + if (error_code ec = getMemoryBuffer(Buff)) + return ec; + if (error_code ec = createBinary(Buff.take(), ret)) return ec; Result.swap(ret); return object_error::success; } 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. + < (8 + sizeof(ArchiveMemberHeader)) // Smallest archive. || StringRef(source->getBufferStart(), 8) != Magic) { ec = object_error::invalid_file_type; return; @@ -195,78 +223,116 @@ 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::parse_failed; 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/, 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/, The size represents the size // of the filename that needs to be read after the archive header // COFF archive format // First member : / // Second member : / (provides a directory of symbols) - // Third member : // contains the string table, this is present even if the - // string table is empty - if (name == "/") { + // Third member : // (may exist, if it exists, contains the string table) + // Note: Microsoft PE/COFF Spec 8.3 says that the third member is present + // 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 == "__.SYMDEF") { + Format = K_BSD; SymbolTable = i; - StringTable = e; - if (i != e) ++i; - if ((ec = i->getName(name))) - return; - if (name[0] != '/') { - Format = K_GNU; - } else if ((name.size() > 1) && (name == "//")) { - Format = K_GNU; - StringTable = i; - ++i; - } else { - Format = K_COFF; - if (i != e) { - SymbolTable = i; - ++i; - } - if (i != e) { - StringTable = i; - } - } - } else if (name == "__.SYMDEF") { + 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 == StringRef("__.SYMDEF SORTED\0\0\0", 20)) + SymbolTable = 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; + ec = object_error::success; + return; + } + + if (Name[0] != '/') { + Format = K_GNU; + ec = object_error::success; + return; + } + + if (Name != "/") { + ec = object_error::parse_failed; + return; + } + + Format = K_COFF; + SymbolTable = i; + + ++i; + if (i == e) { + ec = object_error::success; + return; + } + + Name = i->getRawName(); + + if (Name == "//") + StringTable = i; + ec = object_error::success; } Archive::child_iterator Archive::begin_children(bool skip_internal) const { const char *Loc = Data->getBufferStart() + strlen(Magic); - size_t Size = sizeof(ArchiveMemberHeader) + - ToHeader(Loc)->getSize(); - Child c(this, StringRef(Loc, Size)); + Child c(this, Loc); // Skip internals at the beginning of an archive. - if (skip_internal && isInternalMember(*ToHeader(Loc))) + if (skip_internal && isInternalMember(*toHeader(Loc))) return c.getNext(); 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 { - Result = - StringRef(Parent->SymbolTable->getBuffer()->getBufferStart() + StringIndex); + Result = StringRef(Parent->SymbolTable->getBuffer().begin() + StringIndex); return object_error::success; } error_code Archive::Symbol::getMember(child_iterator &Result) const { - const char *Buf = Parent->SymbolTable->getBuffer()->getBufferStart(); + const char *Buf = Parent->SymbolTable->getBuffer().begin(); const char *Offsets = Buf + 4; uint32_t Offset = 0; if (Parent->kind() == K_GNU) { @@ -305,9 +371,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; } @@ -316,13 +380,16 @@ Archive::Symbol Archive::Symbol::getNext() const { Symbol t(*this); // Go to one past next null. t.StringIndex = - Parent->SymbolTable->getBuffer()->getBuffer().find('\0', t.StringIndex) + 1; + Parent->SymbolTable->getBuffer().find('\0', t.StringIndex) + 1; ++t.SymbolIndex; return t; } Archive::symbol_iterator Archive::begin_symbols() const { - const char *buf = SymbolTable->getBuffer()->getBufferStart(); + if (SymbolTable == end_children()) + return symbol_iterator(Symbol(this, 0, 0)); + + const char *buf = SymbolTable->getBuffer().begin(); if (kind() == K_GNU) { uint32_t symbol_count = 0; symbol_count = *reinterpret_cast(buf); @@ -337,17 +404,18 @@ Archive::symbol_iterator Archive::begin_symbols() const { symbol_count = *reinterpret_cast(buf); buf += 4 + (symbol_count * 2); // Skip indices. } - uint32_t string_start_offset = - buf - SymbolTable->getBuffer()->getBufferStart(); + uint32_t string_start_offset = buf - SymbolTable->getBuffer().begin(); return symbol_iterator(Symbol(this, 0, string_start_offset)); } Archive::symbol_iterator Archive::end_symbols() const { - const char *buf = SymbolTable->getBuffer()->getBufferStart(); + if (SymbolTable == end_children()) + 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(buf); - buf += sizeof(uint32_t) + (symbol_count * (sizeof(uint32_t))); } else if (kind() == K_BSD) { llvm_unreachable("BSD archive format is not supported"); } else {