[Lldb-commits] [lldb] [llvm] [Obj2Yaml] Add support for minidump generation with 64b memory ranges. (PR #101272)

Jacob Lalonde via lldb-commits lldb-commits at lists.llvm.org
Tue Jul 30 18:05:13 PDT 2024


https://github.com/Jlalond created https://github.com/llvm/llvm-project/pull/101272

This PR adds support for `obj2yaml` and `yaml2obj` to generate minidumps that have a Memory64List stream. This is a prerequisite to #101086.

Worth noting
- const dropped on minidumps so we could cache a MemoryDescriptor_64 to it's actual offset, preventing the need to loop multiple times
- doesn't reuse the existing `ListStream` code in some places, because the Memory64List has a different width size field (unsigned 64), and a larger header than all the other streams. I determined refactoring the existing code to support Mem64 would be worse than supporting the special case.

>From 78ab13e3da15832117a7e2f8f85090a63482ca41 Mon Sep 17 00:00:00 2001
From: Jacob Lalonde <jalalonde at fb.com>
Date: Tue, 30 Jul 2024 11:04:45 -0700
Subject: [PATCH 1/2] Squash 64b-memory-regions-minidump and take only
 llvm-changes

---
 llvm/include/llvm/BinaryFormat/Minidump.h   | 12 ++++++++
 llvm/include/llvm/Object/Minidump.h         | 16 ++++++++--
 llvm/include/llvm/ObjectYAML/MinidumpYAML.h | 28 +++++++++++++++++
 llvm/lib/Object/Minidump.cpp                | 19 ++++++++++--
 llvm/lib/ObjectYAML/MinidumpEmitter.cpp     | 11 +++++++
 llvm/lib/ObjectYAML/MinidumpYAML.cpp        | 34 +++++++++++++++++++++
 6 files changed, 115 insertions(+), 5 deletions(-)

diff --git a/llvm/include/llvm/BinaryFormat/Minidump.h b/llvm/include/llvm/BinaryFormat/Minidump.h
index 9669303252615..8054e81322a92 100644
--- a/llvm/include/llvm/BinaryFormat/Minidump.h
+++ b/llvm/include/llvm/BinaryFormat/Minidump.h
@@ -74,6 +74,18 @@ struct MemoryDescriptor_64 {
   support::ulittle64_t StartOfMemoryRange;
   support::ulittle64_t DataSize;
 };
+static_assert(sizeof(MemoryDescriptor_64) == 16);
+
+struct MemoryListHeader {
+  support::ulittle32_t NumberOfMemoryRanges;
+};
+static_assert(sizeof(MemoryListHeader) == 4);
+
+struct Memory64ListHeader {
+  support::ulittle64_t NumberOfMemoryRanges;
+  support::ulittle64_t BaseRVA;
+};
+static_assert(sizeof(Memory64ListHeader) == 16);
 
 struct MemoryInfoListHeader {
   support::ulittle32_t SizeOfHeader;
diff --git a/llvm/include/llvm/Object/Minidump.h b/llvm/include/llvm/Object/Minidump.h
index e45d4de0090de..6ca9eb2afe150 100644
--- a/llvm/include/llvm/Object/Minidump.h
+++ b/llvm/include/llvm/Object/Minidump.h
@@ -103,6 +103,15 @@ class MinidumpFile : public Binary {
         minidump::StreamType::MemoryList);
   }
 
+  /// Returns the header to the memory 64 list stream. An error is returned if
+  /// the file does not contain this stream.
+  Expected<minidump::Memory64ListHeader> getMemoryList64Header() const {
+    return getStream<minidump::Memory64ListHeader>(
+        minidump::StreamType::Memory64List);
+  }
+
+  Expected<ArrayRef<minidump::MemoryDescriptor_64>> getMemory64List() const;
+
   class MemoryInfoIterator
       : public iterator_facade_base<MemoryInfoIterator,
                                     std::forward_iterator_tag,
@@ -152,15 +161,15 @@ class MinidumpFile : public Binary {
   }
 
   /// Return a slice of the given data array, with bounds checking.
-  static Expected<ArrayRef<uint8_t>> getDataSlice(ArrayRef<uint8_t> Data,
-                                                  size_t Offset, size_t Size);
+  static Expected<ArrayRef<uint8_t>>
+  getDataSlice(ArrayRef<uint8_t> Data, uint64_t Offset, uint64_t Size);
 
   /// Return the slice of the given data array as an array of objects of the
   /// given type. The function checks that the input array is large enough to
   /// contain the correct number of objects of the given type.
   template <typename T>
   static Expected<ArrayRef<T>> getDataSliceAs(ArrayRef<uint8_t> Data,
-                                              size_t Offset, size_t Count);
+                                              uint64_t Offset, uint64_t Count);
 
   MinidumpFile(MemoryBufferRef Source, const minidump::Header &Header,
                ArrayRef<minidump::Directory> Streams,
@@ -208,6 +217,7 @@ Expected<ArrayRef<T>> MinidumpFile::getDataSliceAs(ArrayRef<uint8_t> Data,
       getDataSlice(Data, Offset, sizeof(T) * Count);
   if (!Slice)
     return Slice.takeError();
+
   return ArrayRef<T>(reinterpret_cast<const T *>(Slice->data()), Count);
 }
 
diff --git a/llvm/include/llvm/ObjectYAML/MinidumpYAML.h b/llvm/include/llvm/ObjectYAML/MinidumpYAML.h
index b0cee541cef20..2cccf7fba5853 100644
--- a/llvm/include/llvm/ObjectYAML/MinidumpYAML.h
+++ b/llvm/include/llvm/ObjectYAML/MinidumpYAML.h
@@ -29,6 +29,7 @@ struct Stream {
     Exception,
     MemoryInfoList,
     MemoryList,
+    Memory64List,
     ModuleList,
     RawContent,
     SystemInfo,
@@ -104,6 +105,25 @@ using ModuleListStream = detail::ListStream<detail::ParsedModule>;
 using ThreadListStream = detail::ListStream<detail::ParsedThread>;
 using MemoryListStream = detail::ListStream<detail::ParsedMemoryDescriptor>;
 
+/// Memory64ListStream minidump stream.
+struct Memory64ListStream : public Stream {
+  minidump::Memory64ListHeader Header;
+  std::vector<minidump::MemoryDescriptor_64> Entries;
+  yaml::BinaryRef Content;
+
+  Memory64ListStream()
+      : Stream(StreamKind::Memory64List, minidump::StreamType::Memory64List) {}
+
+  explicit Memory64ListStream(
+      std::vector<minidump::MemoryDescriptor_64> Entries)
+      : Stream(StreamKind::Memory64List, minidump::StreamType::Memory64List),
+        Entries(Entries) {}
+
+  static bool classof(const Stream *S) {
+    return S->Kind == StreamKind::Memory64List;
+  }
+};
+
 /// ExceptionStream minidump stream.
 struct ExceptionStream : public Stream {
   minidump::ExceptionStream MDExceptionStream;
@@ -244,6 +264,12 @@ template <> struct MappingContextTraits<minidump::MemoryDescriptor, BinaryRef> {
                       BinaryRef &Content);
 };
 
+template <>
+struct MappingContextTraits<minidump::MemoryDescriptor_64, BinaryRef> {
+  static void mapping(IO &IO, minidump::MemoryDescriptor_64 &Memory,
+                      BinaryRef &Content);
+};
+
 } // namespace yaml
 
 } // namespace llvm
@@ -262,6 +288,7 @@ LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::CPUInfo::X86Info)
 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::Exception)
 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::MemoryInfo)
 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::VSFixedFileInfo)
+LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::MemoryDescriptor_64)
 
 LLVM_YAML_DECLARE_MAPPING_TRAITS(
     llvm::MinidumpYAML::MemoryListStream::entry_type)
@@ -275,6 +302,7 @@ 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)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::minidump::MemoryInfo)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::minidump::MemoryDescriptor_64)
 
 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::MinidumpYAML::Object)
 
diff --git a/llvm/lib/Object/Minidump.cpp b/llvm/lib/Object/Minidump.cpp
index 6febff89ac519..92aa4f66a4b35 100644
--- a/llvm/lib/Object/Minidump.cpp
+++ b/llvm/lib/Object/Minidump.cpp
@@ -99,8 +99,9 @@ template Expected<ArrayRef<Thread>>
 template Expected<ArrayRef<MemoryDescriptor>>
     MinidumpFile::getListStream(StreamType) const;
 
-Expected<ArrayRef<uint8_t>>
-MinidumpFile::getDataSlice(ArrayRef<uint8_t> Data, size_t Offset, size_t Size) {
+Expected<ArrayRef<uint8_t>> MinidumpFile::getDataSlice(ArrayRef<uint8_t> Data,
+                                                       uint64_t Offset,
+                                                       uint64_t Size) {
   // Check for overflow.
   if (Offset + Size < Offset || Offset + Size < Size ||
       Offset + Size > Data.size())
@@ -154,3 +155,17 @@ MinidumpFile::create(MemoryBufferRef Source) {
   return std::unique_ptr<MinidumpFile>(
       new MinidumpFile(Source, Hdr, *ExpectedStreams, std::move(StreamMap)));
 }
+
+Expected<ArrayRef<MemoryDescriptor_64>> MinidumpFile::getMemory64List() const {
+  Expected<minidump::Memory64ListHeader> MemoryList64 = getMemoryList64Header();
+  if (!MemoryList64)
+    return MemoryList64.takeError();
+
+  std::optional<ArrayRef<uint8_t>> Stream =
+      getRawStream(StreamType::Memory64List);
+  if (!Stream)
+    return createError("No such stream");
+
+  return getDataSliceAs<minidump::MemoryDescriptor_64>(
+      *Stream, sizeof(Memory64ListHeader), MemoryList64->NumberOfMemoryRanges);
+}
diff --git a/llvm/lib/ObjectYAML/MinidumpEmitter.cpp b/llvm/lib/ObjectYAML/MinidumpEmitter.cpp
index 24b521a9925c7..f992c4e3bde76 100644
--- a/llvm/lib/ObjectYAML/MinidumpEmitter.cpp
+++ b/llvm/lib/ObjectYAML/MinidumpEmitter.cpp
@@ -136,6 +136,14 @@ static size_t layout(BlobAllocator &File, MinidumpYAML::ExceptionStream &S) {
   return DataEnd;
 }
 
+static void layout(BlobAllocator &File, MinidumpYAML::Memory64ListStream &S) {
+  size_t BaseRVA = File.tell() + sizeof(minidump::Memory64ListHeader);
+  S.Header.BaseRVA = BaseRVA;
+  S.Header.NumberOfMemoryRanges = S.Entries.size();
+  File.allocateObject(S.Header);
+  File.allocateArray(ArrayRef(S.Entries));
+}
+
 static void layout(BlobAllocator &File, MemoryListStream::entry_type &Range) {
   Range.Entry.Memory = layout(File, Range.Content);
 }
@@ -190,6 +198,9 @@ static Directory layout(BlobAllocator &File, Stream &S) {
   case Stream::StreamKind::MemoryList:
     DataEnd = layout(File, cast<MemoryListStream>(S));
     break;
+  case Stream::StreamKind::Memory64List:
+    layout(File, cast<Memory64ListStream>(S));
+    break;
   case Stream::StreamKind::ModuleList:
     DataEnd = layout(File, cast<ModuleListStream>(S));
     break;
diff --git a/llvm/lib/ObjectYAML/MinidumpYAML.cpp b/llvm/lib/ObjectYAML/MinidumpYAML.cpp
index fdbd2d8e6dcbc..aee17c520a010 100644
--- a/llvm/lib/ObjectYAML/MinidumpYAML.cpp
+++ b/llvm/lib/ObjectYAML/MinidumpYAML.cpp
@@ -75,6 +75,8 @@ Stream::StreamKind Stream::getKind(StreamType Type) {
     return StreamKind::MemoryInfoList;
   case StreamType::MemoryList:
     return StreamKind::MemoryList;
+  case StreamType::Memory64List:
+    return StreamKind::Memory64List;
   case StreamType::ModuleList:
     return StreamKind::ModuleList;
   case StreamType::SystemInfo:
@@ -103,6 +105,8 @@ std::unique_ptr<Stream> Stream::create(StreamType Type) {
     return std::make_unique<MemoryInfoListStream>();
   case StreamKind::MemoryList:
     return std::make_unique<MemoryListStream>();
+  case StreamKind::Memory64List:
+    return std::make_unique<Memory64ListStream>();
   case StreamKind::ModuleList:
     return std::make_unique<ModuleListStream>();
   case StreamKind::RawContent:
@@ -256,6 +260,12 @@ void yaml::MappingTraits<MemoryInfo>::mapping(IO &IO, MemoryInfo &Info) {
   mapOptionalHex(IO, "Reserved1", Info.Reserved1, 0);
 }
 
+void yaml::MappingTraits<MemoryDescriptor_64>::mapping(
+    IO &IO, MemoryDescriptor_64 &Mem) {
+  mapRequiredHex(IO, "Start of memory range", Mem.StartOfMemoryRange);
+  mapRequiredHex(IO, "Data Size", Mem.DataSize);
+}
+
 void yaml::MappingTraits<VSFixedFileInfo>::mapping(IO &IO,
                                                    VSFixedFileInfo &Info) {
   mapOptionalHex(IO, "Signature", Info.Signature, 0);
@@ -312,6 +322,10 @@ static void streamMapping(yaml::IO &IO, MemoryListStream &Stream) {
   IO.mapRequired("Memory Ranges", Stream.Entries);
 }
 
+static void streamMapping(yaml::IO &IO, Memory64ListStream &Stream) {
+  IO.mapRequired("Memory Ranges", Stream.Entries);
+}
+
 static void streamMapping(yaml::IO &IO, ModuleListStream &Stream) {
   IO.mapRequired("Modules", Stream.Entries);
 }
@@ -356,6 +370,12 @@ void yaml::MappingContextTraits<MemoryDescriptor, yaml::BinaryRef>::mapping(
   IO.mapRequired("Content", Content);
 }
 
+void yaml::MappingContextTraits<MemoryDescriptor_64, yaml::BinaryRef>::mapping(
+    IO &IO, MemoryDescriptor_64 &Memory, BinaryRef &Content) {
+  mapRequiredHex(IO, "Start of Memory Range", Memory.StartOfMemoryRange);
+  IO.mapRequired("Content", Content);
+}
+
 void yaml::MappingTraits<ThreadListStream::entry_type>::mapping(
     IO &IO, ThreadListStream::entry_type &T) {
   mapRequiredHex(IO, "Thread Id", T.Entry.ThreadId);
@@ -416,6 +436,9 @@ void yaml::MappingTraits<std::unique_ptr<Stream>>::mapping(
   case MinidumpYAML::Stream::StreamKind::MemoryList:
     streamMapping(IO, llvm::cast<MemoryListStream>(*S));
     break;
+  case MinidumpYAML::Stream::StreamKind::Memory64List:
+    streamMapping(IO, llvm::cast<Memory64ListStream>(*S));
+    break;
   case MinidumpYAML::Stream::StreamKind::ModuleList:
     streamMapping(IO, llvm::cast<ModuleListStream>(*S));
     break;
@@ -442,6 +465,7 @@ std::string yaml::MappingTraits<std::unique_ptr<Stream>>::validate(
   case MinidumpYAML::Stream::StreamKind::Exception:
   case MinidumpYAML::Stream::StreamKind::MemoryInfoList:
   case MinidumpYAML::Stream::StreamKind::MemoryList:
+  case MinidumpYAML::Stream::StreamKind::Memory64List:
   case MinidumpYAML::Stream::StreamKind::ModuleList:
   case MinidumpYAML::Stream::StreamKind::SystemInfo:
   case MinidumpYAML::Stream::StreamKind::TextContent:
@@ -494,6 +518,16 @@ Stream::create(const Directory &StreamDesc, const object::MinidumpFile &File) {
     }
     return std::make_unique<MemoryListStream>(std::move(Ranges));
   }
+  case StreamKind::Memory64List: {
+    auto ExpectedList = File.getMemory64List();
+    if (!ExpectedList)
+      return ExpectedList.takeError();
+    std::vector<MemoryDescriptor_64> Ranges;
+    for (const MemoryDescriptor_64 &MD : *ExpectedList) {
+      Ranges.push_back(MD);
+    }
+    return std::make_unique<Memory64ListStream>(std::move(Ranges));
+  }
   case StreamKind::ModuleList: {
     auto ExpectedList = File.getModuleList();
     if (!ExpectedList)

>From 9be9a32f57c5bd516eb5e64282ed71292a78c27a Mon Sep 17 00:00:00 2001
From: Jacob Lalonde <jalalonde at fb.com>
Date: Tue, 30 Jul 2024 17:57:43 -0700
Subject: [PATCH 2/2] Make some further changes to enable content, remove const
 modifier so we can cache the memory descriptors instead of doing N^2 lookups.
 Run Formatters and cleanup debugging code.

---
 .../Shell/Minidump/Inputs/linux-x86_64.yaml   |  6 +--
 llvm/include/llvm/Object/Minidump.h           | 10 +++-
 llvm/include/llvm/ObjectYAML/MinidumpYAML.h   | 37 +++++++-------
 llvm/lib/Object/Minidump.cpp                  | 42 +++++++++++++---
 llvm/lib/ObjectYAML/MinidumpEmitter.cpp       | 14 ++++--
 llvm/lib/ObjectYAML/MinidumpYAML.cpp          | 22 +++++----
 llvm/test/tools/obj2yaml/Minidump/basic.yaml  | 12 ++++-
 llvm/tools/obj2yaml/minidump2yaml.cpp         |  2 +-
 llvm/tools/obj2yaml/obj2yaml.h                |  2 +-
 .../unittests/ObjectYAML/MinidumpYAMLTest.cpp | 48 +++++++++++++++++++
 10 files changed, 150 insertions(+), 45 deletions(-)

diff --git a/lldb/test/Shell/Minidump/Inputs/linux-x86_64.yaml b/lldb/test/Shell/Minidump/Inputs/linux-x86_64.yaml
index d2ae6543141e8..157903f368a08 100644
--- a/lldb/test/Shell/Minidump/Inputs/linux-x86_64.yaml
+++ b/lldb/test/Shell/Minidump/Inputs/linux-x86_64.yaml
@@ -1,7 +1,7 @@
 --- !minidump
-Streams:         
+Streams:
   - Type:            ModuleList
-    Modules:         
+    Modules:
       - Base of Image:   0x0000000000400000
         Size of Image:   0x00001000
         Module Name:     '/tmp/test/linux-x86_64'
@@ -13,7 +13,7 @@ Streams:
     Number of Processors: 40
     Platform ID:     Linux
     CSD Version:     'Linux 3.13.0-91-generic #138-Ubuntu SMP Fri Jun 24 17:00:34 UTC 2016 x86_64'
-    CPU:             
+    CPU:
       Vendor ID:       GenuineIntel
       Version Info:    0x00000000
       Feature Info:    0x00000000
diff --git a/llvm/include/llvm/Object/Minidump.h b/llvm/include/llvm/Object/Minidump.h
index 6ca9eb2afe150..eedebc10b3fe7 100644
--- a/llvm/include/llvm/Object/Minidump.h
+++ b/llvm/include/llvm/Object/Minidump.h
@@ -15,6 +15,7 @@
 #include "llvm/BinaryFormat/Minidump.h"
 #include "llvm/Object/Binary.h"
 #include "llvm/Support/Error.h"
+#include <map>
 
 namespace llvm {
 namespace object {
@@ -52,6 +53,9 @@ class MinidumpFile : public Binary {
     return getDataSlice(getData(), Desc.RVA, Desc.DataSize);
   }
 
+  Expected<ArrayRef<uint8_t>>
+  getRawData(minidump::MemoryDescriptor_64 Desc) const;
+
   /// Returns the minidump string at the given offset. An error is returned if
   /// we fail to parse the string, or the string is invalid UTF16.
   Expected<std::string> getString(size_t Offset) const;
@@ -110,7 +114,7 @@ class MinidumpFile : public Binary {
         minidump::StreamType::Memory64List);
   }
 
-  Expected<ArrayRef<minidump::MemoryDescriptor_64>> getMemory64List() const;
+  Expected<ArrayRef<minidump::MemoryDescriptor_64>> getMemory64List();
 
   class MemoryInfoIterator
       : public iterator_facade_base<MemoryInfoIterator,
@@ -191,9 +195,13 @@ class MinidumpFile : public Binary {
   template <typename T>
   Expected<ArrayRef<T>> getListStream(minidump::StreamType Stream) const;
 
+  void cacheMemory64RVAs(uint64_t BaseRVA,
+                         ArrayRef<minidump::MemoryDescriptor_64> Descriptors);
+
   const minidump::Header &Header;
   ArrayRef<minidump::Directory> Streams;
   DenseMap<minidump::StreamType, std::size_t> StreamMap;
+  std::unordered_map<uint64_t, uint64_t> Memory64DescriptorToRvaMap;
 };
 
 template <typename T>
diff --git a/llvm/include/llvm/ObjectYAML/MinidumpYAML.h b/llvm/include/llvm/ObjectYAML/MinidumpYAML.h
index 2cccf7fba5853..7f7924b92029f 100644
--- a/llvm/include/llvm/ObjectYAML/MinidumpYAML.h
+++ b/llvm/include/llvm/ObjectYAML/MinidumpYAML.h
@@ -51,8 +51,7 @@ struct Stream {
 
   /// Create a stream from the given stream directory entry.
   static Expected<std::unique_ptr<Stream>>
-  create(const minidump::Directory &StreamDesc,
-         const object::MinidumpFile &File);
+  create(const minidump::Directory &StreamDesc, object::MinidumpFile &File);
 };
 
 namespace detail {
@@ -99,29 +98,28 @@ struct ParsedMemoryDescriptor {
   minidump::MemoryDescriptor Entry;
   yaml::BinaryRef Content;
 };
+
+struct ParsedMemory64Descriptor {
+  static constexpr Stream::StreamKind Kind = Stream::StreamKind::Memory64List;
+  static constexpr minidump::StreamType Type =
+      minidump::StreamType::Memory64List;
+
+  minidump::MemoryDescriptor_64 Entry;
+  yaml::BinaryRef Content;
+};
 } // namespace detail
 
 using ModuleListStream = detail::ListStream<detail::ParsedModule>;
 using ThreadListStream = detail::ListStream<detail::ParsedThread>;
 using MemoryListStream = detail::ListStream<detail::ParsedMemoryDescriptor>;
 
-/// Memory64ListStream minidump stream.
-struct Memory64ListStream : public Stream {
+struct Memory64ListStream
+    : public detail::ListStream<detail::ParsedMemory64Descriptor> {
   minidump::Memory64ListHeader Header;
-  std::vector<minidump::MemoryDescriptor_64> Entries;
-  yaml::BinaryRef Content;
-
-  Memory64ListStream()
-      : Stream(StreamKind::Memory64List, minidump::StreamType::Memory64List) {}
 
   explicit Memory64ListStream(
-      std::vector<minidump::MemoryDescriptor_64> Entries)
-      : Stream(StreamKind::Memory64List, minidump::StreamType::Memory64List),
-        Entries(Entries) {}
-
-  static bool classof(const Stream *S) {
-    return S->Kind == StreamKind::Memory64List;
-  }
+      std::vector<detail::ParsedMemory64Descriptor> Entries = {})
+      : ListStream(Entries){};
 };
 
 /// ExceptionStream minidump stream.
@@ -235,7 +233,7 @@ struct Object {
   /// The list of streams in this minidump object.
   std::vector<std::unique_ptr<Stream>> Streams;
 
-  static Expected<Object> create(const object::MinidumpFile &File);
+  static Expected<Object> create(object::MinidumpFile &File);
 };
 
 } // namespace MinidumpYAML
@@ -288,7 +286,6 @@ LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::CPUInfo::X86Info)
 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::Exception)
 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::MemoryInfo)
 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::VSFixedFileInfo)
-LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::MemoryDescriptor_64)
 
 LLVM_YAML_DECLARE_MAPPING_TRAITS(
     llvm::MinidumpYAML::MemoryListStream::entry_type)
@@ -296,13 +293,15 @@ LLVM_YAML_DECLARE_MAPPING_TRAITS(
     llvm::MinidumpYAML::ModuleListStream::entry_type)
 LLVM_YAML_DECLARE_MAPPING_TRAITS(
     llvm::MinidumpYAML::ThreadListStream::entry_type)
+LLVM_YAML_DECLARE_MAPPING_TRAITS(
+    llvm::MinidumpYAML::Memory64ListStream::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)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MinidumpYAML::Memory64ListStream::entry_type)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::minidump::MemoryInfo)
-LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::minidump::MemoryDescriptor_64)
 
 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::MinidumpYAML::Object)
 
diff --git a/llvm/lib/Object/Minidump.cpp b/llvm/lib/Object/Minidump.cpp
index 92aa4f66a4b35..06bcbe9be195f 100644
--- a/llvm/lib/Object/Minidump.cpp
+++ b/llvm/lib/Object/Minidump.cpp
@@ -156,16 +156,46 @@ MinidumpFile::create(MemoryBufferRef Source) {
       new MinidumpFile(Source, Hdr, *ExpectedStreams, std::move(StreamMap)));
 }
 
-Expected<ArrayRef<MemoryDescriptor_64>> MinidumpFile::getMemory64List() const {
-  Expected<minidump::Memory64ListHeader> MemoryList64 = getMemoryList64Header();
-  if (!MemoryList64)
-    return MemoryList64.takeError();
+void MinidumpFile::cacheMemory64RVAs(
+    uint64_t BaseRVA, ArrayRef<minidump::MemoryDescriptor_64> Descriptors) {
+  // Check if we've already cached the RVAs for this list.
+  if (!Memory64DescriptorToRvaMap.empty())
+    return;
+
+  for (const auto &MD : Descriptors) {
+    Memory64DescriptorToRvaMap[MD.StartOfMemoryRange] = BaseRVA;
+    BaseRVA += MD.DataSize;
+  }
+}
+
+Expected<ArrayRef<MemoryDescriptor_64>> MinidumpFile::getMemory64List() {
+  Expected<minidump::Memory64ListHeader> ListHeader = getMemoryList64Header();
+  if (!ListHeader)
+    return ListHeader.takeError();
 
   std::optional<ArrayRef<uint8_t>> Stream =
       getRawStream(StreamType::Memory64List);
   if (!Stream)
     return createError("No such stream");
 
-  return getDataSliceAs<minidump::MemoryDescriptor_64>(
-      *Stream, sizeof(Memory64ListHeader), MemoryList64->NumberOfMemoryRanges);
+  Expected<ArrayRef<minidump::MemoryDescriptor_64>> Descriptors =
+      getDataSliceAs<minidump::MemoryDescriptor_64>(
+          *Stream, sizeof(Memory64ListHeader),
+          ListHeader->NumberOfMemoryRanges);
+
+  if (!Descriptors)
+    return Descriptors.takeError();
+
+  cacheMemory64RVAs(ListHeader->NumberOfMemoryRanges, *Descriptors);
+  return Descriptors;
+}
+
+Expected<ArrayRef<uint8_t>>
+MinidumpFile::getRawData(MemoryDescriptor_64 MD) const {
+  if (Memory64DescriptorToRvaMap.count(MD.StartOfMemoryRange) > 0) {
+    uint64_t RVA = Memory64DescriptorToRvaMap.at(MD.StartOfMemoryRange);
+    return getDataSlice(getData(), RVA, MD.DataSize);
+  }
+
+  return createError("No such Memory Descriptor64.");
 }
diff --git a/llvm/lib/ObjectYAML/MinidumpEmitter.cpp b/llvm/lib/ObjectYAML/MinidumpEmitter.cpp
index f992c4e3bde76..d2f6bcdc20838 100644
--- a/llvm/lib/ObjectYAML/MinidumpEmitter.cpp
+++ b/llvm/lib/ObjectYAML/MinidumpEmitter.cpp
@@ -136,12 +136,20 @@ static size_t layout(BlobAllocator &File, MinidumpYAML::ExceptionStream &S) {
   return DataEnd;
 }
 
-static void layout(BlobAllocator &File, MinidumpYAML::Memory64ListStream &S) {
+static size_t layout(BlobAllocator &File, MinidumpYAML::Memory64ListStream &S) {
   size_t BaseRVA = File.tell() + sizeof(minidump::Memory64ListHeader);
   S.Header.BaseRVA = BaseRVA;
   S.Header.NumberOfMemoryRanges = S.Entries.size();
   File.allocateObject(S.Header);
-  File.allocateArray(ArrayRef(S.Entries));
+  for (auto &E : S.Entries)
+    File.allocateObject(E.Entry);
+
+  // Save the new offset for the stream size.
+  size_t DataEnd = File.tell();
+  for (auto &E : S.Entries)
+    File.allocateBytes(E.Content);
+
+  return DataEnd;
 }
 
 static void layout(BlobAllocator &File, MemoryListStream::entry_type &Range) {
@@ -199,7 +207,7 @@ static Directory layout(BlobAllocator &File, Stream &S) {
     DataEnd = layout(File, cast<MemoryListStream>(S));
     break;
   case Stream::StreamKind::Memory64List:
-    layout(File, cast<Memory64ListStream>(S));
+    DataEnd = layout(File, cast<Memory64ListStream>(S));
     break;
   case Stream::StreamKind::ModuleList:
     DataEnd = layout(File, cast<ModuleListStream>(S));
diff --git a/llvm/lib/ObjectYAML/MinidumpYAML.cpp b/llvm/lib/ObjectYAML/MinidumpYAML.cpp
index aee17c520a010..b318a9e5cc2e5 100644
--- a/llvm/lib/ObjectYAML/MinidumpYAML.cpp
+++ b/llvm/lib/ObjectYAML/MinidumpYAML.cpp
@@ -260,10 +260,10 @@ void yaml::MappingTraits<MemoryInfo>::mapping(IO &IO, MemoryInfo &Info) {
   mapOptionalHex(IO, "Reserved1", Info.Reserved1, 0);
 }
 
-void yaml::MappingTraits<MemoryDescriptor_64>::mapping(
-    IO &IO, MemoryDescriptor_64 &Mem) {
-  mapRequiredHex(IO, "Start of memory range", Mem.StartOfMemoryRange);
-  mapRequiredHex(IO, "Data Size", Mem.DataSize);
+void yaml::MappingTraits<Memory64ListStream::entry_type>::mapping(
+    IO &IO, Memory64ListStream::entry_type &Mem) {
+  MappingContextTraits<MemoryDescriptor_64, yaml::BinaryRef>::mapping(
+      IO, Mem.Entry, Mem.Content);
 }
 
 void yaml::MappingTraits<VSFixedFileInfo>::mapping(IO &IO,
@@ -373,6 +373,7 @@ void yaml::MappingContextTraits<MemoryDescriptor, yaml::BinaryRef>::mapping(
 void yaml::MappingContextTraits<MemoryDescriptor_64, yaml::BinaryRef>::mapping(
     IO &IO, MemoryDescriptor_64 &Memory, BinaryRef &Content) {
   mapRequiredHex(IO, "Start of Memory Range", Memory.StartOfMemoryRange);
+  mapRequiredHex(IO, "Data Size", Memory.DataSize);
   IO.mapRequired("Content", Content);
 }
 
@@ -483,8 +484,8 @@ void yaml::MappingTraits<Object>::mapping(IO &IO, Object &O) {
   IO.mapRequired("Streams", O.Streams);
 }
 
-Expected<std::unique_ptr<Stream>>
-Stream::create(const Directory &StreamDesc, const object::MinidumpFile &File) {
+Expected<std::unique_ptr<Stream>> Stream::create(const Directory &StreamDesc,
+                                                 object::MinidumpFile &File) {
   StreamKind Kind = getKind(StreamDesc.Type);
   switch (Kind) {
   case StreamKind::Exception: {
@@ -522,9 +523,12 @@ Stream::create(const Directory &StreamDesc, const object::MinidumpFile &File) {
     auto ExpectedList = File.getMemory64List();
     if (!ExpectedList)
       return ExpectedList.takeError();
-    std::vector<MemoryDescriptor_64> Ranges;
+    std::vector<Memory64ListStream::entry_type> Ranges;
     for (const MemoryDescriptor_64 &MD : *ExpectedList) {
-      Ranges.push_back(MD);
+      auto ExpectedContent = File.getRawData(MD);
+      if (!ExpectedContent)
+        return ExpectedContent.takeError();
+      Ranges.push_back({MD, *ExpectedContent});
     }
     return std::make_unique<Memory64ListStream>(std::move(Ranges));
   }
@@ -584,7 +588,7 @@ Stream::create(const Directory &StreamDesc, const object::MinidumpFile &File) {
   llvm_unreachable("Unhandled stream kind!");
 }
 
-Expected<Object> Object::create(const object::MinidumpFile &File) {
+Expected<Object> Object::create(object::MinidumpFile &File) {
   std::vector<std::unique_ptr<Stream>> Streams;
   Streams.reserve(File.streams().size());
   for (const Directory &StreamDesc : File.streams()) {
diff --git a/llvm/test/tools/obj2yaml/Minidump/basic.yaml b/llvm/test/tools/obj2yaml/Minidump/basic.yaml
index dfabc132d8e71..9702f82dc5843 100644
--- a/llvm/test/tools/obj2yaml/Minidump/basic.yaml
+++ b/llvm/test/tools/obj2yaml/Minidump/basic.yaml
@@ -67,9 +67,13 @@ Streams:
       Parameter 1: 0x24
     Thread Context:  '8182838485868788'
   - Type:            MemoryList
-    Memory Ranges:   
+    Memory Ranges:
       - Start of Memory Range: 0x7C7D7E7F80818283
         Content:               '8485868788'
+  - Type:            Memory64List
+    Memory Ranges:
+      - Start of Memory Range: 0x7FFFFFFF0818283
+        Content:               '104101108108111'
   - Type:            MemoryInfoList
     Memory Ranges:
       - Base Address:    0x0000000000000000
@@ -156,9 +160,13 @@ Streams:
 # CHECK-NEXT:       Parameter 1: 0x24
 # CHECK-NEXT:     Thread Context:  '8182838485868788'
 # CHECK-NEXT:   - Type:            MemoryList
-# CHECK-NEXT:     Memory Ranges:   
+# CHECK-NEXT:     Memory Ranges:
 # CHECK-NEXT:       - Start of Memory Range: 0x7C7D7E7F80818283
 # CHECK-NEXT:         Content:               '8485868788'
+# CHECK-NEXT:   - Type:            Memory64List
+# CHECK-NEXT:     Memory Ranges:
+# CHECK-NEXT:       - Start of Memory Range: 0x7FFFFFFF0818283
+# CHECK-NEXT:         Content:               '104101108108111'
 # CHECK-NEXT:   - Type:            MemoryInfoList
 # CHECK-NEXT:     Memory Ranges:
 # CHECK-NEXT:       - Base Address:       0x0
diff --git a/llvm/tools/obj2yaml/minidump2yaml.cpp b/llvm/tools/obj2yaml/minidump2yaml.cpp
index 7b25b1869c6b6..53486d57d0932 100644
--- a/llvm/tools/obj2yaml/minidump2yaml.cpp
+++ b/llvm/tools/obj2yaml/minidump2yaml.cpp
@@ -13,7 +13,7 @@
 
 using namespace llvm;
 
-Error minidump2yaml(raw_ostream &Out, const object::MinidumpFile &Obj) {
+Error minidump2yaml(raw_ostream &Out, object::MinidumpFile &Obj) {
   auto ExpectedObject = MinidumpYAML::Object::create(Obj);
   if (!ExpectedObject)
     return ExpectedObject.takeError();
diff --git a/llvm/tools/obj2yaml/obj2yaml.h b/llvm/tools/obj2yaml/obj2yaml.h
index 03d7db5317acd..96256bc1307d6 100644
--- a/llvm/tools/obj2yaml/obj2yaml.h
+++ b/llvm/tools/obj2yaml/obj2yaml.h
@@ -28,7 +28,7 @@ llvm::Error elf2yaml(llvm::raw_ostream &Out,
 llvm::Error macho2yaml(llvm::raw_ostream &Out, const llvm::object::Binary &Obj,
                        unsigned RawSegments);
 llvm::Error minidump2yaml(llvm::raw_ostream &Out,
-                          const llvm::object::MinidumpFile &Obj);
+                          llvm::object::MinidumpFile &Obj);
 llvm::Error xcoff2yaml(llvm::raw_ostream &Out,
                        const llvm::object::XCOFFObjectFile &Obj);
 std::error_code wasm2yaml(llvm::raw_ostream &Out,
diff --git a/llvm/unittests/ObjectYAML/MinidumpYAMLTest.cpp b/llvm/unittests/ObjectYAML/MinidumpYAMLTest.cpp
index 0297f62d10699..79fb903bcfd10 100644
--- a/llvm/unittests/ObjectYAML/MinidumpYAMLTest.cpp
+++ b/llvm/unittests/ObjectYAML/MinidumpYAMLTest.cpp
@@ -336,3 +336,51 @@ TEST(MinidumpYAML, ExceptionStream_ExtraParameter) {
                                0xab, 0xad, 0xca, 0xfe}),
             *ExpectedContext);
 }
+
+TEST(MinidumpYAML, MemoryRegion_64bit) {
+  SmallString<0> Storage;
+  auto ExpectedFile = toBinary(Storage, R"(
+--- !minidump
+Streams:
+  - Type:            Memory64List
+    Memory Ranges:
+      - Start of Memory Range: 0x7FFFFFCF0818283
+        Data Size:             8
+        Content:               '68656c6c6f'
+      - Start of Memory Range: 0x7FFFFFFF0818283
+        Data Size:             8
+        Content:               '776f726c64'
+        )");
+
+  ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
+  object::MinidumpFile &File = **ExpectedFile;
+
+  ASSERT_EQ(1u, File.streams().size());
+
+  Expected<ArrayRef<minidump::MemoryDescriptor_64>> ExpectedMemoryList =
+      File.getMemory64List();
+
+  ASSERT_THAT_EXPECTED(ExpectedMemoryList, Succeeded());
+
+  ArrayRef<minidump::MemoryDescriptor_64> MemoryList = *ExpectedMemoryList;
+  ASSERT_EQ(2u, MemoryList.size());
+
+  const minidump::MemoryDescriptor_64 &DescOne = MemoryList[0];
+  ASSERT_EQ(0x7FFFFFCF0818283u, DescOne.StartOfMemoryRange);
+  ASSERT_EQ(8u, DescOne.DataSize);
+
+  const minidump::MemoryDescriptor_64 &DescTwo = MemoryList[1];
+  ASSERT_EQ(0x7FFFFFFF0818283u, DescTwo.StartOfMemoryRange);
+  ASSERT_EQ(8u, DescTwo.DataSize);
+
+  const std::optional<ArrayRef<uint8_t>> ExpectedContent =
+      File.getRawStream(StreamType::Memory64List);
+  ASSERT_TRUE(ExpectedContent);
+  const ArrayRef<uint8_t> Content = *ExpectedContent;
+  const size_t offset =
+      sizeof(Memory64ListHeader) + (sizeof(MemoryDescriptor_64) * 2);
+  const uint64_t *Array =
+      reinterpret_cast<const uint64_t *>(Content.slice(offset, 16).data(), 16);
+  ASSERT_EQ(0x7000000000002Au, Array[0]);
+  ASSERT_EQ(0x7000A00000000Au, Array[1]);
+}



More information about the lldb-commits mailing list