[llvm] r374051 - Object/minidump: Add support for the MemoryInfoList stream

Pavel Labath via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 8 07:15:32 PDT 2019


Author: labath
Date: Tue Oct  8 07:15:32 2019
New Revision: 374051

URL: http://llvm.org/viewvc/llvm-project?rev=374051&view=rev
Log:
Object/minidump: Add support for the MemoryInfoList stream

Summary:
This patch adds the definitions of the constants and structures
necessary to interpret the MemoryInfoList minidump stream, as well as
the object::MinidumpFile interface to access the stream.

While the code is fairly simple, there is one important deviation from
the other minidump streams, which is worth calling out explicitly.
Unlike other "List" streams, the size of the records inside
MemoryInfoList stream is not known statically. Instead it is described
in the stream header. This makes it impossible to return
ArrayRef<MemoryInfo> from the accessor method, as it is done with other
streams. Instead, I create an iterator class, which can be parameterized
by the runtime size of the structure, and return
iterator_range<iterator> instead.

Reviewers: amccarth, jhenderson, clayborg

Subscribers: JosephTremoulet, zturner, markmentovai, lldb-commits, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D68210

Modified:
    llvm/trunk/include/llvm/BinaryFormat/Minidump.h
    llvm/trunk/include/llvm/BinaryFormat/MinidumpConstants.def
    llvm/trunk/include/llvm/Object/Minidump.h
    llvm/trunk/lib/Object/Minidump.cpp
    llvm/trunk/unittests/Object/MinidumpTest.cpp

Modified: llvm/trunk/include/llvm/BinaryFormat/Minidump.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/BinaryFormat/Minidump.h?rev=374051&r1=374050&r2=374051&view=diff
==============================================================================
--- llvm/trunk/include/llvm/BinaryFormat/Minidump.h (original)
+++ llvm/trunk/include/llvm/BinaryFormat/Minidump.h Tue Oct  8 07:15:32 2019
@@ -18,6 +18,7 @@
 #ifndef LLVM_BINARYFORMAT_MINIDUMP_H
 #define LLVM_BINARYFORMAT_MINIDUMP_H
 
+#include "llvm/ADT/BitmaskEnum.h"
 #include "llvm/ADT/DenseMapInfo.h"
 #include "llvm/Support/Endian.h"
 
@@ -67,6 +68,42 @@ struct MemoryDescriptor {
 };
 static_assert(sizeof(MemoryDescriptor) == 16, "");
 
+struct MemoryInfoListHeader {
+  support::ulittle32_t SizeOfHeader;
+  support::ulittle32_t SizeOfEntry;
+  support::ulittle64_t NumberOfEntries;
+};
+static_assert(sizeof(MemoryInfoListHeader) == 16, "");
+
+enum class MemoryProtection : uint32_t {
+#define HANDLE_MDMP_PROTECT(CODE, NAME, NATIVENAME) NAME = CODE,
+#include "llvm/BinaryFormat/MinidumpConstants.def"
+  LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/0xffffffffu),
+};
+
+enum class MemoryState : uint32_t {
+#define HANDLE_MDMP_MEMSTATE(CODE, NAME, NATIVENAME) NAME = CODE,
+#include "llvm/BinaryFormat/MinidumpConstants.def"
+};
+
+enum class MemoryType : uint32_t {
+#define HANDLE_MDMP_MEMTYPE(CODE, NAME, NATIVENAME) NAME = CODE,
+#include "llvm/BinaryFormat/MinidumpConstants.def"
+};
+
+struct MemoryInfo {
+  support::ulittle64_t BaseAddress;
+  support::ulittle64_t AllocationBase;
+  support::little_t<MemoryProtection> AllocationProtect;
+  support::ulittle32_t Reserved0;
+  support::ulittle64_t RegionSize;
+  support::little_t<MemoryState> State;
+  support::little_t<MemoryProtection> Protect;
+  support::little_t<MemoryType> Type;
+  support::ulittle32_t Reserved1;
+};
+static_assert(sizeof(MemoryInfo) == 48, "");
+
 /// Specifies the location and type of a single stream in the minidump file. The
 /// minidump stream directory is an array of entries of this type, with its size
 /// given by Header.NumberOfStreams.

Modified: llvm/trunk/include/llvm/BinaryFormat/MinidumpConstants.def
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/BinaryFormat/MinidumpConstants.def?rev=374051&r1=374050&r2=374051&view=diff
==============================================================================
--- llvm/trunk/include/llvm/BinaryFormat/MinidumpConstants.def (original)
+++ llvm/trunk/include/llvm/BinaryFormat/MinidumpConstants.def Tue Oct  8 07:15:32 2019
@@ -6,8 +6,9 @@
 //
 //===----------------------------------------------------------------------===//
 
-#if !(defined HANDLE_MDMP_STREAM_TYPE || defined HANDLE_MDMP_ARCH ||           \
-      defined HANDLE_MDMP_PLATFORM)
+#if !(defined(HANDLE_MDMP_STREAM_TYPE) || defined(HANDLE_MDMP_ARCH) ||         \
+      defined(HANDLE_MDMP_PLATFORM) || defined(HANDLE_MDMP_PROTECT) ||         \
+      defined(HANDLE_MDMP_MEMSTATE) || defined(HANDLE_MDMP_MEMTYPE))
 #error "Missing HANDLE_MDMP definition"
 #endif
 
@@ -23,6 +24,18 @@
 #define HANDLE_MDMP_PLATFORM(CODE, NAME)
 #endif
 
+#ifndef HANDLE_MDMP_PROTECT
+#define HANDLE_MDMP_PROTECT(CODE, NAME, NATIVENAME)
+#endif
+
+#ifndef HANDLE_MDMP_MEMSTATE
+#define HANDLE_MDMP_MEMSTATE(CODE, NAME, NATIVENAME)
+#endif
+
+#ifndef HANDLE_MDMP_MEMTYPE
+#define HANDLE_MDMP_MEMTYPE(CODE, NAME, NATIVENAME)
+#endif
+
 HANDLE_MDMP_STREAM_TYPE(0x0003, ThreadList)
 HANDLE_MDMP_STREAM_TYPE(0x0004, ModuleList)
 HANDLE_MDMP_STREAM_TYPE(0x0005, MemoryList)
@@ -102,6 +115,30 @@ HANDLE_MDMP_PLATFORM(0x8203, Android) //
 HANDLE_MDMP_PLATFORM(0x8204, PS3) // PS3
 HANDLE_MDMP_PLATFORM(0x8205, NaCl) // Native Client (NaCl)
 
+HANDLE_MDMP_PROTECT(0x01, NoAccess, PAGE_NO_ACCESS)
+HANDLE_MDMP_PROTECT(0x02, ReadOnly, PAGE_READ_ONLY)
+HANDLE_MDMP_PROTECT(0x04, ReadWrite, PAGE_READ_WRITE)
+HANDLE_MDMP_PROTECT(0x08, WriteCopy, PAGE_WRITE_COPY)
+HANDLE_MDMP_PROTECT(0x10, Execute, PAGE_EXECUTE)
+HANDLE_MDMP_PROTECT(0x20, ExecuteRead, PAGE_EXECUTE_READ)
+HANDLE_MDMP_PROTECT(0x40, ExecuteReadWrite, PAGE_EXECUTE_READ_WRITE)
+HANDLE_MDMP_PROTECT(0x80, ExeciteWriteCopy, PAGE_EXECUTE_WRITE_COPY)
+HANDLE_MDMP_PROTECT(0x100, Guard, PAGE_GUARD)
+HANDLE_MDMP_PROTECT(0x200, NoCache, PAGE_NOCACHE)
+HANDLE_MDMP_PROTECT(0x400, WriteCombine, PAGE_WRITECOMBINE)
+HANDLE_MDMP_PROTECT(0x40000000, TargetsInvalid, PAGE_TARGETS_INVALID)
+
+HANDLE_MDMP_MEMSTATE(0x01000, Commit, MEM_COMMIT)
+HANDLE_MDMP_MEMSTATE(0x02000, Reserve, MEM_RESERVE)
+HANDLE_MDMP_MEMSTATE(0x10000, Free, MEM_FREE)
+
+HANDLE_MDMP_MEMTYPE(0x0020000, Private, MEM_PRIVATE)
+HANDLE_MDMP_MEMTYPE(0x0040000, Mapped, MEM_MAPPED)
+HANDLE_MDMP_MEMTYPE(0x1000000, Image, MEM_IMAGE)
+
 #undef HANDLE_MDMP_STREAM_TYPE
 #undef HANDLE_MDMP_ARCH
 #undef HANDLE_MDMP_PLATFORM
+#undef HANDLE_MDMP_PROTECT
+#undef HANDLE_MDMP_MEMSTATE
+#undef HANDLE_MDMP_MEMTYPE

Modified: llvm/trunk/include/llvm/Object/Minidump.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Object/Minidump.h?rev=374051&r1=374050&r2=374051&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Object/Minidump.h (original)
+++ llvm/trunk/include/llvm/Object/Minidump.h Tue Oct  8 07:15:32 2019
@@ -11,6 +11,7 @@
 
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/iterator.h"
 #include "llvm/BinaryFormat/Minidump.h"
 #include "llvm/Object/Binary.h"
 #include "llvm/Support/Error.h"
@@ -80,16 +81,56 @@ public:
     return getListStream<minidump::Thread>(minidump::StreamType::ThreadList);
   }
 
-  /// Returns the list of memory ranges embedded in the MemoryList 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 memory descriptors
-  /// declared in the stream header. The consistency of the MemoryDescriptor
-  /// entries themselves is not checked in any way.
+  /// Returns the list of descriptors embedded in the MemoryList stream. The
+  /// descriptors provide the content of interesting regions of memory at the
+  /// time the minidump was taken. 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 memory descriptors declared in the stream header. The
+  /// consistency of the MemoryDescriptor entries themselves is not checked in
+  /// any way.
   Expected<ArrayRef<minidump::MemoryDescriptor>> getMemoryList() const {
     return getListStream<minidump::MemoryDescriptor>(
         minidump::StreamType::MemoryList);
   }
 
+  class MemoryInfoIterator
+      : public iterator_facade_base<MemoryInfoIterator,
+                                    std::forward_iterator_tag,
+                                    minidump::MemoryInfo> {
+  public:
+    MemoryInfoIterator(ArrayRef<uint8_t> Storage, size_t Stride)
+        : Storage(Storage), Stride(Stride) {
+      assert(Storage.size() % Stride == 0);
+    }
+
+    bool operator==(const MemoryInfoIterator &R) const {
+      return Storage.size() == R.Storage.size();
+    }
+
+    const minidump::MemoryInfo &operator*() const {
+      assert(Storage.size() >= sizeof(minidump::MemoryInfo));
+      return *reinterpret_cast<const minidump::MemoryInfo *>(Storage.data());
+    }
+
+    MemoryInfoIterator &operator++() {
+      Storage = Storage.drop_front(Stride);
+      return *this;
+    }
+
+  private:
+    ArrayRef<uint8_t> Storage;
+    size_t Stride;
+  };
+
+  /// Returns the list of descriptors embedded in the MemoryInfoList stream. The
+  /// descriptors provide properties (e.g. permissions) of interesting regions
+  /// of memory at the time the minidump was taken. 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 memory descriptors declared in the stream header.
+  /// The consistency of the MemoryInfoList entries themselves is not checked
+  /// in any way.
+  Expected<iterator_range<MemoryInfoIterator>> getMemoryInfoList() const;
+
 private:
   static Error createError(StringRef Str) {
     return make_error<GenericBinaryError>(Str, object_error::parse_failed);
@@ -137,10 +178,10 @@ private:
 };
 
 template <typename T>
-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());
+Expected<const T &> MinidumpFile::getStream(minidump::StreamType Type) const {
+  if (Optional<ArrayRef<uint8_t>> Stream = getRawStream(Type)) {
+    if (Stream->size() >= sizeof(T))
+      return *reinterpret_cast<const T *>(Stream->data());
     return createEOFError();
   }
   return createError("No such stream");
@@ -153,10 +194,11 @@ Expected<ArrayRef<T>> MinidumpFile::getD
   // Check for overflow.
   if (Count > std::numeric_limits<size_t>::max() / sizeof(T))
     return createEOFError();
-  auto ExpectedArray = getDataSlice(Data, Offset, sizeof(T) * Count);
-  if (!ExpectedArray)
-    return ExpectedArray.takeError();
-  return ArrayRef<T>(reinterpret_cast<const T *>(ExpectedArray->data()), Count);
+  Expected<ArrayRef<uint8_t>> Slice =
+      getDataSlice(Data, Offset, sizeof(T) * Count);
+  if (!Slice)
+    return Slice.takeError();
+  return ArrayRef<T>(reinterpret_cast<const T *>(Slice->data()), Count);
 }
 
 } // end namespace object

Modified: llvm/trunk/lib/Object/Minidump.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Object/Minidump.cpp?rev=374051&r1=374050&r2=374051&view=diff
==============================================================================
--- llvm/trunk/lib/Object/Minidump.cpp (original)
+++ llvm/trunk/lib/Object/Minidump.cpp Tue Oct  8 07:15:32 2019
@@ -53,13 +53,30 @@ Expected<std::string> MinidumpFile::getS
   return Result;
 }
 
+Expected<iterator_range<MinidumpFile::MemoryInfoIterator>>
+MinidumpFile::getMemoryInfoList() const {
+  Optional<ArrayRef<uint8_t>> Stream = getRawStream(StreamType::MemoryInfoList);
+  if (!Stream)
+    return createError("No such stream");
+  auto ExpectedHeader =
+      getDataSliceAs<minidump::MemoryInfoListHeader>(*Stream, 0, 1);
+  if (!ExpectedHeader)
+    return ExpectedHeader.takeError();
+  const minidump::MemoryInfoListHeader &H = ExpectedHeader.get()[0];
+  Expected<ArrayRef<uint8_t>> Data =
+      getDataSlice(*Stream, H.SizeOfHeader, H.SizeOfEntry * H.NumberOfEntries);
+  if (!Data)
+    return Data.takeError();
+  return make_range(MemoryInfoIterator(*Data, H.SizeOfEntry),
+                    MemoryInfoIterator({}, H.SizeOfEntry));
+}
+
 template <typename T>
-Expected<ArrayRef<T>> MinidumpFile::getListStream(StreamType Stream) const {
-  auto OptionalStream = getRawStream(Stream);
-  if (!OptionalStream)
+Expected<ArrayRef<T>> MinidumpFile::getListStream(StreamType Type) const {
+  Optional<ArrayRef<uint8_t>> Stream = getRawStream(Type);
+  if (!Stream)
     return createError("No such stream");
-  auto ExpectedSize =
-      getDataSliceAs<support::ulittle32_t>(*OptionalStream, 0, 1);
+  auto ExpectedSize = getDataSliceAs<support::ulittle32_t>(*Stream, 0, 1);
   if (!ExpectedSize)
     return ExpectedSize.takeError();
 
@@ -69,10 +86,10 @@ Expected<ArrayRef<T>> MinidumpFile::getL
   // Some producers insert additional padding bytes to align the list to an
   // 8-byte boundary. Check for that by comparing the list size with the overall
   // stream size.
-  if (ListOffset + sizeof(T) * ListSize < OptionalStream->size())
+  if (ListOffset + sizeof(T) * ListSize < Stream->size())
     ListOffset = 8;
 
-  return getDataSliceAs<T>(*OptionalStream, ListOffset, ListSize);
+  return getDataSliceAs<T>(*Stream, ListOffset, ListSize);
 }
 template Expected<ArrayRef<Module>>
     MinidumpFile::getListStream(StreamType) const;
@@ -109,13 +126,14 @@ MinidumpFile::create(MemoryBufferRef Sou
     return ExpectedStreams.takeError();
 
   DenseMap<StreamType, std::size_t> StreamMap;
-  for (const auto &Stream : llvm::enumerate(*ExpectedStreams)) {
-    StreamType Type = Stream.value().Type;
-    const LocationDescriptor &Loc = Stream.value().Location;
-
-    auto ExpectedStream = getDataSlice(Data, Loc.RVA, Loc.DataSize);
-    if (!ExpectedStream)
-      return ExpectedStream.takeError();
+  for (const auto &StreamDescriptor : llvm::enumerate(*ExpectedStreams)) {
+    StreamType Type = StreamDescriptor.value().Type;
+    const LocationDescriptor &Loc = StreamDescriptor.value().Location;
+
+    Expected<ArrayRef<uint8_t>> Stream =
+        getDataSlice(Data, Loc.RVA, Loc.DataSize);
+    if (!Stream)
+      return Stream.takeError();
 
     if (Type == StreamType::Unused && Loc.DataSize == 0) {
       // Ignore dummy streams. This is technically ill-formed, but a number of
@@ -128,7 +146,7 @@ MinidumpFile::create(MemoryBufferRef Sou
       return createError("Cannot handle one of the minidump streams");
 
     // Update the directory map, checking for duplicate stream types.
-    if (!StreamMap.try_emplace(Type, Stream.index()).second)
+    if (!StreamMap.try_emplace(Type, StreamDescriptor.index()).second)
       return createError("Duplicate stream type");
   }
 

Modified: llvm/trunk/unittests/Object/MinidumpTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Object/MinidumpTest.cpp?rev=374051&r1=374050&r2=374051&view=diff
==============================================================================
--- llvm/trunk/unittests/Object/MinidumpTest.cpp (original)
+++ llvm/trunk/unittests/Object/MinidumpTest.cpp Tue Oct  8 07:15:32 2019
@@ -511,3 +511,202 @@ TEST(MinidumpFile, getMemoryList) {
     EXPECT_EQ(0x00090807u, MD.Memory.RVA);
   }
 }
+
+TEST(MinidumpFile, getMemoryInfoList) {
+  std::vector<uint8_t> OneEntry{
+      // 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
+      16, 0, 0, 0, 64, 0, 0, 0,             // Type, DataSize,
+      44, 0, 0, 0,                          // RVA
+      // MemoryInfoListHeader
+      16, 0, 0, 0, 48, 0, 0, 0, // SizeOfHeader, SizeOfEntry
+      1, 0, 0, 0, 0, 0, 0, 0,   // NumberOfEntries
+      // MemoryInfo
+      0, 1, 2, 3, 4, 5, 6, 7,   // BaseAddress
+      8, 9, 0, 1, 2, 3, 4, 5,   // AllocationBase
+      16, 0, 0, 0, 6, 7, 8, 9,  // AllocationProtect, Reserved0
+      0, 1, 2, 3, 4, 5, 6, 7,   // RegionSize
+      0, 16, 0, 0, 32, 0, 0, 0, // State, Protect
+      0, 0, 2, 0, 8, 9, 0, 1,   // Type, Reserved1
+  };
+
+  // Same as before, but the list header is larger.
+  std::vector<uint8_t> BiggerHeader{
+      // 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
+      16, 0, 0, 0, 68, 0, 0, 0,             // Type, DataSize,
+      44, 0, 0, 0,                          // RVA
+      // MemoryInfoListHeader
+      20, 0, 0, 0, 48, 0, 0, 0, // SizeOfHeader, SizeOfEntry
+      1, 0, 0, 0, 0, 0, 0, 0,   // NumberOfEntries
+      0, 0, 0, 0,               // ???
+      // MemoryInfo
+      0, 1, 2, 3, 4, 5, 6, 7,   // BaseAddress
+      8, 9, 0, 1, 2, 3, 4, 5,   // AllocationBase
+      16, 0, 0, 0, 6, 7, 8, 9,  // AllocationProtect, Reserved0
+      0, 1, 2, 3, 4, 5, 6, 7,   // RegionSize
+      0, 16, 0, 0, 32, 0, 0, 0, // State, Protect
+      0, 0, 2, 0, 8, 9, 0, 1,   // Type, Reserved1
+  };
+
+  // Same as before, but the entry is larger.
+  std::vector<uint8_t> BiggerEntry{
+      // 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
+      16, 0, 0, 0, 68, 0, 0, 0,             // Type, DataSize,
+      44, 0, 0, 0,                          // RVA
+      // MemoryInfoListHeader
+      16, 0, 0, 0, 52, 0, 0, 0, // SizeOfHeader, SizeOfEntry
+      1, 0, 0, 0, 0, 0, 0, 0,   // NumberOfEntries
+      // MemoryInfo
+      0, 1, 2, 3, 4, 5, 6, 7,   // BaseAddress
+      8, 9, 0, 1, 2, 3, 4, 5,   // AllocationBase
+      16, 0, 0, 0, 6, 7, 8, 9,  // AllocationProtect, Reserved0
+      0, 1, 2, 3, 4, 5, 6, 7,   // RegionSize
+      0, 16, 0, 0, 32, 0, 0, 0, // State, Protect
+      0, 0, 2, 0, 8, 9, 0, 1,   // Type, Reserved1
+      0, 0, 0, 0,               // ???
+  };
+
+  for (ArrayRef<uint8_t> Data : {OneEntry, BiggerHeader, BiggerEntry}) {
+    auto ExpectedFile = create(Data);
+    ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
+    const MinidumpFile &File = **ExpectedFile;
+    auto ExpectedInfo = File.getMemoryInfoList();
+    ASSERT_THAT_EXPECTED(ExpectedInfo, Succeeded());
+    ASSERT_EQ(1u, std::distance(ExpectedInfo->begin(), ExpectedInfo->end()));
+    const MemoryInfo &Info = *ExpectedInfo.get().begin();
+    EXPECT_EQ(0x0706050403020100u, Info.BaseAddress);
+    EXPECT_EQ(0x0504030201000908u, Info.AllocationBase);
+    EXPECT_EQ(MemoryProtection::Execute, Info.AllocationProtect);
+    EXPECT_EQ(0x09080706u, Info.Reserved0);
+    EXPECT_EQ(0x0706050403020100u, Info.RegionSize);
+    EXPECT_EQ(MemoryState::Commit, Info.State);
+    EXPECT_EQ(MemoryProtection::ExecuteRead, Info.Protect);
+    EXPECT_EQ(MemoryType::Private, Info.Type);
+    EXPECT_EQ(0x01000908u, Info.Reserved1);
+  }
+
+  // Header does not fit into the stream.
+  std::vector<uint8_t> HeaderTooBig{
+      // 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
+      16, 0, 0, 0, 15, 0, 0, 0,             // Type, DataSize,
+      44, 0, 0, 0,                          // RVA
+      // MemoryInfoListHeader
+      16, 0, 0, 0, 48, 0, 0, 0, // SizeOfHeader, SizeOfEntry
+      1, 0, 0, 0, 0, 0, 0,      // ???
+  };
+  Expected<std::unique_ptr<MinidumpFile>> File = create(HeaderTooBig);
+  ASSERT_THAT_EXPECTED(File, Succeeded());
+  EXPECT_THAT_EXPECTED(File.get()->getMemoryInfoList(), Failed<BinaryError>());
+
+  // Header fits into the stream, but it is too small to contain the required
+  // entries.
+  std::vector<uint8_t> HeaderTooSmall{
+      // 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
+      16, 0, 0, 0, 15, 0, 0, 0,             // Type, DataSize,
+      44, 0, 0, 0,                          // RVA
+      // MemoryInfoListHeader
+      15, 0, 0, 0, 48, 0, 0, 0, // SizeOfHeader, SizeOfEntry
+      1, 0, 0, 0, 0, 0, 0,      // ???
+  };
+  File = create(HeaderTooSmall);
+  ASSERT_THAT_EXPECTED(File, Succeeded());
+  EXPECT_THAT_EXPECTED(File.get()->getMemoryInfoList(), Failed<BinaryError>());
+
+  std::vector<uint8_t> EntryTooBig{
+      // 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
+      16, 0, 0, 0, 64, 0, 0, 0,             // Type, DataSize,
+      44, 0, 0, 0,                          // RVA
+      // MemoryInfoListHeader
+      16, 0, 0, 0, 49, 0, 0, 0, // SizeOfHeader, SizeOfEntry
+      1, 0, 0, 0, 0, 0, 0, 0,   // NumberOfEntries
+      // MemoryInfo
+      0, 1, 2, 3, 4, 5, 6, 7,   // BaseAddress
+      8, 9, 0, 1, 2, 3, 4, 5,   // AllocationBase
+      16, 0, 0, 0, 6, 7, 8, 9,  // AllocationProtect, Reserved0
+      0, 1, 2, 3, 4, 5, 6, 7,   // RegionSize
+      0, 16, 0, 0, 32, 0, 0, 0, // State, Protect
+      0, 0, 2, 0, 8, 9, 0, 1,   // Type, Reserved1
+  };
+  File = create(EntryTooBig);
+  ASSERT_THAT_EXPECTED(File, Succeeded());
+  EXPECT_THAT_EXPECTED(File.get()->getMemoryInfoList(), Failed<BinaryError>());
+
+  std::vector<uint8_t> ThreeEntries{
+      // 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
+      16, 0, 0, 0, 160, 0, 0, 0,            // Type, DataSize,
+      44, 0, 0, 0,                          // RVA
+      // MemoryInfoListHeader
+      16, 0, 0, 0, 48, 0, 0, 0, // SizeOfHeader, SizeOfEntry
+      3, 0, 0, 0, 0, 0, 0, 0,   // NumberOfEntries
+      // MemoryInfo
+      0, 1, 2, 3, 0, 0, 0, 0, // BaseAddress
+      0, 0, 0, 0, 0, 0, 0, 0, // AllocationBase
+      0, 0, 0, 0, 0, 0, 0, 0, // AllocationProtect, Reserved0
+      0, 0, 0, 0, 0, 0, 0, 0, // RegionSize
+      0, 0, 0, 0, 0, 0, 0, 0, // State, Protect
+      0, 0, 0, 0, 0, 0, 0, 0, // Type, Reserved1
+      0, 0, 4, 5, 6, 7, 0, 0, // BaseAddress
+      0, 0, 0, 0, 0, 0, 0, 0, // AllocationBase
+      0, 0, 0, 0, 0, 0, 0, 0, // AllocationProtect, Reserved0
+      0, 0, 0, 0, 0, 0, 0, 0, // RegionSize
+      0, 0, 0, 0, 0, 0, 0, 0, // State, Protect
+      0, 0, 0, 0, 0, 0, 0, 0, // Type, Reserved1
+      0, 0, 0, 8, 9, 0, 1, 0, // BaseAddress
+      0, 0, 0, 0, 0, 0, 0, 0, // AllocationBase
+      0, 0, 0, 0, 0, 0, 0, 0, // AllocationProtect, Reserved0
+      0, 0, 0, 0, 0, 0, 0, 0, // RegionSize
+      0, 0, 0, 0, 0, 0, 0, 0, // State, Protect
+      0, 0, 0, 0, 0, 0, 0, 0, // Type, Reserved1
+  };
+  File = create(ThreeEntries);
+  ASSERT_THAT_EXPECTED(File, Succeeded());
+  auto ExpectedInfo = File.get()->getMemoryInfoList();
+  ASSERT_THAT_EXPECTED(ExpectedInfo, Succeeded());
+  EXPECT_THAT(to_vector<3>(map_range(*ExpectedInfo,
+                                     [](const MemoryInfo &Info) -> uint64_t {
+                                       return Info.BaseAddress;
+                                     })),
+              testing::ElementsAre(0x0000000003020100u, 0x0000070605040000u,
+                                   0x0001000908000000u));
+}




More information about the llvm-commits mailing list