summaryrefslogtreecommitdiffstats
path: root/llvm
diff options
context:
space:
mode:
Diffstat (limited to 'llvm')
-rw-r--r--llvm/include/llvm/BinaryFormat/Minidump.h31
-rw-r--r--llvm/include/llvm/Object/Minidump.h19
-rw-r--r--llvm/lib/Object/Minidump.cpp21
-rw-r--r--llvm/unittests/Object/MinidumpTest.cpp112
4 files changed, 177 insertions, 6 deletions
diff --git a/llvm/include/llvm/BinaryFormat/Minidump.h b/llvm/include/llvm/BinaryFormat/Minidump.h
index 1e2dd972830..2bb75a6cc1f 100644
--- a/llvm/include/llvm/BinaryFormat/Minidump.h
+++ b/llvm/include/llvm/BinaryFormat/Minidump.h
@@ -124,6 +124,37 @@ struct SystemInfo {
};
static_assert(sizeof(SystemInfo) == 56, "");
+struct VSFixedFileInfo {
+ support::ulittle32_t Signature;
+ support::ulittle32_t StructVersion;
+ support::ulittle32_t FileVersionHigh;
+ support::ulittle32_t FileVersionLow;
+ support::ulittle32_t ProductVersionHigh;
+ support::ulittle32_t ProductVersionLow;
+ support::ulittle32_t FileFlagsMask;
+ support::ulittle32_t FileFlags;
+ support::ulittle32_t FileOS;
+ support::ulittle32_t FileType;
+ support::ulittle32_t FileSubtype;
+ support::ulittle32_t FileDateHigh;
+ support::ulittle32_t FileDateLow;
+};
+static_assert(sizeof(VSFixedFileInfo) == 52, "");
+
+struct Module {
+ support::ulittle64_t BaseOfImage;
+ support::ulittle32_t SizeOfImage;
+ support::ulittle32_t Checksum;
+ support::ulittle32_t TimeDateStamp;
+ support::ulittle32_t ModuleNameRVA;
+ VSFixedFileInfo VersionInfo;
+ LocationDescriptor CvRecord;
+ LocationDescriptor MiscRecord;
+ support::ulittle64_t Reserved0;
+ support::ulittle64_t Reserved1;
+};
+static_assert(sizeof(Module) == 108, "");
+
} // namespace minidump
template <> struct DenseMapInfo<minidump::StreamType> {
diff --git a/llvm/include/llvm/Object/Minidump.h b/llvm/include/llvm/Object/Minidump.h
index 63a43d5bd88..0a74fcb4354 100644
--- a/llvm/include/llvm/Object/Minidump.h
+++ b/llvm/include/llvm/Object/Minidump.h
@@ -55,14 +55,21 @@ public:
return getStream<minidump::SystemInfo>(minidump::StreamType::SystemInfo);
}
+ /// Returns the module list embedded in the ModuleList stream. An error is
+ /// returned if the file does not contain this stream, or if the stream is
+ /// not large enough to contain the number of modules declared in the stream
+ /// header. The consistency of the Module entries themselves is not checked in
+ /// any way.
+ Expected<ArrayRef<minidump::Module>> getModuleList() const;
+
private:
- static Error createError(StringRef Str,
- object_error Err = object_error::parse_failed) {
- return make_error<GenericBinaryError>(Str, Err);
+ static Error createError(StringRef Str) {
+ return make_error<GenericBinaryError>(Str, object_error::parse_failed);
}
static Error createEOFError() {
- return createError("Unexpected EOF", object_error::unexpected_eof);
+ return make_error<GenericBinaryError>("Unexpected EOF",
+ object_error::unexpected_eof);
}
/// Return a slice of the given data array, with bounds checking.
@@ -101,9 +108,9 @@ Expected<const T &> MinidumpFile::getStream(minidump::StreamType Stream) const {
if (auto OptionalStream = getRawStream(Stream)) {
if (OptionalStream->size() >= sizeof(T))
return *reinterpret_cast<const T *>(OptionalStream->data());
- return createError("Malformed stream", object_error::unexpected_eof);
+ return createEOFError();
}
- return createError("No such stream", object_error::invalid_section_index);
+ return createError("No such stream");
}
template <typename T>
diff --git a/llvm/lib/Object/Minidump.cpp b/llvm/lib/Object/Minidump.cpp
index 1a22491ce3c..4b1abe52994 100644
--- a/llvm/lib/Object/Minidump.cpp
+++ b/llvm/lib/Object/Minidump.cpp
@@ -53,6 +53,27 @@ Expected<std::string> MinidumpFile::getString(size_t Offset) const {
return Result;
}
+Expected<ArrayRef<Module>> MinidumpFile::getModuleList() const {
+ auto OptionalStream = getRawStream(StreamType::ModuleList);
+ if (!OptionalStream)
+ return createError("No such stream");
+ auto ExpectedSize =
+ getDataSliceAs<support::ulittle32_t>(*OptionalStream, 0, 1);
+ if (!ExpectedSize)
+ return ExpectedSize.takeError();
+
+ size_t ListSize = ExpectedSize.get()[0];
+
+ size_t ListOffset = 4;
+ // Some producers insert additional padding bytes to align the module list to
+ // 8-byte boundary. Check for that by comparing the module list size with the
+ // overall stream size.
+ if (ListOffset + sizeof(Module) * ListSize < OptionalStream->size())
+ ListOffset = 8;
+
+ return getDataSliceAs<Module>(*OptionalStream, ListOffset, ListSize);
+}
+
Expected<ArrayRef<uint8_t>>
MinidumpFile::getDataSlice(ArrayRef<uint8_t> Data, size_t Offset, size_t Size) {
// Check for overflow.
diff --git a/llvm/unittests/Object/MinidumpTest.cpp b/llvm/unittests/Object/MinidumpTest.cpp
index 06034e1e5ad..fdb9d22db04 100644
--- a/llvm/unittests/Object/MinidumpTest.cpp
+++ b/llvm/unittests/Object/MinidumpTest.cpp
@@ -284,3 +284,115 @@ TEST(MinidumpFile, getString) {
EXPECT_THAT_EXPECTED(File.getString(ManyStrings.size() - 2),
Failed<BinaryError>());
}
+
+TEST(MinidumpFile, getModuleList) {
+ std::vector<uint8_t> OneModule{
+ // Header
+ 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
+ 1, 0, 0, 0, // NumberOfStreams,
+ 32, 0, 0, 0, // StreamDirectoryRVA
+ 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
+ 0, 0, 0, 0, 0, 0, 0, 0, // Flags
+ // Stream Directory
+ 4, 0, 0, 0, 112, 0, 0, 0, // Type, DataSize,
+ 44, 0, 0, 0, // RVA
+ // ModuleList
+ 1, 0, 0, 0, // NumberOfModules
+ 1, 2, 3, 4, 5, 6, 7, 8, // BaseOfImage
+ 9, 0, 1, 2, 3, 4, 5, 6, // SizeOfImage, Checksum
+ 7, 8, 9, 0, 1, 2, 3, 4, // TimeDateStamp, ModuleNameRVA
+ 0, 0, 0, 0, 0, 0, 0, 0, // Signature, StructVersion
+ 0, 0, 0, 0, 0, 0, 0, 0, // FileVersion
+ 0, 0, 0, 0, 0, 0, 0, 0, // ProductVersion
+ 0, 0, 0, 0, 0, 0, 0, 0, // FileFlagsMask, FileFlags
+ 0, 0, 0, 0, // FileOS
+ 0, 0, 0, 0, 0, 0, 0, 0, // FileType, FileSubType
+ 0, 0, 0, 0, 0, 0, 0, 0, // FileDate
+ 1, 2, 3, 4, 5, 6, 7, 8, // CvRecord
+ 9, 0, 1, 2, 3, 4, 5, 6, // MiscRecord
+ 7, 8, 9, 0, 1, 2, 3, 4, // Reserved0
+ 5, 6, 7, 8, 9, 0, 1, 2, // Reserved1
+ };
+ // Same as before, but with a padded module list.
+ std::vector<uint8_t> PaddedModule{
+ // Header
+ 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
+ 1, 0, 0, 0, // NumberOfStreams,
+ 32, 0, 0, 0, // StreamDirectoryRVA
+ 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
+ 0, 0, 0, 0, 0, 0, 0, 0, // Flags
+ // Stream Directory
+ 4, 0, 0, 0, 116, 0, 0, 0, // Type, DataSize,
+ 44, 0, 0, 0, // RVA
+ // ModuleList
+ 1, 0, 0, 0, // NumberOfModules
+ 0, 0, 0, 0, // Padding
+ 1, 2, 3, 4, 5, 6, 7, 8, // BaseOfImage
+ 9, 0, 1, 2, 3, 4, 5, 6, // SizeOfImage, Checksum
+ 7, 8, 9, 0, 1, 2, 3, 4, // TimeDateStamp, ModuleNameRVA
+ 0, 0, 0, 0, 0, 0, 0, 0, // Signature, StructVersion
+ 0, 0, 0, 0, 0, 0, 0, 0, // FileVersion
+ 0, 0, 0, 0, 0, 0, 0, 0, // ProductVersion
+ 0, 0, 0, 0, 0, 0, 0, 0, // FileFlagsMask, FileFlags
+ 0, 0, 0, 0, // FileOS
+ 0, 0, 0, 0, 0, 0, 0, 0, // FileType, FileSubType
+ 0, 0, 0, 0, 0, 0, 0, 0, // FileDate
+ 1, 2, 3, 4, 5, 6, 7, 8, // CvRecord
+ 9, 0, 1, 2, 3, 4, 5, 6, // MiscRecord
+ 7, 8, 9, 0, 1, 2, 3, 4, // Reserved0
+ 5, 6, 7, 8, 9, 0, 1, 2, // Reserved1
+ };
+
+ for (const std::vector<uint8_t> &Data : {OneModule, PaddedModule}) {
+ auto ExpectedFile = create(Data);
+ ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
+ const MinidumpFile &File = **ExpectedFile;
+ Expected<ArrayRef<Module>> ExpectedModule = File.getModuleList();
+ ASSERT_THAT_EXPECTED(ExpectedModule, Succeeded());
+ ASSERT_EQ(1u, ExpectedModule->size());
+ const Module &M = ExpectedModule.get()[0];
+ EXPECT_EQ(0x0807060504030201u, M.BaseOfImage);
+ EXPECT_EQ(0x02010009u, M.SizeOfImage);
+ EXPECT_EQ(0x06050403u, M.Checksum);
+ EXPECT_EQ(0x00090807u, M.TimeDateStamp);
+ EXPECT_EQ(0x04030201u, M.ModuleNameRVA);
+ EXPECT_EQ(0x04030201u, M.CvRecord.DataSize);
+ EXPECT_EQ(0x08070605u, M.CvRecord.RVA);
+ EXPECT_EQ(0x02010009u, M.MiscRecord.DataSize);
+ EXPECT_EQ(0x06050403u, M.MiscRecord.RVA);
+ EXPECT_EQ(0x0403020100090807u, M.Reserved0);
+ EXPECT_EQ(0x0201000908070605u, M.Reserved1);
+ }
+
+ std::vector<uint8_t> StreamTooShort{
+ // Header
+ 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
+ 1, 0, 0, 0, // NumberOfStreams,
+ 32, 0, 0, 0, // StreamDirectoryRVA
+ 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
+ 0, 0, 0, 0, 0, 0, 0, 0, // Flags
+ // Stream Directory
+ 4, 0, 0, 0, 111, 0, 0, 0, // Type, DataSize,
+ 44, 0, 0, 0, // RVA
+ // ModuleList
+ 1, 0, 0, 0, // NumberOfModules
+ 1, 2, 3, 4, 5, 6, 7, 8, // BaseOfImage
+ 9, 0, 1, 2, 3, 4, 5, 6, // SizeOfImage, Checksum
+ 7, 8, 9, 0, 1, 2, 3, 4, // TimeDateStamp, ModuleNameRVA
+ 0, 0, 0, 0, 0, 0, 0, 0, // Signature, StructVersion
+ 0, 0, 0, 0, 0, 0, 0, 0, // FileVersion
+ 0, 0, 0, 0, 0, 0, 0, 0, // ProductVersion
+ 0, 0, 0, 0, 0, 0, 0, 0, // FileFlagsMask, FileFlags
+ 0, 0, 0, 0, // FileOS
+ 0, 0, 0, 0, 0, 0, 0, 0, // FileType, FileSubType
+ 0, 0, 0, 0, 0, 0, 0, 0, // FileDate
+ 1, 2, 3, 4, 5, 6, 7, 8, // CvRecord
+ 9, 0, 1, 2, 3, 4, 5, 6, // MiscRecord
+ 7, 8, 9, 0, 1, 2, 3, 4, // Reserved0
+ 5, 6, 7, 8, 9, 0, 1, 2, // Reserved1
+ };
+ auto ExpectedFile = create(StreamTooShort);
+ ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
+ const MinidumpFile &File = **ExpectedFile;
+ EXPECT_THAT_EXPECTED(File.getModuleList(), Failed<BinaryError>());
+}
OpenPOWER on IntegriCloud