diff options
Diffstat (limited to 'lib/Object/Archive.cpp')
-rw-r--r-- | lib/Object/Archive.cpp | 189 |
1 files changed, 132 insertions, 57 deletions
diff --git a/lib/Object/Archive.cpp b/lib/Object/Archive.cpp index 99b0650c8b7e..daf301e2e7e4 100644 --- a/lib/Object/Archive.cpp +++ b/lib/Object/Archive.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #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" @@ -52,14 +51,14 @@ ErrorOr<uint32_t> ArchiveMemberHeader::getSize() const { sys::fs::perms ArchiveMemberHeader::getAccessMode() const { unsigned Ret; - if (StringRef(AccessMode, sizeof(AccessMode)).rtrim(" ").getAsInteger(8, 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); } sys::TimeValue ArchiveMemberHeader::getLastModified() const { unsigned Seconds; - if (StringRef(LastModified, sizeof(LastModified)).rtrim(" ") + if (StringRef(LastModified, sizeof(LastModified)).rtrim(' ') .getAsInteger(10, Seconds)) llvm_unreachable("Last modified time not a decimal number."); @@ -70,14 +69,20 @@ sys::TimeValue ArchiveMemberHeader::getLastModified() const { unsigned ArchiveMemberHeader::getUID() const { unsigned Ret; - if (StringRef(UID, sizeof(UID)).rtrim(" ").getAsInteger(10, Ret)) + StringRef User = StringRef(UID, sizeof(UID)).rtrim(' '); + if (User.empty()) + return 0; + if (User.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)) + StringRef Group = StringRef(GID, sizeof(GID)).rtrim(' '); + if (Group.empty()) + return 0; + if (Group.getAsInteger(10, Ret)) llvm_unreachable("GID time not a decimal number."); return Ret; } @@ -108,7 +113,7 @@ Archive::Child::Child(const Archive *Parent, const char *Start, StringRef Name = getRawName(); if (Name.startswith("#1/")) { uint64_t NameSize; - if (Name.substr(3).rtrim(" ").getAsInteger(10, NameSize)) + if (Name.substr(3).rtrim(' ').getAsInteger(10, NameSize)) llvm_unreachable("Long name length is not an integer"); StartOfFile += NameSize; } @@ -136,6 +141,21 @@ bool Archive::Child::isThinMember() const { return Parent->IsThin && Name != "/" && Name != "//"; } +ErrorOr<std::string> Archive::Child::getFullName() const { + assert(isThinMember()); + ErrorOr<StringRef> NameOrErr = getName(); + if (std::error_code EC = NameOrErr.getError()) + return EC; + StringRef Name = *NameOrErr; + if (sys::path::is_absolute(Name)) + return Name; + + SmallString<128> FullName = sys::path::parent_path( + Parent->getMemoryBufferRef().getBufferIdentifier()); + sys::path::append(FullName, Name); + return StringRef(FullName); +} + ErrorOr<StringRef> Archive::Child::getBuffer() const { if (!isThinMember()) { ErrorOr<uint32_t> Size = getSize(); @@ -143,12 +163,10 @@ ErrorOr<StringRef> Archive::Child::getBuffer() const { return EC; return StringRef(Data.data() + StartOfFile, Size.get()); } - ErrorOr<StringRef> Name = getName(); - if (std::error_code EC = Name.getError()) + ErrorOr<std::string> FullNameOrEr = getFullName(); + if (std::error_code EC = FullNameOrEr.getError()) return EC; - SmallString<128> FullName = sys::path::parent_path( - Parent->getMemoryBufferRef().getBufferIdentifier()); - sys::path::append(FullName, *Name); + const std::string &FullName = *FullNameOrEr; ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = MemoryBuffer::getFile(FullName); if (std::error_code EC = Buf.getError()) return EC; @@ -197,7 +215,7 @@ ErrorOr<StringRef> Archive::Child::getName() const { // It's a long name. // Get the offset. std::size_t offset; - if (name.substr(1).rtrim(" ").getAsInteger(10, offset)) + if (name.substr(1).rtrim(' ').getAsInteger(10, offset)) llvm_unreachable("Long name offset is not an integer"); // Verify it. @@ -213,10 +231,14 @@ ErrorOr<StringRef> Archive::Child::getName() const { return StringRef(addr); } else if (name.startswith("#1/")) { uint64_t name_size; - if (name.substr(3).rtrim(" ").getAsInteger(10, 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)); + return Data.substr(sizeof(ArchiveMemberHeader), name_size).rtrim('\0'); + } else { + // It is not a long name so trim the blanks at the end of the name. + if (name[name.size() - 1] != '/') { + return name.rtrim(' '); + } } // It's a simple name. if (name[name.size() - 1] == '/') @@ -235,20 +257,23 @@ ErrorOr<MemoryBufferRef> Archive::Child::getMemoryBufferRef() const { return MemoryBufferRef(*Buf, Name); } -ErrorOr<std::unique_ptr<Binary>> +Expected<std::unique_ptr<Binary>> Archive::Child::getAsBinary(LLVMContext *Context) const { ErrorOr<MemoryBufferRef> BuffOrErr = getMemoryBufferRef(); if (std::error_code EC = BuffOrErr.getError()) - return EC; + return errorCodeToError(EC); - return createBinary(BuffOrErr.get(), Context); + auto BinaryOrErr = createBinary(BuffOrErr.get(), Context); + if (BinaryOrErr) + return std::move(*BinaryOrErr); + return BinaryOrErr.takeError(); } -ErrorOr<std::unique_ptr<Archive>> Archive::create(MemoryBufferRef Source) { - std::error_code EC; - std::unique_ptr<Archive> Ret(new Archive(Source, EC)); - if (EC) - return EC; +Expected<std::unique_ptr<Archive>> Archive::create(MemoryBufferRef Source) { + Error Err; + std::unique_ptr<Archive> Ret(new Archive(Source, Err)); + if (Err) + return std::move(Err); return std::move(Ret); } @@ -257,8 +282,9 @@ void Archive::setFirstRegular(const Child &C) { FirstRegularStartOfFile = C.StartOfFile; } -Archive::Archive(MemoryBufferRef Source, std::error_code &ec) +Archive::Archive(MemoryBufferRef Source, Error &Err) : Binary(Binary::ID_Archive, Source) { + ErrorAsOutParameter ErrAsOutParam(Err); StringRef Buffer = Data.getBuffer(); // Check for sufficient magic. if (Buffer.startswith(ThinMagic)) { @@ -266,27 +292,33 @@ Archive::Archive(MemoryBufferRef Source, std::error_code &ec) } else if (Buffer.startswith(Magic)) { IsThin = false; } else { - ec = object_error::invalid_file_type; + Err = make_error<GenericBinaryError>("File too small to be an archive", + object_error::invalid_file_type); return; } // Get the special members. - child_iterator I = child_begin(false); - if ((ec = I->getError())) + child_iterator I = child_begin(Err, false); + if (Err) return; child_iterator E = child_end(); + // This is at least a valid empty archive. Since an empty archive is the + // same in all formats, just claim it to be gnu to make sure Format is + // initialized. + Format = K_GNU; + if (I == E) { - ec = std::error_code(); + Err = Error::success(); return; } - const Child *C = &**I; + const Child *C = &*I; auto Increment = [&]() { ++I; - if ((ec = I->getError())) + if (Err) return true; - C = &**I; + C = &*I; return false; }; @@ -311,8 +343,11 @@ Archive::Archive(MemoryBufferRef Source, std::error_code &ec) // 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; + if (Name == "__.SYMDEF" || Name == "__.SYMDEF_64") { + if (Name == "__.SYMDEF") + Format = K_BSD; + else // Name == "__.SYMDEF_64" + Format = K_DARWIN64; // We know that the symbol table is not an external file, so we just assert // there is no error. SymbolTable = *C->getBuffer(); @@ -320,7 +355,7 @@ Archive::Archive(MemoryBufferRef Source, std::error_code &ec) return; setFirstRegular(*C); - ec = std::error_code(); + Err = Error::success(); return; } @@ -328,9 +363,10 @@ Archive::Archive(MemoryBufferRef Source, std::error_code &ec) Format = K_BSD; // We know this is BSD, so getName will work since there is no string table. ErrorOr<StringRef> NameOrErr = C->getName(); - ec = NameOrErr.getError(); - if (ec) + if (auto ec = NameOrErr.getError()) { + Err = errorCodeToError(ec); return; + } Name = NameOrErr.get(); if (Name == "__.SYMDEF SORTED" || Name == "__.SYMDEF") { // We know that the symbol table is not an external file, so we just @@ -339,6 +375,14 @@ Archive::Archive(MemoryBufferRef Source, std::error_code &ec) if (Increment()) return; } + else if (Name == "__.SYMDEF_64 SORTED" || Name == "__.SYMDEF_64") { + Format = K_DARWIN64; + // We know that the symbol table is not an external file, so we just + // assert there is no error. + SymbolTable = *C->getBuffer(); + if (Increment()) + return; + } setFirstRegular(*C); return; } @@ -359,7 +403,7 @@ Archive::Archive(MemoryBufferRef Source, std::error_code &ec) if (Increment()) return; if (I == E) { - ec = std::error_code(); + Err = Error::success(); return; } Name = C->getRawName(); @@ -373,19 +417,19 @@ Archive::Archive(MemoryBufferRef Source, std::error_code &ec) if (Increment()) return; setFirstRegular(*C); - ec = std::error_code(); + Err = Error::success(); return; } if (Name[0] != '/') { Format = has64SymTable ? K_MIPS64 : K_GNU; setFirstRegular(*C); - ec = std::error_code(); + Err = Error::success(); return; } if (Name != "/") { - ec = object_error::parse_failed; + Err = errorCodeToError(object_error::parse_failed); return; } @@ -399,7 +443,7 @@ Archive::Archive(MemoryBufferRef Source, std::error_code &ec) if (I == E) { setFirstRegular(*C); - ec = std::error_code(); + Err = Error::success(); return; } @@ -414,26 +458,32 @@ Archive::Archive(MemoryBufferRef Source, std::error_code &ec) } setFirstRegular(*C); - ec = std::error_code(); + Err = Error::success(); } -Archive::child_iterator Archive::child_begin(bool SkipInternal) const { +Archive::child_iterator Archive::child_begin(Error &Err, + bool SkipInternal) const { if (Data.getBufferSize() == 8) // empty archive. return child_end(); if (SkipInternal) - return Child(this, FirstRegularData, FirstRegularStartOfFile); + return child_iterator(Child(this, FirstRegularData, + FirstRegularStartOfFile), + &Err); const char *Loc = Data.getBufferStart() + strlen(Magic); std::error_code EC; - Child c(this, Loc, &EC); - if (EC) - return child_iterator(EC); - return child_iterator(c); + Child C(this, Loc, &EC); + if (EC) { + ErrorAsOutParameter ErrAsOutParam(Err); + Err = errorCodeToError(EC); + return child_end(); + } + return child_iterator(C, &Err); } Archive::child_iterator Archive::child_end() const { - return Child(this, nullptr, nullptr); + return child_iterator(Child(this, nullptr, nullptr), nullptr); } StringRef Archive::Symbol::getName() const { @@ -443,7 +493,7 @@ StringRef Archive::Symbol::getName() const { ErrorOr<Archive::Child> Archive::Symbol::getMember() const { const char *Buf = Parent->getSymbolTable().begin(); const char *Offsets = Buf; - if (Parent->kind() == K_MIPS64) + if (Parent->kind() == K_MIPS64 || Parent->kind() == K_DARWIN64) Offsets += sizeof(uint64_t); else Offsets += sizeof(uint32_t); @@ -460,6 +510,14 @@ ErrorOr<Archive::Child> Archive::Symbol::getMember() const { // the archive of the member that defines the symbol. Which is what // is needed here. Offset = read32le(Offsets + SymbolIndex * 8 + 4); + } else if (Parent->kind() == K_DARWIN64) { + // The SymbolIndex is an index into the ranlib_64 structs that start at + // Offsets (the first uint64_t is the number of bytes of the ranlib_64 + // structs). The ranlib_64 structs are a pair of uint64_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 = read64le(Offsets + SymbolIndex * 16 + 8); } else { // Skip offsets. uint32_t MemberCount = read32le(Buf); @@ -559,6 +617,22 @@ Archive::symbol_iterator Archive::symbol_begin() const { // Skip the byte count of the string table. buf += sizeof(uint32_t); buf += ran_strx; + } else if (kind() == K_DARWIN64) { + // The __.SYMDEF_64 or "__.SYMDEF_64 SORTED" member starts with a uint64_t + // which is the number of bytes of ranlib_64 structs that follow. The + // ranlib_64 structs are a pair of uint64_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 uint64_t is the byte + // count of the string table followed by the string table. + uint64_t ranlib_count = 0; + ranlib_count = read64le(buf) / 16; + const char *ranlibs = buf + 8; + uint64_t ran_strx = 0; + ran_strx = read64le(ranlibs); + buf += sizeof(uint64_t) + (ranlib_count * (2 * (sizeof(uint64_t)))); + // Skip the byte count of the string table. + buf += sizeof(uint64_t); + buf += ran_strx; } else { uint32_t member_count = 0; uint32_t symbol_count = 0; @@ -585,27 +659,28 @@ uint32_t Archive::getNumberOfSymbols() const { return read64be(buf); if (kind() == K_BSD) return read32le(buf) / 8; + if (kind() == K_DARWIN64) + return read64le(buf) / 16; uint32_t member_count = 0; member_count = read32le(buf); buf += 4 + (member_count * 4); // Skip offsets. return read32le(buf); } -Archive::child_iterator Archive::findSym(StringRef name) const { +Expected<Optional<Archive::Child>> 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<Archive::child_iterator> ResultOrErr = bs->getMember(); - // FIXME: Should we really eat the error? - if (ResultOrErr.getError()) - return child_end(); - return ResultOrErr.get(); + if (auto MemberOrErr = bs->getMember()) + return Child(*MemberOrErr); + else + return errorCodeToError(MemberOrErr.getError()); } } - return child_end(); + return Optional<Child>(); } bool Archive::hasSymbolTable() const { return !SymbolTable.empty(); } |