From fadf8cbec7a9c62f1361dcc470920b9b7f72f91e Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Tue, 14 Jul 2015 22:18:43 +0000 Subject: [PATCH] Add support for reading members out of thin archives. For now the Archive owns the buffers of the thin archive members. This makes for a simple API, but all the buffers are destructed only when the archive is destructed. This should be fine since we close the files after mmap so we should not hit an open file limit. llvm-svn: 242215 --- include/llvm/Object/Archive.h | 11 +++++++---- lib/Object/Archive.cpp | 23 ++++++++++++++++++++++- test/Object/archive-extract.test | 6 ++++++ tools/llvm-ar/llvm-ar.cpp | 6 ++++-- 4 files changed, 39 insertions(+), 7 deletions(-) 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());