labath created this revision.
labath added reviewers: amccarth, jhenderson, clayborg.
Herald added a project: LLVM.

the stream format is exactly the same as for ThreadList and ModuleList
streams, only the entry types are slightly different, so the changes in
this patch are just straight-forward applications of established
patterns.


Repository:
  rL LLVM

https://reviews.llvm.org/D61885

Files:
  include/llvm/Object/Minidump.h
  include/llvm/ObjectYAML/MinidumpYAML.h
  lib/Object/Minidump.cpp
  lib/ObjectYAML/MinidumpYAML.cpp
  test/tools/obj2yaml/basic-minidump.yaml
  unittests/Object/MinidumpTest.cpp

Index: unittests/Object/MinidumpTest.cpp
===================================================================
--- unittests/Object/MinidumpTest.cpp
+++ unittests/Object/MinidumpTest.cpp
@@ -463,3 +463,51 @@
     EXPECT_EQ(0x08070605u, T.Context.RVA);
   }
 }
+
+TEST(MinidumpFile, getMemoryList) {
+  std::vector<uint8_t> OneRange{
+      // 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
+      5, 0, 0, 0, 20, 0, 0, 0,              // Type, DataSize,
+      44, 0, 0, 0,                          // RVA
+      // MemoryDescriptor
+      1, 0, 0, 0,             // NumberOfMemoryRanges
+      5, 6, 7, 8, 9, 0, 1, 2, // StartOfMemoryRange
+      3, 4, 5, 6, 7, 8, 9, 0, // DataSize, RVA
+  };
+  // Same as before, but with a padded thread list.
+  std::vector<uint8_t> PaddedRange{
+      // 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
+      5, 0, 0, 0, 24, 0, 0, 0,              // Type, DataSize,
+      44, 0, 0, 0,                          // RVA
+      // MemoryDescriptor
+      1, 0, 0, 0,             // NumberOfMemoryRanges
+      0, 0, 0, 0,             // Padding
+      5, 6, 7, 8, 9, 0, 1, 2, // StartOfMemoryRange
+      3, 4, 5, 6, 7, 8, 9, 0, // DataSize, RVA
+  };
+
+  for (ArrayRef<uint8_t> Data : {OneRange, PaddedRange}) {
+    auto ExpectedFile = create(Data);
+    ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
+    const MinidumpFile &File = **ExpectedFile;
+    Expected<ArrayRef<MemoryDescriptor>> ExpectedRanges = File.getMemoryList();
+    ASSERT_THAT_EXPECTED(ExpectedRanges, Succeeded());
+    ASSERT_EQ(1u, ExpectedRanges->size());
+    const MemoryDescriptor &MD = ExpectedRanges.get()[0];
+    EXPECT_EQ(0x0201000908070605u, MD.StartOfMemoryRange);
+    EXPECT_EQ(0x06050403u, MD.Memory.DataSize);
+    EXPECT_EQ(0x00090807u, MD.Memory.RVA);
+  }
+}
Index: test/tools/obj2yaml/basic-minidump.yaml
===================================================================
--- test/tools/obj2yaml/basic-minidump.yaml
+++ test/tools/obj2yaml/basic-minidump.yaml
@@ -51,6 +51,10 @@
         Stack:
           Start of Memory Range: 0x6C6D6E6F70717273
           Content:         7475767778797A7B
+  - Type:            MemoryList
+    Memory Ranges:   
+      - Start of Memory Range: 0x7C7D7E7F80818283
+        Content:         '8485868788'
 ...
 
 # CHECK:      --- !minidump
@@ -104,4 +108,8 @@
 # CHECK-NEXT:         Stack:
 # CHECK-NEXT:           Start of Memory Range: 0x6C6D6E6F70717273
 # CHECK-NEXT:           Content:         7475767778797A7B
+# CHECK-NEXT:   - Type:            MemoryList
+# CHECK-NEXT:     Memory Ranges:   
+# CHECK-NEXT:       - Start of Memory Range: 0x7C7D7E7F80818283
+# CHECK-NEXT:         Content:         '8485868788'
 # CHECK-NEXT: ...
Index: lib/ObjectYAML/MinidumpYAML.cpp
===================================================================
--- lib/ObjectYAML/MinidumpYAML.cpp
+++ lib/ObjectYAML/MinidumpYAML.cpp
@@ -168,6 +168,8 @@
 
 Stream::StreamKind Stream::getKind(StreamType Type) {
   switch (Type) {
+  case StreamType::MemoryList:
+    return StreamKind::MemoryList;
   case StreamType::ModuleList:
     return StreamKind::ModuleList;
   case StreamType::SystemInfo:
@@ -190,6 +192,8 @@
 std::unique_ptr<Stream> Stream::create(StreamType Type) {
   StreamKind Kind = getKind(Type);
   switch (Kind) {
+  case StreamKind::MemoryList:
+    return llvm::make_unique<MemoryListStream>();
   case StreamKind::ModuleList:
     return llvm::make_unique<ModuleListStream>();
   case StreamKind::RawContent:
@@ -353,6 +357,16 @@
   return "";
 }
 
+void yaml::MappingTraits<MemoryListStream::entry_type>::mapping(
+    IO &IO, MemoryListStream::entry_type &Range) {
+  MappingContextTraits<MemoryDescriptor, yaml::BinaryRef>::mapping(
+      IO, Range.Entry, Range.Content);
+}
+
+static void streamMapping(yaml::IO &IO, MemoryListStream &Stream) {
+  IO.mapRequired("Memory Ranges", Stream.Entries);
+}
+
 static void streamMapping(yaml::IO &IO, ModuleListStream &Stream) {
   IO.mapRequired("Modules", Stream.Entries);
 }
@@ -421,6 +435,9 @@
   if (!IO.outputting())
     S = MinidumpYAML::Stream::create(Type);
   switch (S->Kind) {
+  case MinidumpYAML::Stream::StreamKind::MemoryList:
+    streamMapping(IO, llvm::cast<MemoryListStream>(*S));
+    break;
   case MinidumpYAML::Stream::StreamKind::ModuleList:
     streamMapping(IO, llvm::cast<ModuleListStream>(*S));
     break;
@@ -444,6 +461,7 @@
   switch (S->Kind) {
   case MinidumpYAML::Stream::StreamKind::RawContent:
     return streamValidate(cast<RawContentStream>(*S));
+  case MinidumpYAML::Stream::StreamKind::MemoryList:
   case MinidumpYAML::Stream::StreamKind::ModuleList:
   case MinidumpYAML::Stream::StreamKind::SystemInfo:
   case MinidumpYAML::Stream::StreamKind::TextContent:
@@ -466,6 +484,10 @@
           support::ulittle32_t(File.allocateBytes(Data))};
 }
 
+static void layout(BlobAllocator &File, MemoryListStream::entry_type &Range) {
+  Range.Entry.Memory = layout(File, Range.Content);
+}
+
 static void layout(BlobAllocator &File, ModuleListStream::entry_type &M) {
   M.Entry.ModuleNameRVA = File.allocateString(M.Name);
 
@@ -502,6 +524,9 @@
   Result.Location.RVA = File.tell();
   Optional<size_t> DataEnd;
   switch (S.Kind) {
+  case Stream::StreamKind::MemoryList:
+    DataEnd = layout(File, cast<MemoryListStream>(S));
+    break;
   case Stream::StreamKind::ModuleList:
     DataEnd = layout(File, cast<ModuleListStream>(S));
     break;
@@ -566,6 +591,19 @@
 Stream::create(const Directory &StreamDesc, const object::MinidumpFile &File) {
   StreamKind Kind = getKind(StreamDesc.Type);
   switch (Kind) {
+  case StreamKind::MemoryList: {
+    auto ExpectedList = File.getMemoryList();
+    if (!ExpectedList)
+      return ExpectedList.takeError();
+    std::vector<MemoryListStream::entry_type> Ranges;
+    for (const MemoryDescriptor &MD : *ExpectedList) {
+      auto ExpectedContent = File.getRawData(MD.Memory);
+      if (!ExpectedContent)
+        return ExpectedContent.takeError();
+      Ranges.push_back({MD, *ExpectedContent});
+    }
+    return llvm::make_unique<MemoryListStream>(std::move(Ranges));
+  }
   case StreamKind::ModuleList: {
     auto ExpectedList = File.getModuleList();
     if (!ExpectedList)
Index: lib/Object/Minidump.cpp
===================================================================
--- lib/Object/Minidump.cpp
+++ lib/Object/Minidump.cpp
@@ -78,6 +78,8 @@
     MinidumpFile::getListStream(StreamType) const;
 template Expected<ArrayRef<Thread>>
     MinidumpFile::getListStream(StreamType) const;
+template Expected<ArrayRef<MemoryDescriptor>>
+    MinidumpFile::getListStream(StreamType) const;
 
 Expected<ArrayRef<uint8_t>>
 MinidumpFile::getDataSlice(ArrayRef<uint8_t> Data, size_t Offset, size_t Size) {
Index: include/llvm/ObjectYAML/MinidumpYAML.h
===================================================================
--- include/llvm/ObjectYAML/MinidumpYAML.h
+++ include/llvm/ObjectYAML/MinidumpYAML.h
@@ -26,6 +26,7 @@
 /// from Types to Kinds is fixed and given by the static getKind function.
 struct Stream {
   enum class StreamKind {
+    MemoryList,
     ModuleList,
     RawContent,
     SystemInfo,
@@ -86,10 +87,20 @@
   yaml::BinaryRef Stack;
   yaml::BinaryRef Context;
 };
+
+/// A structure containing all data describing a single memory region.
+struct ParsedMemoryRange {
+  static constexpr Stream::StreamKind Kind = Stream::StreamKind::MemoryList;
+  static constexpr minidump::StreamType Type = minidump::StreamType::MemoryList;
+
+  minidump::MemoryDescriptor Entry;
+  yaml::BinaryRef Content;
+};
 } // namespace detail
 
 using ModuleListStream = detail::ListStream<detail::ParsedModule>;
 using ThreadListStream = detail::ListStream<detail::ParsedThread>;
+using MemoryListStream = detail::ListStream<detail::ParsedMemoryRange>;
 
 /// A minidump stream represented as a sequence of hex bytes. This is used as a
 /// fallback when no other stream kind is suitable.
@@ -211,12 +222,15 @@
 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::CPUInfo::X86Info)
 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::VSFixedFileInfo)
 
+LLVM_YAML_DECLARE_MAPPING_TRAITS(
+    llvm::MinidumpYAML::MemoryListStream::entry_type)
 LLVM_YAML_DECLARE_MAPPING_TRAITS(
     llvm::MinidumpYAML::ModuleListStream::entry_type)
 LLVM_YAML_DECLARE_MAPPING_TRAITS(
     llvm::MinidumpYAML::ThreadListStream::entry_type)
 
 LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<llvm::MinidumpYAML::Stream>)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MinidumpYAML::MemoryListStream::entry_type)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MinidumpYAML::ModuleListStream::entry_type)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MinidumpYAML::ThreadListStream::entry_type)
 
Index: include/llvm/Object/Minidump.h
===================================================================
--- include/llvm/Object/Minidump.h
+++ include/llvm/Object/Minidump.h
@@ -80,6 +80,16 @@
     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 threads declared in
+  /// the stream header. The consistency of the Thread entries themselves is not
+  /// checked in any way.
+  Expected<ArrayRef<minidump::MemoryDescriptor>> getMemoryList() const {
+    return getListStream<minidump::MemoryDescriptor>(
+        minidump::StreamType::MemoryList);
+  }
+
 private:
   static Error createError(StringRef Str) {
     return make_error<GenericBinaryError>(Str, object_error::parse_failed);
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to