X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FObject%2FArchive.cpp;h=45156f1311e9fbe987afd73d81c4e2854b659162;hb=6b863256e442f8d1df4dcbd1325ad132380de828;hp=ad1cde0d258b699f53202e4c3fd7ce0be8b3caba;hpb=2d24e2a396a1d211baaeedf32148a3b657240170;p=oota-llvm.git diff --git a/lib/Object/Archive.cpp b/lib/Object/Archive.cpp index ad1cde0d258..45156f1311e 100644 --- a/lib/Object/Archive.cpp +++ b/lib/Object/Archive.cpp @@ -13,72 +13,95 @@ #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 StringRef 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); - } +static const char *const Magic = "!\n"; - uint64_t getSize() const { - APInt ret; - StringRef(Size, sizeof(Size)).getAsInteger(10, ret); - return ret.getZExtValue(); - } -}; +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); } -static const ArchiveMemberHeader *ToHeader(const char *base) { - return reinterpret_cast(base); +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); +} -static bool isInternalMember(const ArchiveMemberHeader &amh) { - const char *internals[] = { - "/", - "//", - "#_LLVM_SYM_TAB_#" - }; +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."); - StringRef name = amh.getName(); - for (std::size_t i = 0; i < sizeof(internals) / sizeof(*internals); ++i) { - if (name == internals[i]) - return true; - } - return false; + sys::TimeValue Ret; + Ret.fromEpochTime(Seconds); + return Ret; } -void Archive::anchor() { } +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(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; @@ -87,186 +110,396 @@ 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)); - - size_t NextSize = sizeof(ArchiveMemberHeader) + - ToHeader(NextLoc)->getSize(); + return Child(Parent, nullptr); - return Child(Parent, StringRef(NextLoc, NextSize)); + return Child(Parent, NextLoc); } -error_code Archive::Child::getName(StringRef &Result) const { - StringRef name = ToHeader(Data.data())->getName(); +ErrorOr Archive::Child::getName() const { + StringRef name = getRawName(); // Check if it's a special name. if (name[0] == '/') { - if (name.size() == 1) { // Linker member. - Result = name; - return object_error::success; - } - if (name.size() == 2 && name[1] == '/') { // String table. - Result = name; - return object_error::success; - } + if (name.size() == 1) // Linker member. + return name; + if (name.size() == 2 && name[1] == '/') // String table. + return name; // It's a long name. // Get the offset. - APInt 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.getZExtValue(); + + offset; // Verify it. - if (Parent->StringTable == Parent->end_children() + if (Parent->StringTable == Parent->child_end() || addr < (Parent->StringTable->Data.begin() + sizeof(ArchiveMemberHeader)) || addr > (Parent->StringTable->Data.begin() + sizeof(ArchiveMemberHeader) + Parent->StringTable->getSize())) return object_error::parse_failed; - Result = addr; - return object_error::success; + + // GNU long file names end with a /. + if (Parent->kind() == K_GNU) { + StringRef::size_type End = StringRef(addr).find('/'); + return StringRef(addr, End); + } + return StringRef(addr); } else if (name.startswith("#1/")) { - APInt name_size; - name.substr(3).getAsInteger(10, name_size); - Result = Data.substr(0, name_size.getZExtValue()); - return object_error::success; + uint64_t name_size; + if (name.substr(3).rtrim(" ").getAsInteger(10, name_size)) + llvm_unreachable("Long name length is not an ingeter"); + return Data.substr(sizeof(ArchiveMemberHeader), name_size) + .rtrim(StringRef("\0", 1)); } // It's a simple name. if (name[name.size() - 1] == '/') - Result = name.substr(0, name.size() - 1); - else - Result = name; - return object_error::success; + return name.substr(0, name.size() - 1); + return name; } -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/")) { - APInt name_size; - name.substr(3).getAsInteger(10, name_size); - size -= name_size.getZExtValue(); - } - return size; +ErrorOr> +Archive::Child::getMemoryBuffer(bool FullPath) const { + ErrorOr NameOrErr = getName(); + if (std::error_code EC = NameOrErr.getError()) + return EC; + StringRef Name = NameOrErr.get(); + SmallString<128> Path; + std::unique_ptr Ret(MemoryBuffer::getMemBuffer( + getBuffer(), + FullPath + ? (Twine(Parent->getFileName()) + "(" + Name + ")").toStringRef(Path) + : Name, + false)); + return std::move(Ret); } -MemoryBuffer *Archive::Child::getBuffer() const { - StringRef name; - if (getName(name)) return NULL; - int size = sizeof(ArchiveMemberHeader); - if (name.startswith("#1/")) { - APInt name_size; - name.substr(3).getAsInteger(10, name_size); - size += name_size.getZExtValue(); - } - return MemoryBuffer::getMemBuffer(Data.substr(size, getSize()), - name, - false); +ErrorOr> +Archive::Child::getAsBinary(LLVMContext *Context) const { + ErrorOr> BuffOrErr = getMemoryBuffer(); + if (std::error_code EC = BuffOrErr.getError()) + return EC; + + return createBinary(std::move(*BuffOrErr), Context); } -error_code Archive::Child::getAsBinary(OwningPtr &Result) const { - OwningPtr ret; - if (error_code ec = - createBinary(getBuffer(), ret)) - return ec; - Result.swap(ret); - return object_error::success; +ErrorOr> +Archive::create(std::unique_ptr Source) { + std::error_code EC; + std::unique_ptr Ret(new Archive(std::move(Source), EC)); + if (EC) + return EC; + return std::move(Ret); } -Archive::Archive(MemoryBuffer *source, error_code &ec) - : Binary(Binary::isArchive, source) { +Archive::Archive(std::unique_ptr Source, std::error_code &ec) + : Binary(Binary::ID_Archive, std::move(Source)), SymbolTable(child_end()) { // Check for sufficient magic. - if (!source || source->getBufferSize() - < (8 + sizeof(ArchiveMemberHeader) + 2) // Smallest archive. - || StringRef(source->getBufferStart(), 8) != Magic) { + if (Data->getBufferSize() < 8 || + StringRef(Data->getBufferStart(), 8) != Magic) { ec = object_error::invalid_file_type; return; } // Get the special members. - child_iterator i = begin_children(false); - child_iterator e = end_children(); + child_iterator i = child_begin(false); + child_iterator e = child_end(); + + 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 : / (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 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 : // (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; + ++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. + ErrorOr NameOrErr = i->getName(); + ec = NameOrErr.getError(); + if (ec) + return; + Name = NameOrErr.get(); + if (Name == "__.SYMDEF SORTED") { + SymbolTable = i; + ++i; + } + FirstRegular = i; + return; + } - if (i != e) ++i; // Nobody cares about the first member. - if (i != e) { + if (Name == "/") { SymbolTable = i; + + ++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; } - if (i != e) { + + Name = i->getRawName(); + + if (Name == "//") { StringTable = i; + ++i; } + FirstRegular = i; ec = object_error::success; } -Archive::child_iterator Archive::begin_children(bool skip_internal) const { - const char *Loc = Data->getBufferStart() + Magic.size(); - 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(); +Archive::child_iterator Archive::child_begin(bool SkipInternal) const { + if (Data->getBufferSize() == 8) // empty archive. + return child_end(); + + if (SkipInternal) + return FirstRegular; + + const char *Loc = Data->getBufferStart() + strlen(Magic); + Child c(this, Loc); return c; } -Archive::child_iterator Archive::end_children() const { - return Child(this, StringRef(0, 0)); +Archive::child_iterator Archive::child_end() const { + return Child(this, nullptr); } -error_code Archive::Symbol::getName(StringRef &Result) const { - Result = - StringRef(Parent->SymbolTable->getBuffer()->getBufferStart() + StringIndex); - return object_error::success; +StringRef Archive::Symbol::getName() const { + return Parent->SymbolTable->getBuffer().begin() + StringIndex; } -error_code Archive::Symbol::getMember(child_iterator &Result) const { - const char *buf = Parent->SymbolTable->getBuffer()->getBufferStart(); - uint32_t member_count = *reinterpret_cast(buf); - const char *offsets = buf + 4; - buf += 4 + (member_count * 4); // Skip offsets. - const char *indicies = buf + 4; +ErrorOr Archive::Symbol::getMember() const { + const char *Buf = Parent->SymbolTable->getBuffer().begin(); + const char *Offsets = Buf + 4; + uint32_t Offset = 0; + if (Parent->kind() == K_GNU) { + Offset = *(reinterpret_cast(Offsets) + + SymbolIndex); + } else if (Parent->kind() == K_BSD) { + // The SymbolIndex is an index into the ranlib structs that start at + // Offsets (the first uint32_t is the number of bytes of the ranlib + // structs). The ranlib structs are a pair of uint32_t's the first + // being a string table offset and the second being the offset into + // the archive of the member that defines the symbol. Which is what + // is needed here. + Offset = *(reinterpret_cast(Offsets) + + (SymbolIndex * 2) + 1); + } else { + uint32_t MemberCount = *reinterpret_cast(Buf); + + // Skip offsets. + Buf += sizeof(support::ulittle32_t) + + (MemberCount * sizeof(support::ulittle32_t)); + + uint32_t SymbolCount = *reinterpret_cast(Buf); + + if (SymbolIndex >= SymbolCount) + return object_error::parse_failed; - uint16_t offsetindex = - *(reinterpret_cast(indicies) - + SymbolIndex); + // Skip SymbolCount to get to the indices table. + const char *Indices = Buf + sizeof(support::ulittle32_t); - uint32_t offset = *(reinterpret_cast(offsets) - + (offsetindex - 1)); + // Get the index of the offset in the file member offset table for this + // symbol. + uint16_t OffsetIndex = + *(reinterpret_cast(Indices) + + SymbolIndex); + // Subtract 1 since OffsetIndex is 1 based. + --OffsetIndex; - const char *Loc = Parent->getData().begin() + offset; - size_t Size = sizeof(ArchiveMemberHeader) + - ToHeader(Loc)->getSize(); - Result = Child(Parent, StringRef(Loc, Size)); + if (OffsetIndex >= MemberCount) + return object_error::parse_failed; - return object_error::success; + Offset = *(reinterpret_cast(Offsets) + + OffsetIndex); + } + + const char *Loc = Parent->getData().begin() + Offset; + child_iterator Iter(Child(Parent, Loc)); + return Iter; } 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; + if (Parent->kind() == K_BSD) { + // t.StringIndex is an offset from the start of the __.SYMDEF or + // "__.SYMDEF SORTED" member into the string table for the ranlib + // struct indexed by t.SymbolIndex . To change t.StringIndex to the + // offset in the string table for t.SymbolIndex+1 we subtract the + // its offset from the start of the string table for t.SymbolIndex + // and add the offset of the string table for t.SymbolIndex+1. + + // The __.SYMDEF or "__.SYMDEF SORTED" member starts with a uint32_t + // which is the number of bytes of ranlib structs that follow. The ranlib + // structs are a pair of uint32_t's the first being a string table offset + // and the second being the offset into the archive of the member that + // define the symbol. After that the next uint32_t is the byte count of + // the string table followed by the string table. + const char *Buf = Parent->SymbolTable->getBuffer().begin(); + uint32_t RanlibCount = 0; + RanlibCount = (*reinterpret_cast(Buf)) / + (sizeof(uint32_t) * 2); + // If t.SymbolIndex + 1 will be past the count of symbols (the RanlibCount) + // don't change the t.StringIndex as we don't want to reference a ranlib + // past RanlibCount. + if (t.SymbolIndex + 1 < RanlibCount) { + const char *Ranlibs = Buf + 4; + uint32_t CurRanStrx = 0; + uint32_t NextRanStrx = 0; + CurRanStrx = *(reinterpret_cast(Ranlibs) + + (t.SymbolIndex * 2)); + NextRanStrx = *(reinterpret_cast(Ranlibs) + + ((t.SymbolIndex + 1) * 2)); + t.StringIndex -= CurRanStrx; + t.StringIndex += NextRanStrx; + } + } else { + // Go to one past next null. + t.StringIndex = + 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(); - uint32_t member_count = *reinterpret_cast(buf); - buf += 4 + (member_count * 4); // Skip offsets. - uint32_t symbol_count = *reinterpret_cast(buf); - buf += 4 + (symbol_count * 2); // Skip indices. - uint32_t string_start_offset = - buf - SymbolTable->getBuffer()->getBufferStart(); +Archive::symbol_iterator Archive::symbol_begin() 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; + symbol_count = *reinterpret_cast(buf); + buf += sizeof(uint32_t) + (symbol_count * (sizeof(uint32_t))); + } else if (kind() == K_BSD) { + // The __.SYMDEF or "__.SYMDEF SORTED" member starts with a uint32_t + // which is the number of bytes of ranlib structs that follow. The ranlib + // structs are a pair of uint32_t's the first being a string table offset + // and the second being the offset into the archive of the member that + // define the symbol. After that the next uint32_t is the byte count of + // the string table followed by the string table. + uint32_t ranlib_count = 0; + ranlib_count = (*reinterpret_cast(buf)) / + (sizeof(uint32_t) * 2); + const char *ranlibs = buf + 4; + uint32_t ran_strx = 0; + ran_strx = *(reinterpret_cast(ranlibs)); + buf += sizeof(uint32_t) + (ranlib_count * (2 * (sizeof(uint32_t)))); + // Skip the byte count of the string table. + buf += sizeof(uint32_t); + buf += ran_strx; + } else { + uint32_t member_count = 0; + uint32_t symbol_count = 0; + member_count = *reinterpret_cast(buf); + buf += 4 + (member_count * 4); // Skip offsets. + symbol_count = *reinterpret_cast(buf); + buf += 4 + (symbol_count * 2); // Skip indices. + } + 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(); - uint32_t member_count = *reinterpret_cast(buf); - buf += 4 + (member_count * 4); // Skip offsets. - uint32_t symbol_count = *reinterpret_cast(buf); +Archive::symbol_iterator Archive::symbol_end() 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(buf); + } else if (kind() == K_BSD) { + symbol_count = (*reinterpret_cast(buf)) / + (sizeof(uint32_t) * 2); + } else { + uint32_t member_count = 0; + member_count = *reinterpret_cast(buf); + buf += 4 + (member_count * 4); // Skip offsets. + symbol_count = *reinterpret_cast(buf); + } return symbol_iterator( Symbol(this, symbol_count, 0)); } + +Archive::child_iterator Archive::findSym(StringRef name) const { + Archive::symbol_iterator bs = symbol_begin(); + Archive::symbol_iterator es = symbol_end(); + + for (; bs != es; ++bs) { + StringRef SymName = bs->getName(); + if (SymName == name) { + ErrorOr ResultOrErr = bs->getMember(); + // FIXME: Should we really eat the error? + if (ResultOrErr.getError()) + return child_end(); + return ResultOrErr.get(); + } + } + return child_end(); +} + +bool Archive::hasSymbolTable() const { + return SymbolTable != child_end(); +}