diff --git a/include/llvm/Object/Archive.h b/include/llvm/Object/Archive.h index e461564ace8..597f0d48c11 100644 --- a/include/llvm/Object/Archive.h +++ b/include/llvm/Object/Archive.h @@ -94,9 +94,7 @@ public: /// \return the size in the archive header for this member. uint64_t getRawSize() const; - StringRef getBuffer() const { - return StringRef(Data.data() + StartOfFile, getSize()); - } + ErrorOr getBuffer() const; uint64_t getChildOffset() const; ErrorOr getMemoryBufferRef() const; @@ -208,7 +206,11 @@ public: bool hasSymbolTable() const; child_iterator getSymbolTableChild() const { return SymbolTable; } - StringRef getSymbolTable() const { return SymbolTable->getBuffer(); } + StringRef getSymbolTable() const { + // We know that the symbol table is not an external file, + // so we just assert there is no error. + return *SymbolTable->getBuffer(); + } uint32_t getNumberOfSymbols() const; private: @@ -217,6 +219,7 @@ private: child_iterator FirstRegular; unsigned Format : 2; unsigned IsThin : 1; + mutable std::vector> ThinBuffers; }; } diff --git a/lib/Object/Archive.cpp b/lib/Object/Archive.cpp index c29e63941f2..d4821196a6c 100644 --- a/lib/Object/Archive.cpp +++ b/lib/Object/Archive.cpp @@ -17,6 +17,7 @@ #include "llvm/ADT/Twine.h" #include "llvm/Support/Endian.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" using namespace llvm; using namespace object; @@ -115,6 +116,23 @@ uint64_t Archive::Child::getRawSize() const { return getHeader()->getSize(); } +ErrorOr Archive::Child::getBuffer() const { + if (!Parent->IsThin) + return StringRef(Data.data() + StartOfFile, getSize()); + ErrorOr Name = getName(); + if (std::error_code EC = Name.getError()) + return EC; + SmallString<128> FullName = + Parent->getMemoryBufferRef().getBufferIdentifier(); + sys::path::remove_filename(FullName); + sys::path::append(FullName, *Name); + ErrorOr> Buf = MemoryBuffer::getFile(FullName); + if (std::error_code EC = Buf.getError()) + return EC; + Parent->ThinBuffers.push_back(std::move(*Buf)); + return Parent->ThinBuffers.back()->getBuffer(); +} + Archive::Child Archive::Child::getNext() const { size_t SpaceToSkip = Data.size(); // If it's odd, add 1 to make it even. @@ -186,7 +204,10 @@ ErrorOr Archive::Child::getMemoryBufferRef() const { if (std::error_code EC = NameOrErr.getError()) return EC; StringRef Name = NameOrErr.get(); - return MemoryBufferRef(getBuffer(), Name); + ErrorOr Buf = getBuffer(); + if (std::error_code EC = Buf.getError()) + return EC; + return MemoryBufferRef(*Buf, Name); } ErrorOr> diff --git a/test/Object/archive-extract.test b/test/Object/archive-extract.test index c1ddcf71725..a77adf2cabb 100644 --- a/test/Object/archive-extract.test +++ b/test/Object/archive-extract.test @@ -48,3 +48,9 @@ NOTFOUND: foo.o was not found RUN: not llvm-ar x %p/Inputs/thin.a foo.o 2>&1 | FileCheck %s --check-prefix=THINEXTRACT THINEXTRACT: extracting from a thin archive is not supported + +RUN: llvm-ar p %p/Inputs/thin.a evenlen | FileCheck %s --check-prefix=EVENLEN +EVENLEN: evenlen + +RUN: not llvm-ar p %p/Inputs/thin-path.a t/test2.o | FileCheck %s --check-prefix=MISSING +MISSING: No such file or directory. diff --git a/tools/llvm-ar/llvm-ar.cpp b/tools/llvm-ar/llvm-ar.cpp index c87606d7826..2c9668c63b8 100644 --- a/tools/llvm-ar/llvm-ar.cpp +++ b/tools/llvm-ar/llvm-ar.cpp @@ -299,7 +299,9 @@ static void doPrint(StringRef Name, const object::Archive::Child &C) { if (Verbose) outs() << "Printing " << Name << "\n"; - StringRef Data = C.getBuffer(); + ErrorOr DataOrErr = C.getBuffer(); + failIfError(DataOrErr.getError()); + StringRef Data = *DataOrErr; outs().write(Data.data(), Data.size()); } @@ -355,7 +357,7 @@ static void doExtract(StringRef Name, const object::Archive::Child &C) { raw_fd_ostream file(FD, false); // Get the data and its length - StringRef Data = C.getBuffer(); + StringRef Data = *C.getBuffer(); // Write the data. file.write(Data.data(), Data.size());