[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.
llvm-svn: 219260
diff --git a/llvm/include/llvm/Support/MemoryBuffer.h b/llvm/include/llvm/Support/MemoryBuffer.h
index 341850a..e2f8d7e 100644
--- a/llvm/include/llvm/Support/MemoryBuffer.h
+++ b/llvm/include/llvm/Support/MemoryBuffer.h
@@ -126,6 +126,10 @@
static ErrorOr<std::unique_ptr<MemoryBuffer>>
getFileOrSTDIN(const Twine &Filename, int64_t FileSize = -1);
+ /// Map a subrange of the the specified file as a MemoryBuffer.
+ static ErrorOr<std::unique_ptr<MemoryBuffer>>
+ getFileSlice(const Twine &Filename, uint64_t MapSize, uint64_t Offset);
+
//===--------------------------------------------------------------------===//
// Provided for performance analysis.
//===--------------------------------------------------------------------===//
diff --git a/llvm/lib/Support/MemoryBuffer.cpp b/llvm/lib/Support/MemoryBuffer.cpp
index a9ccf98..7eb0752 100644
--- a/llvm/lib/Support/MemoryBuffer.cpp
+++ b/llvm/lib/Support/MemoryBuffer.cpp
@@ -97,6 +97,10 @@
};
}
+static ErrorOr<std::unique_ptr<MemoryBuffer>>
+getFileAux(const Twine &Filename, int64_t FileSize, uint64_t MapSize,
+ uint64_t Offset, bool RequiresNullTerminator, bool IsVolatileSize);
+
std::unique_ptr<MemoryBuffer>
MemoryBuffer::getMemBuffer(StringRef InputData, StringRef BufferName,
bool RequiresNullTerminator) {
@@ -167,6 +171,12 @@
return getFile(Filename, FileSize);
}
+ErrorOr<std::unique_ptr<MemoryBuffer>>
+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 @@
return MemoryBuffer::getMemBufferCopy(Buffer, BufferName);
}
-static ErrorOr<std::unique_ptr<MemoryBuffer>>
-getFileAux(const Twine &Filename, int64_t FileSize, bool RequiresNullTerminator,
- bool IsVolatileSize);
ErrorOr<std::unique_ptr<MemoryBuffer>>
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<std::unique_ptr<MemoryBuffer>>
@@ -249,15 +256,15 @@
bool IsVolatileSize);
static ErrorOr<std::unique_ptr<MemoryBuffer>>
-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<std::unique_ptr<MemoryBuffer>> Ret =
- getOpenFileImpl(FD, Filename, FileSize, FileSize, 0,
+ getOpenFileImpl(FD, Filename, FileSize, MapSize, Offset,
RequiresNullTerminator, IsVolatileSize);
close(FD);
return Ret;
diff --git a/llvm/unittests/Support/MemoryBufferTest.cpp b/llvm/unittests/Support/MemoryBufferTest.cpp
index 93bf301..1cdd6ad 100644
--- a/llvm/unittests/Support/MemoryBufferTest.cpp
+++ b/llvm/unittests/Support/MemoryBufferTest.cpp
@@ -169,4 +169,54 @@
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<OwningBuffer> 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<OwningBuffer> 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"));
+
+}
+
+
+
}