From: Nick Kledzik Date: Wed, 8 Oct 2014 00:22:18 +0000 (+0000) Subject: [Support] Add MemoryBuffer::getFileSlice() X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=commitdiff_plain;h=52688c3aff57defe144c7a87e3622050ba2d3997 [Support] Add MemoryBuffer::getFileSlice() mach-o supports "fat" files which are a header/table-of-contents followed by a concatenation of mach-o files built for different architectures. Currently, MemoryBuffer has no easy way to map a subrange (slice) of a file which lld will need to select a mach-o slice of a fat file. The new function provides an easy way to map a slice of a file into a MemoryBuffer. Test case included. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@219260 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/Support/MemoryBuffer.h b/include/llvm/Support/MemoryBuffer.h index 341850a538d..e2f8d7e90fe 100644 --- a/include/llvm/Support/MemoryBuffer.h +++ b/include/llvm/Support/MemoryBuffer.h @@ -126,6 +126,10 @@ public: static ErrorOr> getFileOrSTDIN(const Twine &Filename, int64_t FileSize = -1); + /// Map a subrange of the the specified file as a MemoryBuffer. + static ErrorOr> + getFileSlice(const Twine &Filename, uint64_t MapSize, uint64_t Offset); + //===--------------------------------------------------------------------===// // Provided for performance analysis. //===--------------------------------------------------------------------===// diff --git a/lib/Support/MemoryBuffer.cpp b/lib/Support/MemoryBuffer.cpp index a9ccf98f1b3..7eb0752c222 100644 --- a/lib/Support/MemoryBuffer.cpp +++ b/lib/Support/MemoryBuffer.cpp @@ -97,6 +97,10 @@ public: }; } +static ErrorOr> +getFileAux(const Twine &Filename, int64_t FileSize, uint64_t MapSize, + uint64_t Offset, bool RequiresNullTerminator, bool IsVolatileSize); + std::unique_ptr MemoryBuffer::getMemBuffer(StringRef InputData, StringRef BufferName, bool RequiresNullTerminator) { @@ -167,6 +171,12 @@ MemoryBuffer::getFileOrSTDIN(const Twine &Filename, int64_t FileSize) { return getFile(Filename, FileSize); } +ErrorOr> +MemoryBuffer::getFileSlice(const Twine &FilePath, uint64_t MapSize, + uint64_t Offset) { + return getFileAux(FilePath, -1, MapSize, Offset, false, false); +} + //===----------------------------------------------------------------------===// // MemoryBuffer::getFile implementation. @@ -232,15 +242,12 @@ getMemoryBufferForStream(int FD, const Twine &BufferName) { return MemoryBuffer::getMemBufferCopy(Buffer, BufferName); } -static ErrorOr> -getFileAux(const Twine &Filename, int64_t FileSize, bool RequiresNullTerminator, - bool IsVolatileSize); ErrorOr> MemoryBuffer::getFile(const Twine &Filename, int64_t FileSize, bool RequiresNullTerminator, bool IsVolatileSize) { - return getFileAux(Filename, FileSize, RequiresNullTerminator, - IsVolatileSize); + return getFileAux(Filename, FileSize, FileSize, 0, + RequiresNullTerminator, IsVolatileSize); } static ErrorOr> @@ -249,15 +256,15 @@ getOpenFileImpl(int FD, const Twine &Filename, uint64_t FileSize, bool IsVolatileSize); static ErrorOr> -getFileAux(const Twine &Filename, int64_t FileSize, bool RequiresNullTerminator, - bool IsVolatileSize) { +getFileAux(const Twine &Filename, int64_t FileSize, uint64_t MapSize, + uint64_t Offset, bool RequiresNullTerminator, bool IsVolatileSize) { int FD; std::error_code EC = sys::fs::openFileForRead(Filename, FD); if (EC) return EC; ErrorOr> Ret = - getOpenFileImpl(FD, Filename, FileSize, FileSize, 0, + getOpenFileImpl(FD, Filename, FileSize, MapSize, Offset, RequiresNullTerminator, IsVolatileSize); close(FD); return Ret; diff --git a/unittests/Support/MemoryBufferTest.cpp b/unittests/Support/MemoryBufferTest.cpp index 93bf301267e..1cdd6adbf8b 100644 --- a/unittests/Support/MemoryBufferTest.cpp +++ b/unittests/Support/MemoryBufferTest.cpp @@ -169,4 +169,54 @@ TEST_F(MemoryBufferTest, getOpenFileReopened) { testGetOpenFileSlice(true); } + +TEST_F(MemoryBufferTest, slice) { + // Create a file that is six pages long with different data on each page. + int FD; + SmallString<64> TestPath; + sys::fs::createTemporaryFile("MemoryBufferTest_Slice", "temp", FD, TestPath); + raw_fd_ostream OF(FD, true, /*unbuffered=*/true); + for (unsigned i = 0; i < 0x2000 / 8; ++i) { + OF << "12345678"; + } + for (unsigned i = 0; i < 0x2000 / 8; ++i) { + OF << "abcdefgh"; + } + for (unsigned i = 0; i < 0x2000 / 8; ++i) { + OF << "ABCDEFGH"; + } + OF.close(); + + // Try offset of one page. + ErrorOr MB = MemoryBuffer::getFileSlice(TestPath.str(), + 0x4000, 0x1000); + std::error_code EC = MB.getError(); + ASSERT_FALSE(EC); + EXPECT_EQ(0x4000UL, MB.get()->getBufferSize()); + + StringRef BufData = MB.get()->getBuffer(); + EXPECT_TRUE(BufData.substr(0x0000,8).equals("12345678")); + EXPECT_TRUE(BufData.substr(0x0FF8,8).equals("12345678")); + EXPECT_TRUE(BufData.substr(0x1000,8).equals("abcdefgh")); + EXPECT_TRUE(BufData.substr(0x2FF8,8).equals("abcdefgh")); + EXPECT_TRUE(BufData.substr(0x3000,8).equals("ABCDEFGH")); + EXPECT_TRUE(BufData.substr(0x3FF8,8).equals("ABCDEFGH")); + + // Try non-page aligned. + ErrorOr MB2 = MemoryBuffer::getFileSlice(TestPath.str(), + 0x3000, 0x0800); + EC = MB2.getError(); + ASSERT_FALSE(EC); + EXPECT_EQ(0x3000UL, MB2.get()->getBufferSize()); + + StringRef BufData2 = MB2.get()->getBuffer(); + EXPECT_TRUE(BufData2.substr(0x0000,8).equals("12345678")); + EXPECT_TRUE(BufData2.substr(0x17F8,8).equals("12345678")); + EXPECT_TRUE(BufData2.substr(0x1800,8).equals("abcdefgh")); + EXPECT_TRUE(BufData2.substr(0x2FF8,8).equals("abcdefgh")); + +} + + + }