[llvm] a27164c - [LLDB][Minidump] Add 64b support to LLDB's minidump file builder. (#95312)

via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 24 10:48:06 PDT 2024


Author: Jacob Lalonde
Date: 2024-06-24T10:48:01-07:00
New Revision: a27164cb33162bb42642c091703f9c6f8829785c

URL: https://github.com/llvm/llvm-project/commit/a27164cb33162bb42642c091703f9c6f8829785c
DIFF: https://github.com/llvm/llvm-project/commit/a27164cb33162bb42642c091703f9c6f8829785c.diff

LOG: [LLDB][Minidump] Add 64b support to LLDB's minidump file builder. (#95312)

Currently, LLDB does not support taking a minidump over the 4.2gb limit imposed by uint32. In fact, currently it writes the RVA's and the headers to the end of the file, which can become corrupted due to the header offset only supporting a 32b offset.

This change reorganizes how the file structure is laid out. LLDB will precalculate the number of directories required and preallocate space at the top of the file to fill in later. Additionally, thread stacks require a 32b offset, and we provision empty descriptors and keep track of them to clean up once we write the 32b memory list.

For
[MemoryList64](https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_memory64_list),
the RVA to the start of the section itself will remain in a 32b addressable space. We achieve this by predetermining the space the memory regions will take, and only writing up to 4.2 gb of data with some buffer to allow all the MemoryDescriptor64s to also still be 32b addressable.

I did not add any explicit tests to this PR because allocating 4.2gb+ to test is very expensive. However, we have 32b automation tests and I validated with in several ways, including with 5gb+ array/object and would be willing to add this as a test case.

Added: 
    

Modified: 
    lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp
    lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h
    lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp
    llvm/include/llvm/BinaryFormat/Minidump.h

Removed: 
    


################################################################################
diff  --git a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp
index 7231433619ffb..7a09c6104d08c 100644
--- a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp
+++ b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp
@@ -20,25 +20,100 @@
 #include "lldb/Target/RegisterContext.h"
 #include "lldb/Target/StopInfo.h"
 #include "lldb/Target/ThreadList.h"
+#include "lldb/Utility/DataBufferHeap.h"
 #include "lldb/Utility/DataExtractor.h"
 #include "lldb/Utility/LLDBLog.h"
 #include "lldb/Utility/Log.h"
+#include "lldb/Utility/RangeMap.h"
 #include "lldb/Utility/RegisterValue.h"
 
 #include "llvm/ADT/StringRef.h"
 #include "llvm/BinaryFormat/Minidump.h"
 #include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/Endian.h"
 #include "llvm/Support/Error.h"
+#include "llvm/TargetParser/Triple.h"
 
 #include "Plugins/Process/minidump/MinidumpTypes.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-types.h"
 
+#include <algorithm>
 #include <cinttypes>
+#include <climits>
+#include <cstddef>
+#include <cstdint>
+#include <functional>
+#include <iostream>
+#include <set>
+#include <utility>
+#include <vector>
 
 using namespace lldb;
 using namespace lldb_private;
 using namespace llvm::minidump;
 
-void MinidumpFileBuilder::AddDirectory(StreamType type, size_t stream_size) {
+Status MinidumpFileBuilder::AddHeaderAndCalculateDirectories() {
+  // First set the offset on the file, and on the bytes saved
+  m_saved_data_size = HEADER_SIZE;
+  // We know we will have at least Misc, SystemInfo, Modules, and ThreadList
+  // (corresponding memory list for stacks) And an additional memory list for
+  // non-stacks.
+  lldb_private::Target &target = m_process_sp->GetTarget();
+  m_expected_directories = 6;
+  // Check if OS is linux and reserve directory space for all linux specific
+  // breakpad extension directories.
+  if (target.GetArchitecture().GetTriple().getOS() ==
+      llvm::Triple::OSType::Linux)
+    m_expected_directories += 9;
+
+  // Go through all of the threads and check for exceptions.
+  lldb_private::ThreadList thread_list = m_process_sp->GetThreadList();
+  const uint32_t num_threads = thread_list.GetSize();
+  for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
+    ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx));
+    StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
+    if (stop_info_sp) {
+      const StopReason &stop_reason = stop_info_sp->GetStopReason();
+      if (stop_reason == StopReason::eStopReasonException ||
+          stop_reason == StopReason::eStopReasonSignal)
+        m_expected_directories++;
+    }
+  }
+
+  m_saved_data_size +=
+      m_expected_directories * sizeof(llvm::minidump::Directory);
+  Status error;
+  offset_t new_offset = m_core_file->SeekFromStart(m_saved_data_size);
+  if (new_offset != m_saved_data_size)
+    error.SetErrorStringWithFormat("Failed to fill in header and directory "
+                                   "sections. Written / Expected (%" PRIx64
+                                   " / %" PRIx64 ")",
+                                   new_offset, m_saved_data_size);
+
+  return error;
+}
+
+Status MinidumpFileBuilder::AddDirectory(StreamType type,
+                                         uint64_t stream_size) {
+  // We explicitly cast type, an 32b enum, to uint32_t to avoid warnings.
+  Status error;
+  if (GetCurrentDataEndOffset() > UINT32_MAX) {
+    error.SetErrorStringWithFormat("Unable to add directory for stream type "
+                                   "%x, offset is greater then 32 bit limit.",
+                                   (uint32_t)type);
+    return error;
+  }
+
+  if (m_directories.size() + 1 > m_expected_directories) {
+    error.SetErrorStringWithFormat(
+        "Unable to add directory for stream type %x, exceeded expected number "
+        "of directories %d.",
+        (uint32_t)type, m_expected_directories);
+    return error;
+  }
+
   LocationDescriptor loc;
   loc.DataSize = static_cast<llvm::support::ulittle32_t>(stream_size);
   // Stream will begin at the current end of data section
@@ -49,11 +124,17 @@ void MinidumpFileBuilder::AddDirectory(StreamType type, size_t stream_size) {
   dir.Location = loc;
 
   m_directories.push_back(dir);
+  return error;
 }
 
-Status MinidumpFileBuilder::AddSystemInfo(const llvm::Triple &target_triple) {
+Status MinidumpFileBuilder::AddSystemInfo() {
   Status error;
-  AddDirectory(StreamType::SystemInfo, sizeof(llvm::minidump::SystemInfo));
+  const llvm::Triple &target_triple =
+      m_process_sp->GetTarget().GetArchitecture().GetTriple();
+  error =
+      AddDirectory(StreamType::SystemInfo, sizeof(llvm::minidump::SystemInfo));
+  if (error.Fail())
+    return error;
 
   llvm::minidump::ProcessorArchitecture arch;
   switch (target_triple.getArch()) {
@@ -165,7 +246,6 @@ llvm::Expected<uint64_t> getModuleFileSize(Target &target,
     }
     return SizeOfImage;
   }
-
   SectionSP sect_sp = mod->GetObjectFile()->GetBaseAddress().GetSection();
 
   if (!sect_sp) {
@@ -203,10 +283,11 @@ llvm::Expected<uint64_t> getModuleFileSize(Target &target,
 // single module. Additional data of variable length, such as module's names,
 // are stored just after the ModuleList stream. The llvm::minidump::Module
 // structures point to this helper data by global offset.
-Status MinidumpFileBuilder::AddModuleList(Target &target) {
+Status MinidumpFileBuilder::AddModuleList() {
   constexpr size_t minidump_module_size = sizeof(llvm::minidump::Module);
   Status error;
 
+  lldb_private::Target &target = m_process_sp->GetTarget();
   const ModuleList &modules = target.GetImages();
   llvm::support::ulittle32_t modules_count =
       static_cast<llvm::support::ulittle32_t>(modules.GetSize());
@@ -223,7 +304,9 @@ Status MinidumpFileBuilder::AddModuleList(Target &target) {
       sizeof(llvm::support::ulittle32_t) + modules_count * minidump_module_size;
 
   // Adding directory describing this stream.
-  AddDirectory(StreamType::ModuleList, module_stream_size);
+  error = AddDirectory(StreamType::ModuleList, module_stream_size);
+  if (error.Fail())
+    return error;
 
   m_data.AppendData(&modules_count, sizeof(llvm::support::ulittle32_t));
 
@@ -480,42 +563,32 @@ class ArchThreadContexts {
   }
 };
 
-// Function returns start and size of the memory region that contains
-// memory location pointed to by the current stack pointer.
-llvm::Expected<std::pair<addr_t, addr_t>>
-findStackHelper(const lldb::ProcessSP &process_sp, uint64_t rsp) {
-  MemoryRegionInfo range_info;
-  Status error = process_sp->GetMemoryRegionInfo(rsp, range_info);
-  // Skip failed memory region requests or any regions with no permissions.
-  if (error.Fail() || range_info.GetLLDBPermissions() == 0)
-    return llvm::createStringError(
-        std::errc::not_supported,
-        "unable to load stack segment of the process");
-
-  // This is a duplicate of the logic in
-  // Process::SaveOffRegionsWithStackPointers but ultimately, we need to only
-  // save up from the start of the stack down to the stack pointer
-  const addr_t range_end = range_info.GetRange().GetRangeEnd();
-  const addr_t red_zone = process_sp->GetABI()->GetRedZoneSize();
-  const addr_t stack_head = rsp - red_zone;
-  if (stack_head > range_info.GetRange().GetRangeEnd()) {
-    range_info.GetRange().SetRangeBase(stack_head);
-    range_info.GetRange().SetByteSize(range_end - stack_head);
-  }
-
-  const addr_t addr = range_info.GetRange().GetRangeBase();
-  const addr_t size = range_info.GetRange().GetByteSize();
-
-  if (size == 0)
-    return llvm::createStringError(std::errc::not_supported,
-                                   "stack segment of the process is empty");
-
-  return std::make_pair(addr, size);
+Status MinidumpFileBuilder::FixThreadStacks() {
+  Status error;
+  // If we have anything in the heap flush it.
+  FlushBufferToDisk();
+  m_core_file->SeekFromStart(m_thread_list_start);
+  for (auto &pair : m_thread_by_range_end) {
+    // The thread objects will get a new memory descriptor added
+    // When we are emitting the memory list and then we write it here
+    const llvm::minidump::Thread &thread = pair.second;
+    size_t bytes_to_write = sizeof(llvm::minidump::Thread);
+    size_t bytes_written = bytes_to_write;
+    error = m_core_file->Write(&thread, bytes_written);
+    if (error.Fail() || bytes_to_write != bytes_written) {
+      error.SetErrorStringWithFormat(
+          "Wrote incorrect number of bytes to minidump file. (written %zd/%zd)",
+          bytes_written, bytes_to_write);
+      return error;
+    }
+  }
+
+  return error;
 }
 
-Status MinidumpFileBuilder::AddThreadList(const lldb::ProcessSP &process_sp) {
+Status MinidumpFileBuilder::AddThreadList() {
   constexpr size_t minidump_thread_size = sizeof(llvm::minidump::Thread);
-  lldb_private::ThreadList thread_list = process_sp->GetThreadList();
+  lldb_private::ThreadList thread_list = m_process_sp->GetThreadList();
 
   // size of the entire thread stream consists of:
   // number of threads and threads array
@@ -523,28 +596,31 @@ Status MinidumpFileBuilder::AddThreadList(const lldb::ProcessSP &process_sp) {
                               thread_list.GetSize() * minidump_thread_size;
   // save for the ability to set up RVA
   size_t size_before = GetCurrentDataEndOffset();
-
-  AddDirectory(StreamType::ThreadList, thread_stream_size);
+  Status error;
+  error = AddDirectory(StreamType::ThreadList, thread_stream_size);
+  if (error.Fail())
+    return error;
 
   llvm::support::ulittle32_t thread_count =
       static_cast<llvm::support::ulittle32_t>(thread_list.GetSize());
   m_data.AppendData(&thread_count, sizeof(llvm::support::ulittle32_t));
 
+  // Take the offset after the thread count.
+  m_thread_list_start = GetCurrentDataEndOffset();
   DataBufferHeap helper_data;
 
   const uint32_t num_threads = thread_list.GetSize();
-
+  Log *log = GetLog(LLDBLog::Object);
   for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
     ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx));
     RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
-    Status error;
 
     if (!reg_ctx_sp) {
       error.SetErrorString("Unable to get the register context.");
       return error;
     }
     RegisterContext *reg_ctx = reg_ctx_sp.get();
-    Target &target = process_sp->GetTarget();
+    Target &target = m_process_sp->GetTarget();
     const ArchSpec &arch = target.GetArchitecture();
     ArchThreadContexts thread_context(arch.GetMachine());
     if (!thread_context.prepareRegisterContext(reg_ctx)) {
@@ -553,38 +629,18 @@ Status MinidumpFileBuilder::AddThreadList(const lldb::ProcessSP &process_sp) {
           arch.GetTriple().getArchName().str().c_str());
       return error;
     }
-    uint64_t sp = reg_ctx->GetSP();
-    auto expected_address_range = findStackHelper(process_sp, sp);
 
-    if (!expected_address_range) {
-      consumeError(expected_address_range.takeError());
-      error.SetErrorString("Unable to get the stack address.");
-      return error;
-    }
-
-    std::pair<uint64_t, uint64_t> range = std::move(*expected_address_range);
-    uint64_t addr = range.first;
-    uint64_t size = range.second;
-
-    auto data_up = std::make_unique<DataBufferHeap>(size, 0);
-    const size_t stack_bytes_read =
-        process_sp->ReadMemory(addr, data_up->GetBytes(), size, error);
-
-    if (error.Fail())
-      return error;
-
-    LocationDescriptor stack_memory;
-    stack_memory.DataSize =
-        static_cast<llvm::support::ulittle32_t>(stack_bytes_read);
-    stack_memory.RVA = static_cast<llvm::support::ulittle32_t>(
-        size_before + thread_stream_size + helper_data.GetByteSize());
+    uint64_t sp = reg_ctx->GetSP();
+    MemoryRegionInfo sp_region;
+    m_process_sp->GetMemoryRegionInfo(sp, sp_region);
 
+    // Emit a blank descriptor
     MemoryDescriptor stack;
-    stack.StartOfMemoryRange = static_cast<llvm::support::ulittle64_t>(addr);
-    stack.Memory = stack_memory;
-
-    helper_data.AppendData(data_up->GetBytes(), stack_bytes_read);
-
+    LocationDescriptor empty_label;
+    empty_label.DataSize = 0;
+    empty_label.RVA = 0;
+    stack.Memory = empty_label;
+    stack.StartOfMemoryRange = 0;
     LocationDescriptor thread_context_memory_locator;
     thread_context_memory_locator.DataSize =
         static_cast<llvm::support::ulittle32_t>(thread_context.size());
@@ -593,6 +649,8 @@ Status MinidumpFileBuilder::AddThreadList(const lldb::ProcessSP &process_sp) {
     // Cache thie thread context memory so we can reuse for exceptions.
     m_tid_to_reg_ctx[thread_sp->GetID()] = thread_context_memory_locator;
 
+    LLDB_LOGF(log, "AddThreadList for thread %d: thread_context %zu bytes",
+              thread_idx, thread_context.size());
     helper_data.AppendData(thread_context.data(), thread_context.size());
 
     llvm::minidump::Thread t;
@@ -604,16 +662,20 @@ Status MinidumpFileBuilder::AddThreadList(const lldb::ProcessSP &process_sp) {
     t.EnvironmentBlock = static_cast<llvm::support::ulittle64_t>(0);
     t.Stack = stack, t.Context = thread_context_memory_locator;
 
+    // We save off the stack object so we can circle back and clean it up.
+    m_thread_by_range_end[sp_region.GetRange().GetRangeEnd()] = t;
     m_data.AppendData(&t, sizeof(llvm::minidump::Thread));
   }
 
+  LLDB_LOGF(log, "AddThreadList(): total helper_data %" PRIx64 " bytes",
+            helper_data.GetByteSize());
   m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize());
   return Status();
 }
 
-void MinidumpFileBuilder::AddExceptions(const lldb::ProcessSP &process_sp) {
-  lldb_private::ThreadList thread_list = process_sp->GetThreadList();
-
+Status MinidumpFileBuilder::AddExceptions() {
+  lldb_private::ThreadList thread_list = m_process_sp->GetThreadList();
+  Status error;
   const uint32_t num_threads = thread_list.GetSize();
   for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
     ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx));
@@ -632,7 +694,10 @@ void MinidumpFileBuilder::AddExceptions(const lldb::ProcessSP &process_sp) {
     if (add_exception) {
       constexpr size_t minidump_exception_size =
           sizeof(llvm::minidump::ExceptionStream);
-      AddDirectory(StreamType::Exception, minidump_exception_size);
+      error = AddDirectory(StreamType::Exception, minidump_exception_size);
+      if (error.Fail())
+        return error;
+
       StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
       RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
       Exception exp_record = {};
@@ -660,69 +725,16 @@ void MinidumpFileBuilder::AddExceptions(const lldb::ProcessSP &process_sp) {
       m_data.AppendData(&exp_stream, minidump_exception_size);
     }
   }
-}
-
-lldb_private::Status
-MinidumpFileBuilder::AddMemoryList(const lldb::ProcessSP &process_sp,
-                                   lldb::SaveCoreStyle core_style) {
-  Status error;
-  Process::CoreFileMemoryRanges core_ranges;
-  error = process_sp->CalculateCoreFileSaveRanges(core_style, core_ranges);
-  if (error.Fail()) {
-    error.SetErrorString("Process doesn't support getting memory region info.");
-    return error;
-  }
-
-  DataBufferHeap helper_data;
-  std::vector<MemoryDescriptor> mem_descriptors;
-  for (const auto &core_range : core_ranges) {
-    // Skip empty memory regions.
-    if (core_range.range.empty())
-      continue;
-    const addr_t addr = core_range.range.start();
-    const addr_t size = core_range.range.size();
-    auto data_up = std::make_unique<DataBufferHeap>(size, 0);
-    const size_t bytes_read =
-        process_sp->ReadMemory(addr, data_up->GetBytes(), size, error);
-    if (error.Fail()) {
-      Log *log = GetLog(LLDBLog::Object);
-      LLDB_LOGF(log, "Failed to read memory region. Bytes read: %zu, error: %s",
-                bytes_read, error.AsCString());
-      error.Clear();
-    }
-    if (bytes_read == 0)
-      continue;
-    // We have a good memory region with valid bytes to store.
-    LocationDescriptor memory_dump;
-    memory_dump.DataSize = static_cast<llvm::support::ulittle32_t>(bytes_read);
-    memory_dump.RVA =
-        static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset());
-    MemoryDescriptor memory_desc;
-    memory_desc.StartOfMemoryRange =
-        static_cast<llvm::support::ulittle64_t>(addr);
-    memory_desc.Memory = memory_dump;
-    mem_descriptors.push_back(memory_desc);
-    m_data.AppendData(data_up->GetBytes(), bytes_read);
-  }
-
-  AddDirectory(StreamType::MemoryList,
-               sizeof(llvm::support::ulittle32_t) +
-                   mem_descriptors.size() *
-                       sizeof(llvm::minidump::MemoryDescriptor));
-  llvm::support::ulittle32_t memory_ranges_num(mem_descriptors.size());
-
-  m_data.AppendData(&memory_ranges_num, sizeof(llvm::support::ulittle32_t));
-  for (auto memory_descriptor : mem_descriptors) {
-    m_data.AppendData(&memory_descriptor,
-                      sizeof(llvm::minidump::MemoryDescriptor));
-  }
 
   return error;
 }
 
-void MinidumpFileBuilder::AddMiscInfo(const lldb::ProcessSP &process_sp) {
-  AddDirectory(StreamType::MiscInfo,
-               sizeof(lldb_private::minidump::MinidumpMiscInfo));
+lldb_private::Status MinidumpFileBuilder::AddMiscInfo() {
+  Status error;
+  error = AddDirectory(StreamType::MiscInfo,
+                       sizeof(lldb_private::minidump::MinidumpMiscInfo));
+  if (error.Fail())
+    return error;
 
   lldb_private::minidump::MinidumpMiscInfo misc_info;
   misc_info.size = static_cast<llvm::support::ulittle32_t>(
@@ -732,7 +744,7 @@ void MinidumpFileBuilder::AddMiscInfo(const lldb::ProcessSP &process_sp) {
   misc_info.flags1 = static_cast<llvm::support::ulittle32_t>(0);
 
   lldb_private::ProcessInstanceInfo process_info;
-  process_sp->GetProcessInfo(process_info);
+  m_process_sp->GetProcessInfo(process_info);
   if (process_info.ProcessIDIsValid()) {
     // Set flags1 to reflect that PID is filled in
     misc_info.flags1 =
@@ -744,6 +756,7 @@ void MinidumpFileBuilder::AddMiscInfo(const lldb::ProcessSP &process_sp) {
 
   m_data.AppendData(&misc_info,
                     sizeof(lldb_private::minidump::MinidumpMiscInfo));
+  return error;
 }
 
 std::unique_ptr<llvm::MemoryBuffer>
@@ -754,15 +767,20 @@ getFileStreamHelper(const std::string &path) {
   return std::move(maybe_stream.get());
 }
 
-void MinidumpFileBuilder::AddLinuxFileStreams(
-    const lldb::ProcessSP &process_sp) {
+Status MinidumpFileBuilder::AddLinuxFileStreams() {
+  Status error;
+  // No-op if we are not on linux.
+  if (m_process_sp->GetTarget().GetArchitecture().GetTriple().getOS() !=
+      llvm::Triple::Linux)
+    return error;
+
   std::vector<std::pair<StreamType, std::string>> files_with_stream_types = {
       {StreamType::LinuxCPUInfo, "/proc/cpuinfo"},
       {StreamType::LinuxLSBRelease, "/etc/lsb-release"},
   };
 
   lldb_private::ProcessInstanceInfo process_info;
-  process_sp->GetProcessInfo(process_info);
+  m_process_sp->GetProcessInfo(process_info);
   if (process_info.ProcessIDIsValid()) {
     lldb::pid_t pid = process_info.GetProcessID();
     std::string pid_str = std::to_string(pid);
@@ -791,16 +809,94 @@ void MinidumpFileBuilder::AddLinuxFileStreams(
       size_t size = memory_buffer->getBufferSize();
       if (size == 0)
         continue;
-      AddDirectory(stream, size);
+      error = AddDirectory(stream, size);
+      if (error.Fail())
+        return error;
       m_data.AppendData(memory_buffer->getBufferStart(), size);
     }
   }
+
+  return error;
 }
 
-Status MinidumpFileBuilder::Dump(lldb::FileUP &core_file) const {
-  constexpr size_t header_size = sizeof(llvm::minidump::Header);
-  constexpr size_t directory_size = sizeof(llvm::minidump::Directory);
+Status MinidumpFileBuilder::AddMemoryList(SaveCoreStyle core_style) {
+  Status error;
+
+  // We first save the thread stacks to ensure they fit in the first UINT32_MAX
+  // bytes of the core file. Thread structures in minidump files can only use
+  // 32 bit memory descriptiors, so we emit them first to ensure the memory is
+  // in accessible with a 32 bit offset.
+  Process::CoreFileMemoryRanges ranges_32;
+  Process::CoreFileMemoryRanges ranges_64;
+  error = m_process_sp->CalculateCoreFileSaveRanges(
+      SaveCoreStyle::eSaveCoreStackOnly, ranges_32);
+  if (error.Fail())
+    return error;
+
+  // Calculate totalsize including the current offset.
+  uint64_t total_size = GetCurrentDataEndOffset();
+  total_size += ranges_32.size() * sizeof(llvm::minidump::MemoryDescriptor);
+  std::unordered_set<addr_t> stack_start_addresses;
+  for (const auto &core_range : ranges_32) {
+    stack_start_addresses.insert(core_range.range.start());
+    total_size += core_range.range.size();
+  }
+
+  if (total_size >= UINT32_MAX) {
+    error.SetErrorStringWithFormat("Unable to write minidump. Stack memory "
+                                   "exceeds 32b limit. (Num Stacks %zu)",
+                                   ranges_32.size());
+    return error;
+  }
+
+  Process::CoreFileMemoryRanges all_core_memory_ranges;
+  if (core_style != SaveCoreStyle::eSaveCoreStackOnly) {
+    error = m_process_sp->CalculateCoreFileSaveRanges(core_style,
+                                                      all_core_memory_ranges);
+    if (error.Fail())
+      return error;
+  }
+
+  // After saving the stacks, we start packing as much as we can into 32b.
+  // We apply a generous padding here so that the Directory, MemoryList and
+  // Memory64List sections all begin in 32b addressable space.
+  // Then anything overflow extends into 64b addressable space.
+  // All core memeroy ranges will either container nothing on stacks only
+  // or all the memory ranges including stacks
+  if (!all_core_memory_ranges.empty())
+    total_size +=
+        256 + (all_core_memory_ranges.size() - stack_start_addresses.size()) *
+                  sizeof(llvm::minidump::MemoryDescriptor_64);
+
+  for (const auto &core_range : all_core_memory_ranges) {
+    const addr_t range_size = core_range.range.size();
+    if (stack_start_addresses.count(core_range.range.start()) > 0)
+      // Don't double save stacks.
+      continue;
+
+    if (total_size + range_size < UINT32_MAX) {
+      ranges_32.push_back(core_range);
+      total_size += range_size;
+    } else {
+      ranges_64.push_back(core_range);
+    }
+  }
 
+  error = AddMemoryList_32(ranges_32);
+  if (error.Fail())
+    return error;
+
+  // Add the remaining memory as a 64b range.
+  if (!ranges_64.empty()) {
+    error = AddMemoryList_64(ranges_64);
+    if (error.Fail())
+      return error;
+  }
+
+  return FixThreadStacks();
+}
+
+Status MinidumpFileBuilder::DumpHeader() const {
   // write header
   llvm::minidump::Header header;
   header.Signature = static_cast<llvm::support::ulittle32_t>(
@@ -808,9 +904,10 @@ Status MinidumpFileBuilder::Dump(lldb::FileUP &core_file) const {
   header.Version = static_cast<llvm::support::ulittle32_t>(
       llvm::minidump::Header::MagicVersion);
   header.NumberOfStreams =
-      static_cast<llvm::support::ulittle32_t>(GetDirectoriesNum());
+      static_cast<llvm::support::ulittle32_t>(m_directories.size());
+  // We write the directories right after the header.
   header.StreamDirectoryRVA =
-      static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset());
+      static_cast<llvm::support::ulittle32_t>(HEADER_SIZE);
   header.Checksum = static_cast<llvm::support::ulittle32_t>(
       0u), // not used in most of the writers
       header.TimeDateStamp =
@@ -821,36 +918,35 @@ Status MinidumpFileBuilder::Dump(lldb::FileUP &core_file) const {
   Status error;
   size_t bytes_written;
 
-  bytes_written = header_size;
-  error = core_file->Write(&header, bytes_written);
-  if (error.Fail() || bytes_written != header_size) {
-    if (bytes_written != header_size)
+  m_core_file->SeekFromStart(0);
+  bytes_written = HEADER_SIZE;
+  error = m_core_file->Write(&header, bytes_written);
+  if (error.Fail() || bytes_written != HEADER_SIZE) {
+    if (bytes_written != HEADER_SIZE)
       error.SetErrorStringWithFormat(
-          "unable to write the header (written %zd/%zd)", bytes_written,
-          header_size);
+          "Unable to write the minidump header (written %zd/%zd)",
+          bytes_written, HEADER_SIZE);
     return error;
   }
+  return error;
+}
 
-  // write data
-  bytes_written = m_data.GetByteSize();
-  error = core_file->Write(m_data.GetBytes(), bytes_written);
-  if (error.Fail() || bytes_written != m_data.GetByteSize()) {
-    if (bytes_written != m_data.GetByteSize())
-      error.SetErrorStringWithFormat(
-          "unable to write the data (written %zd/%" PRIu64 ")", bytes_written,
-          m_data.GetByteSize());
-    return error;
-  }
+offset_t MinidumpFileBuilder::GetCurrentDataEndOffset() const {
+  return m_data.GetByteSize() + m_saved_data_size;
+}
 
-  // write directories
+Status MinidumpFileBuilder::DumpDirectories() const {
+  Status error;
+  size_t bytes_written;
+  m_core_file->SeekFromStart(HEADER_SIZE);
   for (const Directory &dir : m_directories) {
-    bytes_written = directory_size;
-    error = core_file->Write(&dir, bytes_written);
-    if (error.Fail() || bytes_written != directory_size) {
-      if (bytes_written != directory_size)
+    bytes_written = DIRECTORY_SIZE;
+    error = m_core_file->Write(&dir, bytes_written);
+    if (error.Fail() || bytes_written != DIRECTORY_SIZE) {
+      if (bytes_written != DIRECTORY_SIZE)
         error.SetErrorStringWithFormat(
             "unable to write the directory (written %zd/%zd)", bytes_written,
-            directory_size);
+            DIRECTORY_SIZE);
       return error;
     }
   }
@@ -858,10 +954,254 @@ Status MinidumpFileBuilder::Dump(lldb::FileUP &core_file) const {
   return error;
 }
 
-size_t MinidumpFileBuilder::GetDirectoriesNum() const {
-  return m_directories.size();
+static uint64_t
+GetLargestRangeSize(const Process::CoreFileMemoryRanges &ranges) {
+  uint64_t max_size = 0;
+  for (const auto &core_range : ranges)
+    max_size = std::max(max_size, core_range.range.size());
+  return max_size;
+}
+
+Status
+MinidumpFileBuilder::AddMemoryList_32(Process::CoreFileMemoryRanges &ranges) {
+  std::vector<MemoryDescriptor> descriptors;
+  Status error;
+  if (ranges.size() == 0)
+    return error;
+
+  Log *log = GetLog(LLDBLog::Object);
+  size_t region_index = 0;
+  auto data_up =
+      std::make_unique<DataBufferHeap>(GetLargestRangeSize(ranges), 0);
+  for (const auto &core_range : ranges) {
+    // Take the offset before we write.
+    const offset_t offset_for_data = GetCurrentDataEndOffset();
+    const addr_t addr = core_range.range.start();
+    const addr_t size = core_range.range.size();
+    const addr_t end = core_range.range.end();
+
+    LLDB_LOGF(log,
+              "AddMemoryList %zu/%zu reading memory for region "
+              "(%" PRIx64 " bytes) [%" PRIx64 ", %" PRIx64 ")",
+              region_index, ranges.size(), size, addr, addr + size);
+    ++region_index;
+
+    const size_t bytes_read =
+        m_process_sp->ReadMemory(addr, data_up->GetBytes(), size, error);
+    if (error.Fail() || bytes_read == 0) {
+      LLDB_LOGF(log, "Failed to read memory region. Bytes read: %zu, error: %s",
+                bytes_read, error.AsCString());
+      // Just skip sections with errors or zero bytes in 32b mode
+      continue;
+    } else if (bytes_read != size) {
+      LLDB_LOGF(
+          log, "Memory region at: %" PRIx64 " failed to read %" PRIx64 " bytes",
+          addr, size);
+    }
+
+    MemoryDescriptor descriptor;
+    descriptor.StartOfMemoryRange =
+        static_cast<llvm::support::ulittle64_t>(addr);
+    descriptor.Memory.DataSize =
+        static_cast<llvm::support::ulittle32_t>(bytes_read);
+    descriptor.Memory.RVA =
+        static_cast<llvm::support::ulittle32_t>(offset_for_data);
+    descriptors.push_back(descriptor);
+    if (m_thread_by_range_end.count(end) > 0)
+      m_thread_by_range_end[end].Stack = descriptor;
+
+    // Add the data to the buffer, flush as needed.
+    error = AddData(data_up->GetBytes(), bytes_read);
+    if (error.Fail())
+      return error;
+  }
+
+  // Add a directory that references this list
+  // With a size of the number of ranges as a 32 bit num
+  // And then the size of all the ranges
+  error = AddDirectory(StreamType::MemoryList,
+                       sizeof(llvm::support::ulittle32_t) +
+                           descriptors.size() *
+                               sizeof(llvm::minidump::MemoryDescriptor));
+  if (error.Fail())
+    return error;
+
+  llvm::support::ulittle32_t memory_ranges_num =
+      static_cast<llvm::support::ulittle32_t>(descriptors.size());
+  m_data.AppendData(&memory_ranges_num, sizeof(llvm::support::ulittle32_t));
+  // For 32b we can get away with writing off the descriptors after the data.
+  // This means no cleanup loop needed.
+  m_data.AppendData(descriptors.data(),
+                    descriptors.size() * sizeof(MemoryDescriptor));
+
+  return error;
 }
 
-size_t MinidumpFileBuilder::GetCurrentDataEndOffset() const {
-  return sizeof(llvm::minidump::Header) + m_data.GetByteSize();
+Status
+MinidumpFileBuilder::AddMemoryList_64(Process::CoreFileMemoryRanges &ranges) {
+  Status error;
+  if (ranges.empty())
+    return error;
+
+  error = AddDirectory(StreamType::Memory64List,
+                       (sizeof(llvm::support::ulittle64_t) * 2) +
+                           ranges.size() *
+                               sizeof(llvm::minidump::MemoryDescriptor_64));
+  if (error.Fail())
+    return error;
+
+  llvm::support::ulittle64_t memory_ranges_num =
+      static_cast<llvm::support::ulittle64_t>(ranges.size());
+  m_data.AppendData(&memory_ranges_num, sizeof(llvm::support::ulittle64_t));
+  // Capture the starting offset for all the descriptors so we can clean them up
+  // if needed.
+  offset_t starting_offset =
+      GetCurrentDataEndOffset() + sizeof(llvm::support::ulittle64_t);
+  // The base_rva needs to start after the directories, which is right after
+  // this 8 byte variable.
+  offset_t base_rva =
+      starting_offset +
+      (ranges.size() * sizeof(llvm::minidump::MemoryDescriptor_64));
+  llvm::support::ulittle64_t memory_ranges_base_rva =
+      static_cast<llvm::support::ulittle64_t>(base_rva);
+  m_data.AppendData(&memory_ranges_base_rva,
+                    sizeof(llvm::support::ulittle64_t));
+
+  bool cleanup_required = false;
+  std::vector<MemoryDescriptor_64> descriptors;
+  // Enumerate the ranges and create the memory descriptors so we can append
+  // them first
+  for (const auto core_range : ranges) {
+    // Add the space required to store the memory descriptor
+    MemoryDescriptor_64 memory_desc;
+    memory_desc.StartOfMemoryRange =
+        static_cast<llvm::support::ulittle64_t>(core_range.range.start());
+    memory_desc.DataSize =
+        static_cast<llvm::support::ulittle64_t>(core_range.range.size());
+    descriptors.push_back(memory_desc);
+    // Now write this memory descriptor to the buffer.
+    m_data.AppendData(&memory_desc, sizeof(MemoryDescriptor_64));
+  }
+
+  Log *log = GetLog(LLDBLog::Object);
+  size_t region_index = 0;
+  auto data_up =
+      std::make_unique<DataBufferHeap>(GetLargestRangeSize(ranges), 0);
+  for (const auto &core_range : ranges) {
+    const addr_t addr = core_range.range.start();
+    const addr_t size = core_range.range.size();
+
+    LLDB_LOGF(log,
+              "AddMemoryList_64 %zu/%zu reading memory for region "
+              "(%" PRIx64 "bytes) "
+              "[%" PRIx64 ", %" PRIx64 ")",
+              region_index, ranges.size(), size, addr, addr + size);
+    ++region_index;
+
+    const size_t bytes_read =
+        m_process_sp->ReadMemory(addr, data_up->GetBytes(), size, error);
+    if (error.Fail()) {
+      LLDB_LOGF(log, "Failed to read memory region. Bytes read: %zu, error: %s",
+                bytes_read, error.AsCString());
+      error.Clear();
+      cleanup_required = true;
+      descriptors[region_index].DataSize = 0;
+    }
+    if (bytes_read != size) {
+      LLDB_LOGF(
+          log, "Memory region at: %" PRIx64 " failed to read %" PRIx64 " bytes",
+          addr, size);
+      cleanup_required = true;
+      descriptors[region_index].DataSize = bytes_read;
+    }
+
+    // Add the data to the buffer, flush as needed.
+    error = AddData(data_up->GetBytes(), bytes_read);
+    if (error.Fail())
+      return error;
+  }
+
+  // Early return if there is no cleanup needed.
+  if (!cleanup_required) {
+    return error;
+  } else {
+    // Flush to disk we can make the fixes in place.
+    FlushBufferToDisk();
+    // Fixup the descriptors that were not read correctly.
+    m_core_file->SeekFromStart(starting_offset);
+    size_t bytes_written = sizeof(MemoryDescriptor_64) * descriptors.size();
+    error = m_core_file->Write(descriptors.data(), bytes_written);
+    if (error.Fail() ||
+        bytes_written != sizeof(MemoryDescriptor_64) * descriptors.size()) {
+      error.SetErrorStringWithFormat(
+          "unable to write the memory descriptors (written %zd/%zd)",
+          bytes_written, sizeof(MemoryDescriptor_64) * descriptors.size());
+    }
+
+    return error;
+  }
+}
+
+Status MinidumpFileBuilder::AddData(const void *data, uint64_t size) {
+  // This should also get chunked, because worst case we copy over a big
+  // object / memory range, say 5gb. In that case, we'd have to allocate 10gb
+  // 5 gb for the buffer we're copying from, and then 5gb for the buffer we're
+  // copying to. Which will be short lived and immedaitely go to disk, the goal
+  // here is to limit the number of bytes we need to host in memory at any given
+  // time.
+  m_data.AppendData(data, size);
+  if (m_data.GetByteSize() > MAX_WRITE_CHUNK_SIZE)
+    return FlushBufferToDisk();
+
+  return Status();
+}
+
+Status MinidumpFileBuilder::FlushBufferToDisk() {
+  Status error;
+  // Set the stream to it's end.
+  m_core_file->SeekFromStart(m_saved_data_size);
+  addr_t starting_size = m_data.GetByteSize();
+  addr_t remaining_bytes = starting_size;
+  offset_t offset = 0;
+
+  while (remaining_bytes > 0) {
+    size_t bytes_written = remaining_bytes;
+    // We don't care how many bytes we wrote unless we got an error
+    // so just decrement the remaining bytes.
+    error = m_core_file->Write(m_data.GetBytes() + offset, bytes_written);
+    if (error.Fail()) {
+      error.SetErrorStringWithFormat(
+          "Wrote incorrect number of bytes to minidump file. (written %" PRIx64
+          "/%" PRIx64 ")",
+          starting_size - remaining_bytes, starting_size);
+      return error;
+    }
+
+    offset += bytes_written;
+    remaining_bytes -= bytes_written;
+  }
+
+  m_saved_data_size += starting_size;
+  m_data.Clear();
+  return error;
+}
+
+Status MinidumpFileBuilder::DumpFile() {
+  Status error;
+  // If anything is left unsaved, dump it.
+  error = FlushBufferToDisk();
+  if (error.Fail())
+    return error;
+
+  // Overwrite the header which we filled in earlier.
+  error = DumpHeader();
+  if (error.Fail())
+    return error;
+
+  // Overwrite the space saved for directories
+  error = DumpDirectories();
+  if (error.Fail())
+    return error;
+
+  return error;
 }

diff  --git a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h
index b2e984191983f..b606f925f9912 100644
--- a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h
+++ b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h
@@ -17,12 +17,20 @@
 #define LLDB_SOURCE_PLUGINS_OBJECTFILE_MINIDUMP_MINIDUMPFILEBUILDER_H
 
 #include <cstddef>
+#include <cstdint>
 #include <map>
+#include <unordered_map>
+#include <utility>
+#include <variant>
 
+#include "lldb/Target/Process.h"
 #include "lldb/Target/Target.h"
 #include "lldb/Utility/DataBufferHeap.h"
 #include "lldb/Utility/Status.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-types.h"
 
+#include "llvm/BinaryFormat/Minidump.h"
 #include "llvm/Object/Minidump.h"
 
 // Write std::string to minidump in the UTF16 format(with null termination char)
@@ -36,11 +44,39 @@ lldb_private::Status WriteString(const std::string &to_write,
 /// Minidump writer for Linux
 ///
 /// This class provides a Minidump writer that is able to
-/// snapshot the current process state. For the whole time, it stores all
-/// the data on heap.
+/// snapshot the current process state.
+///
+/// Minidumps are a Microsoft format for dumping process state.
+/// This class constructs the minidump on disk starting with
+/// Headers and Directories are written at the top of the file,
+/// with the amount of bytes being precalculates before any writing takes place
+/// Then the smaller data sections are written
+/// SystemInfo, ModuleList, Misc Info.
+/// Then Threads are emitted, threads are the first section that needs to be
+/// 'fixed up' this happens when later we emit the memory stream, we identify if
+/// that stream is the expected stack, and if so we update the stack with the
+/// current RVA. Lastly the Memory lists are added. For Memory List, this will
+/// contain everything that can fit within 4.2gb. MemoryList has it's
+/// descriptors written at the end so it cannot be allowed to overflow.
+///
+/// Memory64List is a special case where it has to be begin before 4.2gb but can
+/// expand forever The 
diff erence in Memory64List is there are no RVA's and all
+/// the addresses are figured out by starting at the base RVA, and adding the
+/// antecedent memory sections.
+///
+/// Because Memory64List can be arbitrarily large, this class has to write
+/// chunks to disk this means we have to precalculate the descriptors and write
+/// them first, and if we encounter any error, or are unable to read the same
+/// number of bytes we have to go back and update them on disk.
+///
+/// And as the last step, after all the directories have been added, we go back
+/// to the top of the file to fill in the header and the redirectory sections
+/// that we preallocated.
 class MinidumpFileBuilder {
 public:
-  MinidumpFileBuilder() = default;
+  MinidumpFileBuilder(lldb::FileUP &&core_file,
+                      const lldb::ProcessSP &process_sp)
+      : m_process_sp(process_sp), m_core_file(std::move(core_file)){};
 
   MinidumpFileBuilder(const MinidumpFileBuilder &) = delete;
   MinidumpFileBuilder &operator=(const MinidumpFileBuilder &) = delete;
@@ -50,48 +86,84 @@ class MinidumpFileBuilder {
 
   ~MinidumpFileBuilder() = default;
 
+  // This method only calculates the amount of bytes the header and directories
+  // will take up. It does not write the directories or headers. This function
+  // must be called with a followup to fill in the data.
+  lldb_private::Status AddHeaderAndCalculateDirectories();
   // Add SystemInfo stream, used for storing the most basic information
   // about the system, platform etc...
-  lldb_private::Status AddSystemInfo(const llvm::Triple &target_triple);
+  lldb_private::Status AddSystemInfo();
   // Add ModuleList stream, containing information about all loaded modules
   // at the time of saving minidump.
-  lldb_private::Status AddModuleList(lldb_private::Target &target);
+  lldb_private::Status AddModuleList();
   // Add ThreadList stream, containing information about all threads running
   // at the moment of core saving. Contains information about thread
   // contexts.
-  lldb_private::Status AddThreadList(const lldb::ProcessSP &process_sp);
+  lldb_private::Status AddThreadList();
   // Add Exception streams for any threads that stopped with exceptions.
-  void AddExceptions(const lldb::ProcessSP &process_sp);
+  lldb_private::Status AddExceptions();
   // Add MemoryList stream, containing dumps of important memory segments
-  lldb_private::Status AddMemoryList(const lldb::ProcessSP &process_sp,
-                                     lldb::SaveCoreStyle core_style);
+  lldb_private::Status AddMemoryList(lldb::SaveCoreStyle core_style);
   // Add MiscInfo stream, mainly providing ProcessId
-  void AddMiscInfo(const lldb::ProcessSP &process_sp);
+  lldb_private::Status AddMiscInfo();
   // Add informative files about a Linux process
-  void AddLinuxFileStreams(const lldb::ProcessSP &process_sp);
-  // Dump the prepared data into file. In case of the failure data are
-  // intact.
-  lldb_private::Status Dump(lldb::FileUP &core_file) const;
-  // Returns the current number of directories(streams) that have been so far
-  // created. This number of directories will be dumped when calling Dump()
-  size_t GetDirectoriesNum() const;
+  lldb_private::Status AddLinuxFileStreams();
+
+  // Run cleanup and write all remaining bytes to file
+  lldb_private::Status DumpFile();
 
 private:
+  // Add data to the end of the buffer, if the buffer exceeds the flush level,
+  // trigger a flush.
+  lldb_private::Status AddData(const void *data, uint64_t size);
+  // Add MemoryList stream, containing dumps of important memory segments
+  lldb_private::Status
+  AddMemoryList_64(lldb_private::Process::CoreFileMemoryRanges &ranges);
+  lldb_private::Status
+  AddMemoryList_32(lldb_private::Process::CoreFileMemoryRanges &ranges);
+  // Update the thread list on disk with the newly emitted stack RVAs.
+  lldb_private::Status FixThreadStacks();
+  lldb_private::Status FlushBufferToDisk();
+
+  lldb_private::Status DumpHeader() const;
+  lldb_private::Status DumpDirectories() const;
   // Add directory of StreamType pointing to the current end of the prepared
   // file with the specified size.
-  void AddDirectory(llvm::minidump::StreamType type, size_t stream_size);
-  size_t GetCurrentDataEndOffset() const;
-
-  // Stores directories to later put them at the end of minidump file
+  lldb_private::Status AddDirectory(llvm::minidump::StreamType type,
+                                    uint64_t stream_size);
+  lldb::offset_t GetCurrentDataEndOffset() const;
+  // Stores directories to fill in later
   std::vector<llvm::minidump::Directory> m_directories;
+  // When we write off the threads for the first time, we need to clean them up
+  // and give them the correct RVA once we write the stack memory list.
+  // We save by the end because we only take from the stack pointer up
+  // So the saved off range base can 
diff er from the memory region the stack
+  // pointer is in.
+  std::unordered_map<lldb::addr_t, llvm::minidump::Thread>
+      m_thread_by_range_end;
   // Main data buffer consisting of data without the minidump header and
   // directories
   lldb_private::DataBufferHeap m_data;
+  lldb::ProcessSP m_process_sp;
+
+  uint m_expected_directories = 0;
+  uint64_t m_saved_data_size = 0;
+  lldb::offset_t m_thread_list_start = 0;
+  // We set the max write amount to 128 mb, this is arbitrary
+  // but we want to try to keep the size of m_data small
+  // and we will only exceed a 128 mb buffer if we get a memory region
+  // that is larger than 128 mb.
+  static constexpr size_t MAX_WRITE_CHUNK_SIZE = (1024 * 1024 * 128);
+
+  static constexpr size_t HEADER_SIZE = sizeof(llvm::minidump::Header);
+  static constexpr size_t DIRECTORY_SIZE = sizeof(llvm::minidump::Directory);
 
   // More that one place can mention the register thread context locations,
   // so when we emit the thread contents, remember where it is so we don't have
   // to duplicate it in the exception data.
-  std::map<lldb::tid_t, llvm::minidump::LocationDescriptor> m_tid_to_reg_ctx;
+  std::unordered_map<lldb::tid_t, llvm::minidump::LocationDescriptor>
+      m_tid_to_reg_ctx;
+  lldb::FileUP m_core_file;
 };
 
 #endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_MINIDUMP_MINIDUMPFILEBUILDER_H

diff  --git a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp
index 1af5d99f0b160..3668c37c5191d 100644
--- a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp
+++ b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp
@@ -15,8 +15,10 @@
 #include "lldb/Core/Section.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
 
 #include "llvm/Support/FileSystem.h"
+#include <unistd.h>
 
 using namespace lldb;
 using namespace lldb_private;
@@ -65,56 +67,70 @@ bool ObjectFileMinidump::SaveCore(const lldb::ProcessSP &process_sp,
   if (!process_sp)
     return false;
 
-  MinidumpFileBuilder builder;
-
-  Target &target = process_sp->GetTarget();
+  llvm::Expected<lldb::FileUP> maybe_core_file = FileSystem::Instance().Open(
+      outfile, File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate);
+  if (!maybe_core_file) {
+    error = maybe_core_file.takeError();
+    return false;
+  }
+  MinidumpFileBuilder builder(std::move(maybe_core_file.get()), process_sp);
 
   Log *log = GetLog(LLDBLog::Object);
-  error = builder.AddSystemInfo(target.GetArchitecture().GetTriple());
+  error = builder.AddHeaderAndCalculateDirectories();
   if (error.Fail()) {
-    LLDB_LOG(log, "AddSystemInfo failed: %s", error.AsCString());
+    LLDB_LOGF(log, "AddHeaderAndCalculateDirectories failed: %s",
+              error.AsCString());
+    return false;
+  };
+  error = builder.AddSystemInfo();
+  if (error.Fail()) {
+    LLDB_LOGF(log, "AddSystemInfo failed: %s", error.AsCString());
     return false;
   }
 
-  error = builder.AddModuleList(target);
+  error = builder.AddModuleList();
   if (error.Fail()) {
-    LLDB_LOG(log, "AddModuleList failed: %s", error.AsCString());
+    LLDB_LOGF(log, "AddModuleList failed: %s", error.AsCString());
     return false;
   }
-
-  builder.AddMiscInfo(process_sp);
-
-  error = builder.AddThreadList(process_sp);
+  error = builder.AddMiscInfo();
   if (error.Fail()) {
-    LLDB_LOG(log, "AddThreadList failed: %s", error.AsCString());
+    LLDB_LOGF(log, "AddMiscInfo failed: %s", error.AsCString());
     return false;
   }
 
-  // Add any exceptions but only if there are any in any threads.
-  builder.AddExceptions(process_sp);
+  error = builder.AddThreadList();
+  if (error.Fail()) {
+    LLDB_LOGF(log, "AddThreadList failed: %s", error.AsCString());
+    return false;
+  }
 
-  error = builder.AddMemoryList(process_sp, core_style);
+  error = builder.AddLinuxFileStreams();
   if (error.Fail()) {
-    LLDB_LOG(log, "AddMemoryList failed: %s", error.AsCString());
+    LLDB_LOGF(log, "AddLinuxFileStreams failed: %s", error.AsCString());
     return false;
   }
 
-  if (target.GetArchitecture().GetTriple().getOS() ==
-      llvm::Triple::OSType::Linux) {
-    builder.AddLinuxFileStreams(process_sp);
+  // Add any exceptions but only if there are any in any threads.
+  error = builder.AddExceptions();
+  if (error.Fail()) {
+    LLDB_LOGF(log, "AddExceptions failed: %s", error.AsCString());
+    return false;
   }
 
-  llvm::Expected<lldb::FileUP> maybe_core_file = FileSystem::Instance().Open(
-      outfile, File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate);
-  if (!maybe_core_file) {
-    error = maybe_core_file.takeError();
+  // Note: add memory HAS to be the last thing we do. It can overflow into 64b
+  // land and many RVA's only support 32b
+  error = builder.AddMemoryList(core_style);
+  if (error.Fail()) {
+    LLDB_LOGF(log, "AddMemoryList failed: %s", error.AsCString());
     return false;
   }
-  lldb::FileUP core_file = std::move(maybe_core_file.get());
 
-  error = builder.Dump(core_file);
-  if (error.Fail())
+  error = builder.DumpFile();
+  if (error.Fail()) {
+    LLDB_LOGF(log, "DumpFile failed: %s", error.AsCString());
     return false;
+  }
 
   return true;
 }

diff  --git a/llvm/include/llvm/BinaryFormat/Minidump.h b/llvm/include/llvm/BinaryFormat/Minidump.h
index bc303929498d0..9669303252615 100644
--- a/llvm/include/llvm/BinaryFormat/Minidump.h
+++ b/llvm/include/llvm/BinaryFormat/Minidump.h
@@ -70,6 +70,11 @@ struct MemoryDescriptor {
 };
 static_assert(sizeof(MemoryDescriptor) == 16);
 
+struct MemoryDescriptor_64 {
+  support::ulittle64_t StartOfMemoryRange;
+  support::ulittle64_t DataSize;
+};
+
 struct MemoryInfoListHeader {
   support::ulittle32_t SizeOfHeader;
   support::ulittle32_t SizeOfEntry;


        


More information about the llvm-commits mailing list