<div dir="ltr">The new test fails under MSan:<div><br></div><div>Uninitialized bytes in __interceptor_write at offset 2 inside [0x7fb1f42ed000, 18438530)<br>==3871==WARNING: MemorySanitizer: use-of-uninitialized-value<br>    #0 0x55f5706515d9 in RetryAfterSignal<int, long (int, const void *, unsigned long), int, const void *, unsigned long> llvm-project/llvm/include/llvm/Support/Errno.h:38:11<br>    #1 0x55f5706515d9 in lldb_private::NativeFile::Write(void const*, unsigned long&) llvm-project/lldb/source/Host/common/File.cpp:585:9<br>    #2 0x55f570badbf5 in MinidumpFileBuilder::Dump(std::__msan::unique_ptr<lldb_private::File, std::__msan::default_delete<lldb_private::File> >&) const llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp:739:22<br>    #3 0x55f570bb075c in ObjectFileMinidump::SaveCore(std::__msan::shared_ptr<lldb_private::Process> const&, lldb_private::FileSpec const&, lldb::SaveCoreStyle&, lldb_private::Status&)  llvm-project/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp:114:19<br>    #4 0x55f57048960b in lldb_private::PluginManager::SaveCore(std::__msan::shared_ptr<lldb_private::Process> const&, lldb_private::FileSpec const&, lldb::SaveCoreStyle&, lldb_private::ConstString)  llvm-project/lldb/source/Core/PluginManager.cpp:696:9<br></div><div><br></div><div>Please can you take a look?</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, 1 Sept 2021 at 06:19, Andy Yankovsky via lldb-commits <<a href="mailto:lldb-commits@lists.llvm.org">lldb-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><br>
Author: Andrej Korman<br>
Date: 2021-09-01T15:14:29+02:00<br>
New Revision: eee687a66d76bf0b6e3746f7b8d09b0d871bff27<br>
<br>
URL: <a href="https://github.com/llvm/llvm-project/commit/eee687a66d76bf0b6e3746f7b8d09b0d871bff27" rel="noreferrer" target="_blank">https://github.com/llvm/llvm-project/commit/eee687a66d76bf0b6e3746f7b8d09b0d871bff27</a><br>
DIFF: <a href="https://github.com/llvm/llvm-project/commit/eee687a66d76bf0b6e3746f7b8d09b0d871bff27.diff" rel="noreferrer" target="_blank">https://github.com/llvm/llvm-project/commit/eee687a66d76bf0b6e3746f7b8d09b0d871bff27.diff</a><br>
<br>
LOG: [lldb] Add minidump save-core functionality to ELF object files<br>
<br>
This change adds save-core functionality into the ObjectFileELF that enables<br>
saving minidump of a stopped process. This change is mainly targeting Linux<br>
running on x86_64 machines. Minidump should contain basic information needed<br>
to examine state of threads, local variables and stack traces. Full support<br>
for other platforms is not so far implemented. API tests are using LLDB's<br>
MinidumpParser.<br>
<br>
This relands commit aafa05e, reverted in 1f986f6.<br>
Failed tests were fixed.<br>
<br>
Reviewed By: clayborg<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D108233" rel="noreferrer" target="_blank">https://reviews.llvm.org/D108233</a><br>
<br>
Added: <br>
    lldb/source/Plugins/ObjectFile/Minidump/CMakeLists.txt<br>
    lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp<br>
    lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h<br>
    lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp<br>
    lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.h<br>
    lldb/test/API/functionalities/process_save_core_minidump/Makefile<br>
    lldb/test/API/functionalities/process_save_core_minidump/TestProcessSaveCoreMinidump.py<br>
    lldb/test/API/functionalities/process_save_core_minidump/main.cpp<br>
<br>
Modified: <br>
    lldb/include/lldb/Core/PluginManager.h<br>
    lldb/source/API/SBProcess.cpp<br>
    lldb/source/Commands/CommandObjectProcess.cpp<br>
    lldb/source/Commands/Options.td<br>
    lldb/source/Core/PluginManager.cpp<br>
    lldb/source/Plugins/ObjectFile/CMakeLists.txt<br>
<br>
Removed: <br>
<br>
<br>
<br>
################################################################################<br>
diff  --git a/lldb/include/lldb/Core/PluginManager.h b/lldb/include/lldb/Core/PluginManager.h<br>
index be91929c62e13..2bee2edea6360 100644<br>
--- a/lldb/include/lldb/Core/PluginManager.h<br>
+++ b/lldb/include/lldb/Core/PluginManager.h<br>
@@ -192,7 +192,8 @@ class PluginManager {<br>
<br>
   static Status SaveCore(const lldb::ProcessSP &process_sp,<br>
                          const FileSpec &outfile,<br>
-                         lldb::SaveCoreStyle &core_style);<br>
+                         lldb::SaveCoreStyle &core_style,<br>
+                         const ConstString plugin_name);<br>
<br>
   // ObjectContainer<br>
   static bool<br>
<br>
diff  --git a/lldb/source/API/SBProcess.cpp b/lldb/source/API/SBProcess.cpp<br>
index 47c35a23b0781..a965814be1b98 100644<br>
--- a/lldb/source/API/SBProcess.cpp<br>
+++ b/lldb/source/API/SBProcess.cpp<br>
@@ -1228,7 +1228,8 @@ lldb::SBError SBProcess::SaveCore(const char *file_name) {<br>
<br>
   FileSpec core_file(file_name);<br>
   SaveCoreStyle core_style = SaveCoreStyle::eSaveCoreFull;<br>
-  error.ref() = PluginManager::SaveCore(process_sp, core_file, core_style);<br>
+  error.ref() =<br>
+      PluginManager::SaveCore(process_sp, core_file, core_style, ConstString());<br>
   return LLDB_RECORD_RESULT(error);<br>
 }<br>
<br>
<br>
diff  --git a/lldb/source/Commands/CommandObjectProcess.cpp b/lldb/source/Commands/CommandObjectProcess.cpp<br>
index bb6220a53d4e8..b3e2f6a1a02b7 100644<br>
--- a/lldb/source/Commands/CommandObjectProcess.cpp<br>
+++ b/lldb/source/Commands/CommandObjectProcess.cpp<br>
@@ -1180,12 +1180,13 @@ static constexpr OptionEnumValues SaveCoreStyles() {<br>
 class CommandObjectProcessSaveCore : public CommandObjectParsed {<br>
 public:<br>
   CommandObjectProcessSaveCore(CommandInterpreter &interpreter)<br>
-      : CommandObjectParsed(interpreter, "process save-core",<br>
-                            "Save the current process as a core file using an "<br>
-                            "appropriate file type.",<br>
-                            "process save-core [-s corefile-style] FILE",<br>
-                            eCommandRequiresProcess | eCommandTryTargetAPILock |<br>
-                                eCommandProcessMustBeLaunched) {}<br>
+      : CommandObjectParsed(<br>
+            interpreter, "process save-core",<br>
+            "Save the current process as a core file using an "<br>
+            "appropriate file type.",<br>
+            "process save-core [-s corefile-style -p plugin-name] FILE",<br>
+            eCommandRequiresProcess | eCommandTryTargetAPILock |<br>
+                eCommandProcessMustBeLaunched) {}<br>
<br>
   ~CommandObjectProcessSaveCore() override = default;<br>
<br>
@@ -1208,6 +1209,9 @@ class CommandObjectProcessSaveCore : public CommandObjectParsed {<br>
       Status error;<br>
<br>
       switch (short_option) {<br>
+      case 'p':<br>
+        m_requested_plugin_name.SetString(option_arg);<br>
+        break;<br>
       case 's':<br>
         m_requested_save_core_style =<br>
             (lldb::SaveCoreStyle)OptionArgParser::ToOptionEnum(<br>
@@ -1223,10 +1227,12 @@ class CommandObjectProcessSaveCore : public CommandObjectParsed {<br>
<br>
     void OptionParsingStarting(ExecutionContext *execution_context) override {<br>
       m_requested_save_core_style = eSaveCoreUnspecified;<br>
+      m_requested_plugin_name.Clear();<br>
     }<br>
<br>
     // Instance variables to hold the values for command options.<br>
     SaveCoreStyle m_requested_save_core_style;<br>
+    ConstString m_requested_plugin_name;<br>
   };<br>
<br>
 protected:<br>
@@ -1237,7 +1243,8 @@ class CommandObjectProcessSaveCore : public CommandObjectParsed {<br>
         FileSpec output_file(command.GetArgumentAtIndex(0));<br>
         SaveCoreStyle corefile_style = m_options.m_requested_save_core_style;<br>
         Status error =<br>
-            PluginManager::SaveCore(process_sp, output_file, corefile_style);<br>
+            PluginManager::SaveCore(process_sp, output_file, corefile_style,<br>
+                                    m_options.m_requested_plugin_name);<br>
         if (error.Success()) {<br>
           if (corefile_style == SaveCoreStyle::eSaveCoreDirtyOnly ||<br>
               corefile_style == SaveCoreStyle::eSaveCoreStackOnly) {<br>
<br>
diff  --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td<br>
index 5cef8f93b6989..67cfc60f9d1b5 100644<br>
--- a/lldb/source/Commands/Options.td<br>
+++ b/lldb/source/Commands/Options.td<br>
@@ -749,6 +749,9 @@ let Command = "process save_core" in {<br>
   def process_save_core_style : Option<"style", "s">, Group<1>,<br>
     EnumArg<"SaveCoreStyle", "SaveCoreStyles()">, Desc<"Request a specific style "<br>
     "of corefile to be saved.">;<br>
+  def process_save_core_plugin_name : Option<"plugin-name", "p">,<br>
+    OptionalArg<"Plugin">, Desc<"Specify a plugin name to create the core file."<br>
+    "This allows core files to be saved in <br>
diff erent formats.">;<br>
 }<br>
<br>
 let Command = "process trace save" in {<br>
<br>
diff  --git a/lldb/source/Core/PluginManager.cpp b/lldb/source/Core/PluginManager.cpp<br>
index fcaa868b083ed..f65ec9fae277f 100644<br>
--- a/lldb/source/Core/PluginManager.cpp<br>
+++ b/lldb/source/Core/PluginManager.cpp<br>
@@ -685,10 +685,13 @@ PluginManager::GetObjectFileCreateMemoryCallbackForPluginName(<br>
<br>
 Status PluginManager::SaveCore(const lldb::ProcessSP &process_sp,<br>
                                const FileSpec &outfile,<br>
-                               lldb::SaveCoreStyle &core_style) {<br>
+                               lldb::SaveCoreStyle &core_style,<br>
+                               const ConstString plugin_name) {<br>
   Status error;<br>
   auto &instances = GetObjectFileInstances().GetInstances();<br>
   for (auto &instance : instances) {<br>
+    if (plugin_name && <a href="http://instance.name" rel="noreferrer" target="_blank">instance.name</a> != plugin_name)<br>
+      continue;<br>
     if (instance.save_core &&<br>
         instance.save_core(process_sp, outfile, core_style, error))<br>
       return error;<br>
<br>
diff  --git a/lldb/source/Plugins/ObjectFile/CMakeLists.txt b/lldb/source/Plugins/ObjectFile/CMakeLists.txt<br>
index 3b2cc6177d313..34ad087173f01 100644<br>
--- a/lldb/source/Plugins/ObjectFile/CMakeLists.txt<br>
+++ b/lldb/source/Plugins/ObjectFile/CMakeLists.txt<br>
@@ -1,6 +1,7 @@<br>
 add_subdirectory(Breakpad)<br>
 add_subdirectory(ELF)<br>
 add_subdirectory(Mach-O)<br>
+add_subdirectory(Minidump)<br>
 add_subdirectory(PDB)<br>
 add_subdirectory(PECOFF)<br>
 add_subdirectory(JIT)<br>
<br>
diff  --git a/lldb/source/Plugins/ObjectFile/Minidump/CMakeLists.txt b/lldb/source/Plugins/ObjectFile/Minidump/CMakeLists.txt<br>
new file mode 100644<br>
index 0000000000000..ac5fba200f351<br>
--- /dev/null<br>
+++ b/lldb/source/Plugins/ObjectFile/Minidump/CMakeLists.txt<br>
@@ -0,0 +1,14 @@<br>
+add_lldb_library(lldbPluginObjectFileMinidump PLUGIN<br>
+  ObjectFileMinidump.cpp<br>
+  MinidumpFileBuilder.cpp<br>
+<br>
+  LINK_LIBS<br>
+    lldbCore<br>
+    lldbHost<br>
+    lldbSymbol<br>
+    lldbTarget<br>
+    lldbUtility<br>
+    lldbPluginProcessUtility<br>
+  LINK_COMPONENTS<br>
+    Support<br>
+  )<br>
<br>
diff  --git a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp<br>
new file mode 100644<br>
index 0000000000000..1f9c96013ebff<br>
--- /dev/null<br>
+++ b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp<br>
@@ -0,0 +1,770 @@<br>
+//===-- MinidumpFileBuilder.cpp -------------------------------------------===//<br>
+//<br>
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.<br>
+// See <a href="https://llvm.org/LICENSE.txt" rel="noreferrer" target="_blank">https://llvm.org/LICENSE.txt</a> for license information.<br>
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#include "MinidumpFileBuilder.h"<br>
+<br>
+#include "Plugins/Process/minidump/RegisterContextMinidump_x86_64.h"<br>
+<br>
+#include "lldb/Core/Module.h"<br>
+#include "lldb/Core/ModuleList.h"<br>
+#include "lldb/Core/Section.h"<br>
+#include "lldb/Target/MemoryRegionInfo.h"<br>
+#include "lldb/Target/Process.h"<br>
+#include "lldb/Target/RegisterContext.h"<br>
+#include "lldb/Target/StopInfo.h"<br>
+#include "lldb/Target/ThreadList.h"<br>
+#include "lldb/Utility/DataExtractor.h"<br>
+#include "lldb/Utility/RegisterValue.h"<br>
+<br>
+#include "llvm/ADT/StringRef.h"<br>
+#include "llvm/BinaryFormat/Minidump.h"<br>
+#include "llvm/Support/ConvertUTF.h"<br>
+#include "llvm/Support/Error.h"<br>
+<br>
+#include "Plugins/Process/minidump/MinidumpTypes.h"<br>
+<br>
+using namespace lldb;<br>
+using namespace lldb_private;<br>
+using namespace llvm::minidump;<br>
+<br>
+void MinidumpFileBuilder::AddDirectory(StreamType type, size_t stream_size) {<br>
+  LocationDescriptor loc;<br>
+  loc.DataSize = static_cast<llvm::support::ulittle32_t>(stream_size);<br>
+  // Stream will begin at the current end of data section<br>
+  loc.RVA = static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset());<br>
+<br>
+  Directory dir;<br>
+  dir.Type = static_cast<llvm::support::little_t<StreamType>>(type);<br>
+  dir.Location = loc;<br>
+<br>
+  m_directories.push_back(dir);<br>
+}<br>
+<br>
+Status MinidumpFileBuilder::AddSystemInfo(const llvm::Triple &target_triple) {<br>
+  Status error;<br>
+  AddDirectory(StreamType::SystemInfo, sizeof(llvm::minidump::SystemInfo));<br>
+<br>
+  llvm::minidump::ProcessorArchitecture arch;<br>
+  switch (target_triple.getArch()) {<br>
+  case llvm::Triple::ArchType::x86_64:<br>
+    arch = ProcessorArchitecture::AMD64;<br>
+    break;<br>
+  case llvm::Triple::ArchType::x86:<br>
+    arch = ProcessorArchitecture::X86;<br>
+    break;<br>
+  case llvm::Triple::ArchType::arm:<br>
+    arch = ProcessorArchitecture::ARM;<br>
+    break;<br>
+  case llvm::Triple::ArchType::aarch64:<br>
+    arch = ProcessorArchitecture::ARM64;<br>
+    break;<br>
+  case llvm::Triple::ArchType::mips64:<br>
+  case llvm::Triple::ArchType::mips64el:<br>
+  case llvm::Triple::ArchType::mips:<br>
+  case llvm::Triple::ArchType::mipsel:<br>
+    arch = ProcessorArchitecture::MIPS;<br>
+    break;<br>
+  case llvm::Triple::ArchType::ppc64:<br>
+  case llvm::Triple::ArchType::ppc:<br>
+  case llvm::Triple::ArchType::ppc64le:<br>
+    arch = ProcessorArchitecture::PPC;<br>
+    break;<br>
+  default:<br>
+    error.SetErrorStringWithFormat("Architecture %s not supported.",<br>
+                                   target_triple.getArchName().str().c_str());<br>
+    return error;<br>
+  };<br>
+<br>
+  llvm::support::little_t<OSPlatform> platform_id;<br>
+  switch (target_triple.getOS()) {<br>
+  case llvm::Triple::OSType::Linux:<br>
+    if (target_triple.getEnvironment() ==<br>
+        llvm::Triple::EnvironmentType::Android)<br>
+      platform_id = OSPlatform::Android;<br>
+    else<br>
+      platform_id = OSPlatform::Linux;<br>
+    break;<br>
+  case llvm::Triple::OSType::Win32:<br>
+    platform_id = OSPlatform::Win32NT;<br>
+    break;<br>
+  case llvm::Triple::OSType::MacOSX:<br>
+    platform_id = OSPlatform::MacOSX;<br>
+    break;<br>
+  case llvm::Triple::OSType::IOS:<br>
+    platform_id = OSPlatform::IOS;<br>
+    break;<br>
+  default:<br>
+    error.SetErrorStringWithFormat("OS %s not supported.",<br>
+                                   target_triple.getOSName().str().c_str());<br>
+    return error;<br>
+  };<br>
+<br>
+  llvm::minidump::SystemInfo sys_info;<br>
+  sys_info.ProcessorArch =<br>
+      static_cast<llvm::support::little_t<ProcessorArchitecture>>(arch);<br>
+  // Global offset to beginning of a csd_string in a data section<br>
+  sys_info.CSDVersionRVA = static_cast<llvm::support::ulittle32_t>(<br>
+      GetCurrentDataEndOffset() + sizeof(llvm::minidump::SystemInfo));<br>
+  sys_info.PlatformId = platform_id;<br>
+  m_data.AppendData(&sys_info, sizeof(llvm::minidump::SystemInfo));<br>
+<br>
+  std::string csd_string = "";<br>
+<br>
+  error = WriteString(csd_string, &m_data);<br>
+  if (error.Fail()) {<br>
+    error.SetErrorString("Unable to convert the csd string to UTF16.");<br>
+    return error;<br>
+  }<br>
+<br>
+  return error;<br>
+}<br>
+<br>
+Status WriteString(const std::string &to_write,<br>
+                   lldb_private::DataBufferHeap *buffer) {<br>
+  Status error;<br>
+  // let the StringRef eat also null termination char<br>
+  llvm::StringRef to_write_ref(to_write.c_str(), to_write.size() + 1);<br>
+  llvm::SmallVector<llvm::UTF16, 128> to_write_utf16;<br>
+<br>
+  bool converted = convertUTF8ToUTF16String(to_write_ref, to_write_utf16);<br>
+  if (!converted) {<br>
+    error.SetErrorStringWithFormat(<br>
+        "Unable to convert the string to UTF16. Failed to convert %s",<br>
+        to_write.c_str());<br>
+    return error;<br>
+  }<br>
+<br>
+  // size of the UTF16 string should be written without the null termination<br>
+  // character that is stored in 2 bytes<br>
+  llvm::support::ulittle32_t to_write_size(to_write_utf16.size_in_bytes() - 2);<br>
+<br>
+  buffer->AppendData(&to_write_size, sizeof(llvm::support::ulittle32_t));<br>
+  buffer->AppendData(to_write_utf16.data(), to_write_utf16.size_in_bytes());<br>
+<br>
+  return error;<br>
+}<br>
+<br>
+llvm::Expected<uint64_t> getModuleFileSize(Target &target,<br>
+                                           const ModuleSP &mod) {<br>
+  SectionSP sect_sp = mod->GetObjectFile()->GetBaseAddress().GetSection();<br>
+  uint64_t SizeOfImage = 0;<br>
+<br>
+  if (!sect_sp) {<br>
+    return llvm::createStringError(std::errc::operation_not_supported,<br>
+                                   "Couldn't obtain the section information.");<br>
+  }<br>
+  lldb::addr_t sect_addr = sect_sp->GetLoadBaseAddress(&target);<br>
+  // Use memory size since zero fill sections, like ".bss", will be smaller on<br>
+  // disk.<br>
+  lldb::addr_t sect_size = sect_sp->GetByteSize();<br>
+  // This will usually be zero, but make sure to calculate the BaseOfImage<br>
+  // offset.<br>
+  const lldb::addr_t base_sect_offset =<br>
+      mod->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target) -<br>
+      sect_addr;<br>
+  SizeOfImage = sect_size - base_sect_offset;<br>
+  lldb::addr_t next_sect_addr = sect_addr + sect_size;<br>
+  Address sect_so_addr;<br>
+  target.ResolveLoadAddress(next_sect_addr, sect_so_addr);<br>
+  lldb::SectionSP next_sect_sp = sect_so_addr.GetSection();<br>
+  while (next_sect_sp &&<br>
+         next_sect_sp->GetLoadBaseAddress(&target) == next_sect_addr) {<br>
+    sect_size = sect_sp->GetByteSize();<br>
+    SizeOfImage += sect_size;<br>
+    next_sect_addr += sect_size;<br>
+    target.ResolveLoadAddress(next_sect_addr, sect_so_addr);<br>
+    next_sect_sp = sect_so_addr.GetSection();<br>
+  }<br>
+<br>
+  return SizeOfImage;<br>
+}<br>
+<br>
+// ModuleList stream consists of a number of modules, followed by an array<br>
+// of llvm::minidump::Module's structures. Every structure informs about a<br>
+// single module. Additional data of variable length, such as module's names,<br>
+// are stored just after the ModuleList stream. The llvm::minidump::Module<br>
+// structures point to this helper data by global offset.<br>
+Status MinidumpFileBuilder::AddModuleList(Target &target) {<br>
+  constexpr size_t minidump_module_size = sizeof(llvm::minidump::Module);<br>
+  Status error;<br>
+<br>
+  const ModuleList &modules = target.GetImages();<br>
+  llvm::support::ulittle32_t modules_count =<br>
+      static_cast<llvm::support::ulittle32_t>(modules.GetSize());<br>
+<br>
+  // This helps us with getting the correct global offset in minidump<br>
+  // file later, when we will be setting up offsets from the<br>
+  // the llvm::minidump::Module's structures into helper data<br>
+  size_t size_before = GetCurrentDataEndOffset();<br>
+<br>
+  // This is the size of the main part of the ModuleList stream.<br>
+  // It consists of a module number and corresponding number of<br>
+  // structs describing individual modules<br>
+  size_t module_stream_size =<br>
+      sizeof(llvm::support::ulittle32_t) + modules_count * minidump_module_size;<br>
+<br>
+  // Adding directory describing this stream.<br>
+  AddDirectory(StreamType::ModuleList, module_stream_size);<br>
+<br>
+  m_data.AppendData(&modules_count, sizeof(llvm::support::ulittle32_t));<br>
+<br>
+  // Temporary storage for the helper data (of variable length)<br>
+  // as these cannot be dumped to m_data before dumping entire<br>
+  // array of module structures.<br>
+  DataBufferHeap helper_data;<br>
+<br>
+  for (size_t i = 0; i < modules_count; ++i) {<br>
+    ModuleSP mod = modules.GetModuleAtIndex(i);<br>
+    std::string module_name = mod->GetSpecificationDescription();<br>
+    auto maybe_mod_size = getModuleFileSize(target, mod);<br>
+    if (!maybe_mod_size) {<br>
+      error.SetErrorStringWithFormat("Unable to get the size of module %s.",<br>
+                                     module_name.c_str());<br>
+      return error;<br>
+    }<br>
+<br>
+    uint64_t mod_size = std::move(*maybe_mod_size);<br>
+<br>
+    llvm::support::ulittle32_t signature =<br>
+        static_cast<llvm::support::ulittle32_t>(<br>
+            static_cast<uint32_t>(minidump::CvSignature::ElfBuildId));<br>
+    auto uuid = mod->GetUUID().GetBytes();<br>
+<br>
+    VSFixedFileInfo info;<br>
+    info.Signature = static_cast<llvm::support::ulittle32_t>(0u);<br>
+    info.StructVersion = static_cast<llvm::support::ulittle32_t>(0u);<br>
+    info.FileVersionHigh = static_cast<llvm::support::ulittle32_t>(0u);<br>
+    info.FileVersionLow = static_cast<llvm::support::ulittle32_t>(0u);<br>
+    info.ProductVersionHigh = static_cast<llvm::support::ulittle32_t>(0u);<br>
+    info.ProductVersionLow = static_cast<llvm::support::ulittle32_t>(0u);<br>
+    info.FileFlagsMask = static_cast<llvm::support::ulittle32_t>(0u);<br>
+    info.FileFlags = static_cast<llvm::support::ulittle32_t>(0u);<br>
+    info.FileOS = static_cast<llvm::support::ulittle32_t>(0u);<br>
+    info.FileType = static_cast<llvm::support::ulittle32_t>(0u);<br>
+    info.FileSubtype = static_cast<llvm::support::ulittle32_t>(0u);<br>
+    info.FileDateHigh = static_cast<llvm::support::ulittle32_t>(0u);<br>
+    info.FileDateLow = static_cast<llvm::support::ulittle32_t>(0u);<br>
+<br>
+    LocationDescriptor ld;<br>
+    ld.DataSize = static_cast<llvm::support::ulittle32_t>(0u);<br>
+    ld.RVA = static_cast<llvm::support::ulittle32_t>(0u);<br>
+<br>
+    // Setting up LocationDescriptor for uuid string. The global offset into<br>
+    // minidump file is calculated.<br>
+    LocationDescriptor ld_cv;<br>
+    ld_cv.DataSize = static_cast<llvm::support::ulittle32_t>(<br>
+        sizeof(llvm::support::ulittle32_t) + uuid.size());<br>
+    ld_cv.RVA = static_cast<llvm::support::ulittle32_t>(<br>
+        size_before + module_stream_size + helper_data.GetByteSize());<br>
+<br>
+    helper_data.AppendData(&signature, sizeof(llvm::support::ulittle32_t));<br>
+    helper_data.AppendData(uuid.begin(), uuid.size());<br>
+<br>
+    llvm::minidump::Module m;<br>
+    m.BaseOfImage = static_cast<llvm::support::ulittle64_t>(<br>
+        mod->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target));<br>
+    m.SizeOfImage = static_cast<llvm::support::ulittle32_t>(mod_size);<br>
+    m.Checksum = static_cast<llvm::support::ulittle32_t>(0);<br>
+    m.TimeDateStamp = static_cast<llvm::support::ulittle32_t>(std::time(0));<br>
+    m.ModuleNameRVA = static_cast<llvm::support::ulittle32_t>(<br>
+        size_before + module_stream_size + helper_data.GetByteSize());<br>
+    m.VersionInfo = info;<br>
+    m.CvRecord = ld_cv;<br>
+    m.MiscRecord = ld;<br>
+<br>
+    error = WriteString(module_name, &helper_data);<br>
+<br>
+    if (error.Fail())<br>
+      return error;<br>
+<br>
+    m_data.AppendData(&m, sizeof(llvm::minidump::Module));<br>
+  }<br>
+<br>
+  m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize());<br>
+  return error;<br>
+}<br>
+<br>
+uint16_t read_register_u16_raw(RegisterContext *reg_ctx,<br>
+                               const std::string &reg_name) {<br>
+  const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);<br>
+  if (!reg_info)<br>
+    return 0;<br>
+  lldb_private::RegisterValue reg_value;<br>
+  bool success = reg_ctx->ReadRegister(reg_info, reg_value);<br>
+  if (!success)<br>
+    return 0;<br>
+  return reg_value.GetAsUInt16();<br>
+}<br>
+<br>
+uint32_t read_register_u32_raw(RegisterContext *reg_ctx,<br>
+                               const std::string &reg_name) {<br>
+  const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);<br>
+  if (!reg_info)<br>
+    return 0;<br>
+  lldb_private::RegisterValue reg_value;<br>
+  bool success = reg_ctx->ReadRegister(reg_info, reg_value);<br>
+  if (!success)<br>
+    return 0;<br>
+  return reg_value.GetAsUInt32();<br>
+}<br>
+<br>
+uint64_t read_register_u64_raw(RegisterContext *reg_ctx,<br>
+                               const std::string &reg_name) {<br>
+  const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);<br>
+  if (!reg_info)<br>
+    return 0;<br>
+  lldb_private::RegisterValue reg_value;<br>
+  bool success = reg_ctx->ReadRegister(reg_info, reg_value);<br>
+  if (!success)<br>
+    return 0;<br>
+  return reg_value.GetAsUInt64();<br>
+}<br>
+<br>
+llvm::support::ulittle16_t read_register_u16(RegisterContext *reg_ctx,<br>
+                                             const std::string &reg_name) {<br>
+  return static_cast<llvm::support::ulittle16_t>(<br>
+      read_register_u16_raw(reg_ctx, reg_name));<br>
+}<br>
+<br>
+llvm::support::ulittle32_t read_register_u32(RegisterContext *reg_ctx,<br>
+                                             const std::string &reg_name) {<br>
+  return static_cast<llvm::support::ulittle32_t>(<br>
+      read_register_u32_raw(reg_ctx, reg_name));<br>
+}<br>
+<br>
+llvm::support::ulittle64_t read_register_u64(RegisterContext *reg_ctx,<br>
+                                             const std::string &reg_name) {<br>
+  return static_cast<llvm::support::ulittle64_t>(<br>
+      read_register_u64_raw(reg_ctx, reg_name));<br>
+}<br>
+<br>
+lldb_private::minidump::MinidumpContext_x86_64<br>
+GetThreadContext_64(RegisterContext *reg_ctx) {<br>
+  lldb_private::minidump::MinidumpContext_x86_64 thread_context;<br>
+  thread_context.context_flags = static_cast<uint32_t>(<br>
+      lldb_private::minidump::MinidumpContext_x86_64_Flags::x86_64_Flag |<br>
+      lldb_private::minidump::MinidumpContext_x86_64_Flags::Control |<br>
+      lldb_private::minidump::MinidumpContext_x86_64_Flags::Segments |<br>
+      lldb_private::minidump::MinidumpContext_x86_64_Flags::Integer);<br>
+  thread_context.rax = read_register_u64(reg_ctx, "rax");<br>
+  thread_context.rbx = read_register_u64(reg_ctx, "rbx");<br>
+  thread_context.rcx = read_register_u64(reg_ctx, "rcx");<br>
+  thread_context.rdx = read_register_u64(reg_ctx, "rdx");<br>
+  thread_context.rdi = read_register_u64(reg_ctx, "rdi");<br>
+  thread_context.rsi = read_register_u64(reg_ctx, "rsi");<br>
+  thread_context.rbp = read_register_u64(reg_ctx, "rbp");<br>
+  thread_context.rsp = read_register_u64(reg_ctx, "rsp");<br>
+  thread_context.r8 = read_register_u64(reg_ctx, "r8");<br>
+  thread_context.r9 = read_register_u64(reg_ctx, "r9");<br>
+  thread_context.r10 = read_register_u64(reg_ctx, "r10");<br>
+  thread_context.r11 = read_register_u64(reg_ctx, "r11");<br>
+  thread_context.r12 = read_register_u64(reg_ctx, "r12");<br>
+  thread_context.r13 = read_register_u64(reg_ctx, "r13");<br>
+  thread_context.r14 = read_register_u64(reg_ctx, "r14");<br>
+  thread_context.r15 = read_register_u64(reg_ctx, "r15");<br>
+  thread_context.rip = read_register_u64(reg_ctx, "rip");<br>
+  thread_context.eflags = read_register_u32(reg_ctx, "rflags");<br>
+  thread_context.cs = read_register_u16(reg_ctx, "cs");<br>
+  thread_context.fs = read_register_u16(reg_ctx, "fs");<br>
+  <a href="http://thread_context.gs" rel="noreferrer" target="_blank">thread_context.gs</a> = read_register_u16(reg_ctx, "gs");<br>
+  thread_context.ss = read_register_u16(reg_ctx, "ss");<br>
+  thread_context.ds = read_register_u16(reg_ctx, "ds");<br>
+  return thread_context;<br>
+}<br>
+<br>
+// Function returns start and size of the memory region that contains<br>
+// memory location pointed to by the current stack pointer.<br>
+llvm::Expected<std::pair<addr_t, addr_t>><br>
+findStackHelper(const lldb::ProcessSP &process_sp, uint64_t rsp) {<br>
+  MemoryRegionInfo range_info;<br>
+  Status error = process_sp->GetMemoryRegionInfo(rsp, range_info);<br>
+  // Skip failed memory region requests or any regions with no permissions.<br>
+  if (error.Fail() || range_info.GetLLDBPermissions() == 0)<br>
+    return llvm::createStringError(<br>
+        std::errc::not_supported,<br>
+        "unable to load stack segment of the process");<br>
+<br>
+  const addr_t addr = range_info.GetRange().GetRangeBase();<br>
+  const addr_t size = range_info.GetRange().GetByteSize();<br>
+<br>
+  if (size == 0)<br>
+    return llvm::createStringError(std::errc::not_supported,<br>
+                                   "stack segment of the process is empty");<br>
+<br>
+  return std::make_pair(addr, size);<br>
+}<br>
+<br>
+Status MinidumpFileBuilder::AddThreadList(const lldb::ProcessSP &process_sp) {<br>
+  constexpr size_t minidump_thread_size = sizeof(llvm::minidump::Thread);<br>
+  lldb_private::ThreadList thread_list = process_sp->GetThreadList();<br>
+<br>
+  // size of the entire thread stream consists of:<br>
+  // number of threads and threads array<br>
+  size_t thread_stream_size = sizeof(llvm::support::ulittle32_t) +<br>
+                              thread_list.GetSize() * minidump_thread_size;<br>
+  // save for the ability to set up RVA<br>
+  size_t size_before = GetCurrentDataEndOffset();<br>
+<br>
+  AddDirectory(StreamType::ThreadList, thread_stream_size);<br>
+<br>
+  llvm::support::ulittle32_t thread_count =<br>
+      static_cast<llvm::support::ulittle32_t>(thread_list.GetSize());<br>
+  m_data.AppendData(&thread_count, sizeof(llvm::support::ulittle32_t));<br>
+<br>
+  DataBufferHeap helper_data;<br>
+<br>
+  const uint32_t num_threads = thread_list.GetSize();<br>
+<br>
+  for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {<br>
+    ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx));<br>
+    RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());<br>
+    Status error;<br>
+<br>
+    if (!reg_ctx_sp) {<br>
+      error.SetErrorString("Unable to get the register context.");<br>
+      return error;<br>
+    }<br>
+    RegisterContext *reg_ctx = reg_ctx_sp.get();<br>
+    auto thread_context = GetThreadContext_64(reg_ctx);<br>
+    uint64_t rsp = read_register_u64_raw(reg_ctx, "rsp");<br>
+    auto expected_address_range = findStackHelper(process_sp, rsp);<br>
+<br>
+    if (!expected_address_range) {<br>
+      error.SetErrorString("Unable to get the stack address.");<br>
+      return error;<br>
+    }<br>
+<br>
+    std::pair<uint64_t, uint64_t> range = std::move(*expected_address_range);<br>
+    uint64_t addr = range.first;<br>
+    uint64_t size = range.second;<br>
+<br>
+    auto data_up = std::make_unique<DataBufferHeap>(size, 0);<br>
+    const size_t stack_bytes_read =<br>
+        process_sp->ReadMemory(addr, data_up->GetBytes(), size, error);<br>
+<br>
+    if (error.Fail())<br>
+      return error;<br>
+<br>
+    LocationDescriptor stack_memory;<br>
+    stack_memory.DataSize =<br>
+        static_cast<llvm::support::ulittle32_t>(stack_bytes_read);<br>
+    stack_memory.RVA = static_cast<llvm::support::ulittle32_t>(<br>
+        size_before + thread_stream_size + helper_data.GetByteSize());<br>
+<br>
+    MemoryDescriptor stack;<br>
+    stack.StartOfMemoryRange = static_cast<llvm::support::ulittle64_t>(addr);<br>
+    stack.Memory = stack_memory;<br>
+<br>
+    helper_data.AppendData(data_up->GetBytes(), stack_bytes_read);<br>
+<br>
+    LocationDescriptor thread_context_memory_locator;<br>
+    thread_context_memory_locator.DataSize =<br>
+        static_cast<llvm::support::ulittle32_t>(sizeof(thread_context));<br>
+    thread_context_memory_locator.RVA = static_cast<llvm::support::ulittle32_t>(<br>
+        size_before + thread_stream_size + helper_data.GetByteSize());<br>
+<br>
+    helper_data.AppendData(<br>
+        &thread_context,<br>
+        sizeof(lldb_private::minidump::MinidumpContext_x86_64));<br>
+<br>
+    llvm::minidump::Thread t;<br>
+    t.ThreadId = static_cast<llvm::support::ulittle32_t>(thread_sp->GetID());<br>
+    t.SuspendCount = static_cast<llvm::support::ulittle32_t>(<br>
+        (thread_sp->GetState() == StateType::eStateSuspended) ? 1 : 0);<br>
+    t.PriorityClass = static_cast<llvm::support::ulittle32_t>(0);<br>
+    t.Priority = static_cast<llvm::support::ulittle32_t>(0);<br>
+    t.EnvironmentBlock = static_cast<llvm::support::ulittle64_t>(0);<br>
+    t.Stack = stack, t.Context = thread_context_memory_locator;<br>
+<br>
+    m_data.AppendData(&t, sizeof(llvm::minidump::Thread));<br>
+  }<br>
+<br>
+  m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize());<br>
+  return Status();<br>
+}<br>
+<br>
+Status MinidumpFileBuilder::AddException(const lldb::ProcessSP &process_sp) {<br>
+  Status error;<br>
+  lldb_private::ThreadList thread_list = process_sp->GetThreadList();<br>
+<br>
+  const uint32_t num_threads = thread_list.GetSize();<br>
+  uint32_t stop_reason_thread_idx = 0;<br>
+  for (stop_reason_thread_idx = 0; stop_reason_thread_idx < num_threads;<br>
+       ++stop_reason_thread_idx) {<br>
+    ThreadSP thread_sp(thread_list.GetThreadAtIndex(stop_reason_thread_idx));<br>
+    StopInfoSP stop_info_sp = thread_sp->GetStopInfo();<br>
+<br>
+    if (stop_info_sp && stop_info_sp->IsValid())<br>
+      break;<br>
+  }<br>
+<br>
+  if (stop_reason_thread_idx == num_threads) {<br>
+    error.SetErrorString("No stop reason thread found.");<br>
+    return error;<br>
+  }<br>
+<br>
+  constexpr size_t minidump_exception_size =<br>
+      sizeof(llvm::minidump::ExceptionStream);<br>
+  AddDirectory(StreamType::Exception, minidump_exception_size);<br>
+  size_t size_before = GetCurrentDataEndOffset();<br>
+<br>
+  ThreadSP thread_sp(thread_list.GetThreadAtIndex(stop_reason_thread_idx));<br>
+  RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());<br>
+  RegisterContext *reg_ctx = reg_ctx_sp.get();<br>
+  auto thread_context = GetThreadContext_64(reg_ctx);<br>
+  StopInfoSP stop_info_sp = thread_sp->GetStopInfo();<br>
+<br>
+  DataBufferHeap helper_data;<br>
+<br>
+  LocationDescriptor thread_context_memory_locator;<br>
+  thread_context_memory_locator.DataSize =<br>
+      static_cast<llvm::support::ulittle32_t>(sizeof(thread_context));<br>
+  thread_context_memory_locator.RVA = static_cast<llvm::support::ulittle32_t>(<br>
+      size_before + minidump_exception_size + helper_data.GetByteSize());<br>
+<br>
+  helper_data.AppendData(<br>
+      &thread_context, sizeof(lldb_private::minidump::MinidumpContext_x86_64));<br>
+<br>
+  Exception exp_record;<br>
+  exp_record.ExceptionCode =<br>
+      static_cast<llvm::support::ulittle32_t>(stop_info_sp->GetValue());<br>
+  exp_record.ExceptionFlags = static_cast<llvm::support::ulittle32_t>(0);<br>
+  exp_record.ExceptionRecord = static_cast<llvm::support::ulittle64_t>(0);<br>
+  exp_record.ExceptionAddress = read_register_u64(reg_ctx, "rip");<br>
+  exp_record.NumberParameters = static_cast<llvm::support::ulittle32_t>(0);<br>
+  exp_record.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0);<br>
+  // exp_record.ExceptionInformation;<br>
+<br>
+  ExceptionStream exp_stream;<br>
+  exp_stream.ThreadId =<br>
+      static_cast<llvm::support::ulittle32_t>(thread_sp->GetID());<br>
+  exp_stream.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0);<br>
+  exp_stream.ExceptionRecord = exp_record;<br>
+  exp_stream.ThreadContext = thread_context_memory_locator;<br>
+<br>
+  m_data.AppendData(&exp_stream, minidump_exception_size);<br>
+  m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize());<br>
+  return error;<br>
+}<br>
+<br>
+lldb_private::Status<br>
+MinidumpFileBuilder::AddMemoryList(const lldb::ProcessSP &process_sp) {<br>
+  Status error;<br>
+<br>
+  if (error.Fail()) {<br>
+    error.SetErrorString("Process doesn't support getting memory region info.");<br>
+    return error;<br>
+  }<br>
+<br>
+  // Get interesting addresses<br>
+  std::vector<size_t> interesting_addresses;<br>
+  auto thread_list = process_sp->GetThreadList();<br>
+  for (size_t i = 0; i < thread_list.GetSize(); ++i) {<br>
+    ThreadSP thread_sp(thread_list.GetThreadAtIndex(i));<br>
+    RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());<br>
+    RegisterContext *reg_ctx = reg_ctx_sp.get();<br>
+<br>
+    interesting_addresses.push_back(read_register_u64(reg_ctx, "rsp"));<br>
+    interesting_addresses.push_back(read_register_u64(reg_ctx, "rip"));<br>
+  }<br>
+<br>
+  DataBufferHeap helper_data;<br>
+  std::vector<MemoryDescriptor> mem_descriptors;<br>
+<br>
+  std::set<addr_t> visited_region_base_addresses;<br>
+  for (size_t interesting_address : interesting_addresses) {<br>
+    MemoryRegionInfo range_info;<br>
+    error = process_sp->GetMemoryRegionInfo(interesting_address, range_info);<br>
+    // Skip failed memory region requests or any regions with no permissions.<br>
+    if (error.Fail() || range_info.GetLLDBPermissions() == 0)<br>
+      continue;<br>
+    const addr_t addr = range_info.GetRange().GetRangeBase();<br>
+    // Skip any regions we have already saved out.<br>
+    if (visited_region_base_addresses.insert(addr).second == false)<br>
+      continue;<br>
+    const addr_t size = range_info.GetRange().GetByteSize();<br>
+    if (size == 0)<br>
+      continue;<br>
+    auto data_up = std::make_unique<DataBufferHeap>(size, 0);<br>
+    const size_t bytes_read =<br>
+        process_sp->ReadMemory(addr, data_up->GetBytes(), size, error);<br>
+    if (bytes_read == 0)<br>
+      continue;<br>
+    // We have a good memory region with valid bytes to store.<br>
+    LocationDescriptor memory_dump;<br>
+    memory_dump.DataSize = static_cast<llvm::support::ulittle32_t>(bytes_read);<br>
+    memory_dump.RVA =<br>
+        static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset());<br>
+    MemoryDescriptor memory_desc;<br>
+    memory_desc.StartOfMemoryRange =<br>
+        static_cast<llvm::support::ulittle64_t>(addr);<br>
+    memory_desc.Memory = memory_dump;<br>
+    mem_descriptors.push_back(memory_desc);<br>
+    m_data.AppendData(data_up->GetBytes(), bytes_read);<br>
+  }<br>
+<br>
+  AddDirectory(StreamType::MemoryList,<br>
+               sizeof(llvm::support::ulittle32_t) +<br>
+                   mem_descriptors.size() *<br>
+                       sizeof(llvm::minidump::MemoryDescriptor));<br>
+  llvm::support::ulittle32_t memory_ranges_num(mem_descriptors.size());<br>
+<br>
+  m_data.AppendData(&memory_ranges_num, sizeof(llvm::support::ulittle32_t));<br>
+  for (auto memory_descriptor : mem_descriptors) {<br>
+    m_data.AppendData(&memory_descriptor,<br>
+                      sizeof(llvm::minidump::MemoryDescriptor));<br>
+  }<br>
+<br>
+  return error;<br>
+}<br>
+<br>
+void MinidumpFileBuilder::AddMiscInfo(const lldb::ProcessSP &process_sp) {<br>
+  AddDirectory(StreamType::MiscInfo,<br>
+               sizeof(lldb_private::minidump::MinidumpMiscInfo));<br>
+<br>
+  lldb_private::minidump::MinidumpMiscInfo misc_info;<br>
+  misc_info.size = static_cast<llvm::support::ulittle32_t>(<br>
+      sizeof(lldb_private::minidump::MinidumpMiscInfo));<br>
+  // Default set flags1 to 0, in case that we will not be able to<br>
+  // get any information<br>
+  misc_info.flags1 = static_cast<llvm::support::ulittle32_t>(0);<br>
+<br>
+  lldb_private::ProcessInstanceInfo process_info;<br>
+  process_sp->GetProcessInfo(process_info);<br>
+  if (process_info.ProcessIDIsValid()) {<br>
+    // Set flags1 to reflect that PID is filled in<br>
+    misc_info.flags1 =<br>
+        static_cast<llvm::support::ulittle32_t>(static_cast<uint32_t>(<br>
+            lldb_private::minidump::MinidumpMiscInfoFlags::ProcessID));<br>
+    misc_info.process_id =<br>
+        static_cast<llvm::support::ulittle32_t>(process_info.GetProcessID());<br>
+  }<br>
+<br>
+  m_data.AppendData(&misc_info,<br>
+                    sizeof(lldb_private::minidump::MinidumpMiscInfo));<br>
+}<br>
+<br>
+std::unique_ptr<llvm::MemoryBuffer><br>
+getFileStreamHelper(const std::string &path) {<br>
+  auto maybe_stream = llvm::MemoryBuffer::getFileAsStream(path);<br>
+  if (!maybe_stream)<br>
+    return nullptr;<br>
+  return std::move(maybe_stream.get());<br>
+}<br>
+<br>
+void MinidumpFileBuilder::AddLinuxFileStreams(<br>
+    const lldb::ProcessSP &process_sp) {<br>
+  std::vector<std::pair<StreamType, std::string>> files_with_stream_types = {<br>
+      {StreamType::LinuxCPUInfo, "/proc/cpuinfo"},<br>
+      {StreamType::LinuxLSBRelease, "/etc/lsb-release"},<br>
+  };<br>
+<br>
+  lldb_private::ProcessInstanceInfo process_info;<br>
+  process_sp->GetProcessInfo(process_info);<br>
+  if (process_info.ProcessIDIsValid()) {<br>
+    lldb::pid_t pid = process_info.GetProcessID();<br>
+    std::string pid_str = std::to_string(pid);<br>
+    files_with_stream_types.push_back(<br>
+        {StreamType::LinuxProcStatus, "/proc/" + pid_str + "/status"});<br>
+    files_with_stream_types.push_back(<br>
+        {StreamType::LinuxCMDLine, "/proc/" + pid_str + "/cmdline"});<br>
+    files_with_stream_types.push_back(<br>
+        {StreamType::LinuxEnviron, "/proc/" + pid_str + "/environ"});<br>
+    files_with_stream_types.push_back(<br>
+        {StreamType::LinuxAuxv, "/proc/" + pid_str + "/auxv"});<br>
+    files_with_stream_types.push_back(<br>
+        {StreamType::LinuxMaps, "/proc/" + pid_str + "/maps"});<br>
+    files_with_stream_types.push_back(<br>
+        {StreamType::LinuxProcStat, "/proc/" + pid_str + "/stat"});<br>
+    files_with_stream_types.push_back(<br>
+        {StreamType::LinuxProcFD, "/proc/" + pid_str + "/fd"});<br>
+  }<br>
+<br>
+  for (const auto &entry : files_with_stream_types) {<br>
+    StreamType stream = entry.first;<br>
+    std::string path = entry.second;<br>
+    auto memory_buffer = getFileStreamHelper(path);<br>
+<br>
+    if (memory_buffer) {<br>
+      size_t size = memory_buffer->getBufferSize();<br>
+      if (size == 0)<br>
+        continue;<br>
+      AddDirectory(stream, size);<br>
+      m_data.AppendData(memory_buffer->getBufferStart(), size);<br>
+    }<br>
+  }<br>
+}<br>
+<br>
+Status MinidumpFileBuilder::Dump(lldb::FileUP &core_file) const {<br>
+  constexpr size_t header_size = sizeof(llvm::minidump::Header);<br>
+  constexpr size_t directory_size = sizeof(llvm::minidump::Directory);<br>
+<br>
+  // write header<br>
+  llvm::minidump::Header header;<br>
+  header.Signature = static_cast<llvm::support::ulittle32_t>(<br>
+      llvm::minidump::Header::MagicSignature);<br>
+  header.Version = static_cast<llvm::support::ulittle32_t>(<br>
+      llvm::minidump::Header::MagicVersion);<br>
+  header.NumberOfStreams =<br>
+      static_cast<llvm::support::ulittle32_t>(GetDirectoriesNum());<br>
+  header.StreamDirectoryRVA =<br>
+      static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset());<br>
+  header.Checksum = static_cast<llvm::support::ulittle32_t>(<br>
+      0u), // not used in most of the writers<br>
+      header.TimeDateStamp =<br>
+          static_cast<llvm::support::ulittle32_t>(std::time(0));<br>
+  header.Flags =<br>
+      static_cast<llvm::support::ulittle64_t>(0u); // minidump normal flag<br>
+<br>
+  Status error;<br>
+  size_t bytes_written;<br>
+<br>
+  bytes_written = header_size;<br>
+  error = core_file->Write(&header, bytes_written);<br>
+  if (error.Fail() || bytes_written != header_size) {<br>
+    if (bytes_written != header_size)<br>
+      error.SetErrorStringWithFormat(<br>
+          "Unable to write the header. (written %ld/%ld).", bytes_written,<br>
+          header_size);<br>
+    return error;<br>
+  }<br>
+<br>
+  // write data<br>
+  bytes_written = m_data.GetByteSize();<br>
+  error = core_file->Write(m_data.GetBytes(), bytes_written);<br>
+  if (error.Fail() || bytes_written != m_data.GetByteSize()) {<br>
+    if (bytes_written != m_data.GetByteSize())<br>
+      error.SetErrorStringWithFormat(<br>
+          "Unable to write the data. (written %ld/%ld).", bytes_written,<br>
+          m_data.GetByteSize());<br>
+    return error;<br>
+  }<br>
+<br>
+  // write directories<br>
+  for (const Directory &dir : m_directories) {<br>
+    bytes_written = directory_size;<br>
+    error = core_file->Write(&dir, bytes_written);<br>
+    if (error.Fail() || bytes_written != directory_size) {<br>
+      if (bytes_written != directory_size)<br>
+        error.SetErrorStringWithFormat(<br>
+            "Unable to write the directory. (written %ld/%ld).", bytes_written,<br>
+            directory_size);<br>
+      return error;<br>
+    }<br>
+  }<br>
+<br>
+  return error;<br>
+}<br>
+<br>
+size_t MinidumpFileBuilder::GetDirectoriesNum() const {<br>
+  return m_directories.size();<br>
+}<br>
+<br>
+size_t MinidumpFileBuilder::GetCurrentDataEndOffset() const {<br>
+  return sizeof(llvm::minidump::Header) + m_data.GetByteSize();<br>
+}<br>
\ No newline at end of file<br>
<br>
diff  --git a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h<br>
new file mode 100644<br>
index 0000000000000..1d67505d736ec<br>
--- /dev/null<br>
+++ b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h<br>
@@ -0,0 +1,92 @@<br>
+//===-- MinidumpFileBuilder.h ---------------------------------------------===//<br>
+//<br>
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.<br>
+// See <a href="https://llvm.org/LICENSE.txt" rel="noreferrer" target="_blank">https://llvm.org/LICENSE.txt</a> for license information.<br>
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+//<br>
+/// \file<br>
+/// Structure holding data neccessary for minidump file creation.<br>
+///<br>
+/// The class MinidumpFileWriter is used to hold the data that will eventually<br>
+/// be dumped to the file.<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_MINIDUMP_MINIDUMPFILEBUILDER_H<br>
+#define LLDB_SOURCE_PLUGINS_OBJECTFILE_MINIDUMP_MINIDUMPFILEBUILDER_H<br>
+<br>
+#include <cstddef><br>
+<br>
+#include "lldb/Target/Target.h"<br>
+#include "lldb/Utility/DataBufferHeap.h"<br>
+#include "lldb/Utility/Status.h"<br>
+<br>
+#include "llvm/Object/Minidump.h"<br>
+<br>
+// Write std::string to minidump in the UTF16 format(with null termination char)<br>
+// with the size(without null termination char) preceding the UTF16 string.<br>
+// Empty strings are also printed with zero length and just null termination<br>
+// char.<br>
+lldb_private::Status WriteString(const std::string &to_write,<br>
+                                 lldb_private::DataBufferHeap *buffer);<br>
+<br>
+/// \class MinidumpFileBuilder<br>
+/// Minidump writer for Linux<br>
+///<br>
+/// This class provides a Minidump writer that is able to<br>
+/// snapshot the current process state. For the whole time, it stores all<br>
+/// the data on heap.<br>
+class MinidumpFileBuilder {<br>
+public:<br>
+  MinidumpFileBuilder() = default;<br>
+<br>
+  MinidumpFileBuilder(const MinidumpFileBuilder &) = delete;<br>
+  MinidumpFileBuilder &operator=(const MinidumpFileBuilder &) = delete;<br>
+<br>
+  MinidumpFileBuilder(MinidumpFileBuilder &&other) = default;<br>
+  MinidumpFileBuilder &operator=(MinidumpFileBuilder &&other) = default;<br>
+<br>
+  ~MinidumpFileBuilder() = default;<br>
+<br>
+  // Add SystemInfo stream, used for storing the most basic information<br>
+  // about the system, platform etc...<br>
+  lldb_private::Status AddSystemInfo(const llvm::Triple &target_triple);<br>
+  // Add ModuleList stream, containing information about all loaded modules<br>
+  // at the time of saving minidump.<br>
+  lldb_private::Status AddModuleList(lldb_private::Target &target);<br>
+  // Add ThreadList stream, containing information about all threads running<br>
+  // at the moment of core saving. Contains information about thread<br>
+  // contexts.<br>
+  lldb_private::Status AddThreadList(const lldb::ProcessSP &process_sp);<br>
+  // Add Exception stream, this contains information about the exception<br>
+  // that stopped the process. In case no thread made exception it return<br>
+  // failed status.<br>
+  lldb_private::Status AddException(const lldb::ProcessSP &process_sp);<br>
+  // Add MemoryList stream, containing dumps of important memory segments<br>
+  lldb_private::Status AddMemoryList(const lldb::ProcessSP &process_sp);<br>
+  // Add MiscInfo stream, mainly providing ProcessId<br>
+  void AddMiscInfo(const lldb::ProcessSP &process_sp);<br>
+  // Add informative files about a Linux process<br>
+  void AddLinuxFileStreams(const lldb::ProcessSP &process_sp);<br>
+  // Dump the prepared data into file. In case of the failure data are<br>
+  // intact.<br>
+  lldb_private::Status Dump(lldb::FileUP &core_file) const;<br>
+  // Returns the current number of directories(streams) that have been so far<br>
+  // created. This number of directories will be dumped when calling Dump()<br>
+  size_t GetDirectoriesNum() const;<br>
+<br>
+private:<br>
+  // Add directory of StreamType pointing to the current end of the prepared<br>
+  // file with the specified size.<br>
+  void AddDirectory(llvm::minidump::StreamType type, size_t stream_size);<br>
+  size_t GetCurrentDataEndOffset() const;<br>
+<br>
+  // Stores directories to later put them at the end of minidump file<br>
+  std::vector<llvm::minidump::Directory> m_directories;<br>
+  // Main data buffer consisting of data without the minidump header and<br>
+  // directories<br>
+  lldb_private::DataBufferHeap m_data;<br>
+};<br>
+<br>
+#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_MINIDUMP_MINIDUMPFILEBUILDER_H<br>
\ No newline at end of file<br>
<br>
diff  --git a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp<br>
new file mode 100644<br>
index 0000000000000..22b5ae0fa2576<br>
--- /dev/null<br>
+++ b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp<br>
@@ -0,0 +1,119 @@<br>
+//===-- ObjectFileMinidump.cpp --------------------------------------------===//<br>
+//<br>
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.<br>
+// See <a href="https://llvm.org/LICENSE.txt" rel="noreferrer" target="_blank">https://llvm.org/LICENSE.txt</a> for license information.<br>
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#include "ObjectFileMinidump.h"<br>
+<br>
+#include "MinidumpFileBuilder.h"<br>
+<br>
+#include "lldb/Core/ModuleSpec.h"<br>
+#include "lldb/Core/PluginManager.h"<br>
+#include "lldb/Core/Section.h"<br>
+#include "lldb/Target/Process.h"<br>
+<br>
+#include "llvm/Support/FileSystem.h"<br>
+<br>
+using namespace lldb;<br>
+using namespace lldb_private;<br>
+<br>
+LLDB_PLUGIN_DEFINE(ObjectFileMinidump)<br>
+<br>
+void ObjectFileMinidump::Initialize() {<br>
+  PluginManager::RegisterPlugin(<br>
+      GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance,<br>
+      CreateMemoryInstance, GetModuleSpecifications, SaveCore);<br>
+}<br>
+<br>
+void ObjectFileMinidump::Terminate() {<br>
+  PluginManager::UnregisterPlugin(CreateInstance);<br>
+}<br>
+<br>
+ConstString ObjectFileMinidump::GetPluginNameStatic() {<br>
+  static ConstString g_name("minidump");<br>
+  return g_name;<br>
+}<br>
+<br>
+ObjectFile *ObjectFileMinidump::CreateInstance(<br>
+    const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp,<br>
+    lldb::offset_t data_offset, const lldb_private::FileSpec *file,<br>
+    lldb::offset_t offset, lldb::offset_t length) {<br>
+  return nullptr;<br>
+}<br>
+<br>
+ObjectFile *ObjectFileMinidump::CreateMemoryInstance(<br>
+    const lldb::ModuleSP &module_sp, DataBufferSP &data_sp,<br>
+    const ProcessSP &process_sp, lldb::addr_t header_addr) {<br>
+  return nullptr;<br>
+}<br>
+<br>
+size_t ObjectFileMinidump::GetModuleSpecifications(<br>
+    const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp,<br>
+    lldb::offset_t data_offset, lldb::offset_t file_offset,<br>
+    lldb::offset_t length, lldb_private::ModuleSpecList &specs) {<br>
+  specs.Clear();<br>
+  return 0;<br>
+}<br>
+<br>
+bool ObjectFileMinidump::SaveCore(const lldb::ProcessSP &process_sp,<br>
+                                  const lldb_private::FileSpec &outfile,<br>
+                                  lldb::SaveCoreStyle &core_style,<br>
+                                  lldb_private::Status &error) {<br>
+  if (core_style != SaveCoreStyle::eSaveCoreStackOnly) {<br>
+    error.SetErrorString("Only stack minidumps supported yet.");<br>
+    return false;<br>
+  }<br>
+<br>
+  if (!process_sp)<br>
+    return false;<br>
+<br>
+  MinidumpFileBuilder builder;<br>
+<br>
+  Target &target = process_sp->GetTarget();<br>
+<br>
+  error = builder.AddSystemInfo(target.GetArchitecture().GetTriple());<br>
+  if (error.Fail())<br>
+    return false;<br>
+<br>
+  error = builder.AddModuleList(target);<br>
+  if (error.Fail())<br>
+    return false;<br>
+<br>
+  builder.AddMiscInfo(process_sp);<br>
+<br>
+  if (target.GetArchitecture().GetMachine() == llvm::Triple::ArchType::x86_64) {<br>
+    error = builder.AddThreadList(process_sp);<br>
+    if (error.Fail())<br>
+      return false;<br>
+<br>
+    error = builder.AddException(process_sp);<br>
+    if (error.Fail())<br>
+      return false;<br>
+<br>
+    error = builder.AddMemoryList(process_sp);<br>
+    if (error.Fail())<br>
+      return false;<br>
+  }<br>
+<br>
+  if (target.GetArchitecture().GetTriple().getOS() ==<br>
+      llvm::Triple::OSType::Linux) {<br>
+    builder.AddLinuxFileStreams(process_sp);<br>
+  }<br>
+<br>
+  llvm::Expected<lldb::FileUP> maybe_core_file = FileSystem::Instance().Open(<br>
+      outfile, File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate);<br>
+  if (!maybe_core_file) {<br>
+    error = maybe_core_file.takeError();<br>
+    return false;<br>
+  }<br>
+  lldb::FileUP core_file = std::move(maybe_core_file.get());<br>
+<br>
+  error = builder.Dump(core_file);<br>
+  if (error.Fail())<br>
+    return false;<br>
+<br>
+  return true;<br>
+}<br>
<br>
diff  --git a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.h b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.h<br>
new file mode 100644<br>
index 0000000000000..d48600e0c6586<br>
--- /dev/null<br>
+++ b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.h<br>
@@ -0,0 +1,70 @@<br>
+//===-- ObjectFileMinidump.h ---------------------------------- -*- C++ -*-===//<br>
+//<br>
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.<br>
+// See <a href="https://llvm.org/LICENSE.txt" rel="noreferrer" target="_blank">https://llvm.org/LICENSE.txt</a> for license information.<br>
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+//<br>
+/// \file<br>
+/// Placeholder plugin for the save core functionality.<br>
+///<br>
+/// ObjectFileMinidump is created only to be able to save minidump core files<br>
+/// from existing processes with the ObjectFileMinidump::SaveCore function.<br>
+/// Minidump files are not ObjectFile objects, but they are core files and<br>
+/// currently LLDB's ObjectFile plug-ins handle emitting core files. If the<br>
+/// core file saving ever moves into a new plug-in type within LLDB, this code<br>
+/// should move as well, but for now this is the best place architecturally.<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_MINIDUMP_OBJECTFILEMINIDUMP_H<br>
+#define LLDB_SOURCE_PLUGINS_OBJECTFILE_MINIDUMP_OBJECTFILEMINIDUMP_H<br>
+<br>
+#include "lldb/Symbol/ObjectFile.h"<br>
+#include "lldb/Utility/ArchSpec.h"<br>
+<br>
+class ObjectFileMinidump : public lldb_private::PluginInterface {<br>
+public:<br>
+  // Static Functions<br>
+  static void Initialize();<br>
+  static void Terminate();<br>
+<br>
+  static lldb_private::ConstString GetPluginNameStatic();<br>
+  static const char *GetPluginDescriptionStatic() {<br>
+    return "Minidump object file.";<br>
+  }<br>
+<br>
+  // PluginInterface protocol<br>
+  lldb_private::ConstString GetPluginName() override {<br>
+    return GetPluginNameStatic();<br>
+  }<br>
+<br>
+  static lldb_private::ObjectFile *<br>
+  CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp,<br>
+                 lldb::offset_t data_offset, const lldb_private::FileSpec *file,<br>
+                 lldb::offset_t offset, lldb::offset_t length);<br>
+<br>
+  static lldb_private::ObjectFile *CreateMemoryInstance(<br>
+      const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp,<br>
+      const lldb::ProcessSP &process_sp, lldb::addr_t header_addr);<br>
+<br>
+  static size_t GetModuleSpecifications(const lldb_private::FileSpec &file,<br>
+                                        lldb::DataBufferSP &data_sp,<br>
+                                        lldb::offset_t data_offset,<br>
+                                        lldb::offset_t file_offset,<br>
+                                        lldb::offset_t length,<br>
+                                        lldb_private::ModuleSpecList &specs);<br>
+<br>
+  uint32_t GetPluginVersion() override { return 1; }<br>
+<br>
+  // Saves dump in Minidump file format<br>
+  static bool SaveCore(const lldb::ProcessSP &process_sp,<br>
+                       const lldb_private::FileSpec &outfile,<br>
+                       lldb::SaveCoreStyle &core_style,<br>
+                       lldb_private::Status &error);<br>
+<br>
+private:<br>
+  ObjectFileMinidump() = default;<br>
+};<br>
+<br>
+#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_MINIDUMP_OBJECTFILEMINIDUMP_H<br>
\ No newline at end of file<br>
<br>
diff  --git a/lldb/test/API/functionalities/process_save_core_minidump/Makefile b/lldb/test/API/functionalities/process_save_core_minidump/Makefile<br>
new file mode 100644<br>
index 0000000000000..2d177981fdde1<br>
--- /dev/null<br>
+++ b/lldb/test/API/functionalities/process_save_core_minidump/Makefile<br>
@@ -0,0 +1,6 @@<br>
+CXX_SOURCES := main.cpp<br>
+<br>
+CFLAGS_EXTRAS := -lpthread<br>
+<br>
+include Makefile.rules<br>
+<br>
<br>
diff  --git a/lldb/test/API/functionalities/process_save_core_minidump/TestProcessSaveCoreMinidump.py b/lldb/test/API/functionalities/process_save_core_minidump/TestProcessSaveCoreMinidump.py<br>
new file mode 100644<br>
index 0000000000000..8d9c12c7ffe61<br>
--- /dev/null<br>
+++ b/lldb/test/API/functionalities/process_save_core_minidump/TestProcessSaveCoreMinidump.py<br>
@@ -0,0 +1,79 @@<br>
+"""<br>
+Test saving a mini dump.<br>
+"""<br>
+<br>
+<br>
+import os<br>
+import lldb<br>
+from lldbsuite.test.decorators import *<br>
+from lldbsuite.test.lldbtest import *<br>
+from lldbsuite.test import lldbutil<br>
+<br>
+<br>
+class ProcessSaveCoreMinidumpTestCase(TestBase):<br>
+<br>
+    mydir = TestBase.compute_mydir(__file__)<br>
+<br>
+    @skipUnlessArch("x86_64")<br>
+    @skipUnlessPlatform(["linux"])<br>
+    def test_save_linux_mini_dump(self):<br>
+        """Test that we can save a Linux mini dump."""<br>
+        self.build()<br>
+        exe = self.getBuildArtifact("a.out")<br>
+        core = self.getBuildArtifact("core.dmp")<br>
+        try:<br>
+            target = self.dbg.CreateTarget(exe)<br>
+            process = target.LaunchSimple(<br>
+                None, None, self.get_process_working_directory())<br>
+            self.assertEqual(process.GetState(), lldb.eStateStopped)<br>
+<br>
+            # get neccessary data for the verification phase<br>
+            process_info = process.GetProcessInfo()<br>
+            expected_pid = process_info.GetProcessID() if process_info.IsValid() else -1<br>
+            expected_number_of_modules = target.GetNumModules()<br>
+            expected_modules = target.modules<br>
+            expected_number_of_threads = process.GetNumThreads()<br>
+            expected_threads = []<br>
+<br>
+            for thread_idx in range(process.GetNumThreads()):<br>
+                thread = process.GetThreadAtIndex(thread_idx)<br>
+                thread_id = thread.GetThreadID()<br>
+                expected_threads.append(thread_id)<br>
+<br>
+            # save core and, kill process and verify corefile existence<br>
+            self.runCmd("process save-core --plugin-name=minidump --style=stack " + core)<br>
+            self.assertTrue(os.path.isfile(core))<br>
+            self.assertTrue(process.Kill().Success())<br>
+<br>
+            # To verify, we'll launch with the mini dump<br>
+            target = self.dbg.CreateTarget(None)<br>
+            process = target.LoadCore(core)<br>
+<br>
+            # check if the core is in desired state<br>
+            self.assertTrue(process, PROCESS_IS_VALID)<br>
+            self.assertTrue(process.GetProcessInfo().IsValid())<br>
+            self.assertEqual(process.GetProcessInfo().GetProcessID(), expected_pid)<br>
+            self.assertTrue(target.GetTriple().find("linux") != -1)<br>
+            self.assertTrue(target.GetNumModules(), expected_number_of_modules)<br>
+            self.assertEqual(process.GetNumThreads(), expected_number_of_threads)<br>
+<br>
+            for module, expected in zip(target.modules, expected_modules):<br>
+                self.assertTrue(module.IsValid())<br>
+                module_file_name = module.GetFileSpec().GetFilename()<br>
+                expected_file_name = expected.GetFileSpec().GetFilename()<br>
+                # skip kernel virtual dynamic shared objects<br>
+                if "vdso" in expected_file_name:<br>
+                    continue<br>
+                self.assertEqual(module_file_name, expected_file_name)<br>
+                self.assertEqual(module.GetUUIDString(), expected.GetUUIDString())<br>
+<br>
+            for thread_idx in range(process.GetNumThreads()):<br>
+                thread = process.GetThreadAtIndex(thread_idx)<br>
+                self.assertTrue(thread.IsValid())<br>
+                thread_id = thread.GetThreadID()<br>
+                self.assertTrue(thread_id in expected_threads)<br>
+        finally:<br>
+            # Clean up the mini dump file.<br>
+            self.assertTrue(self.dbg.DeleteTarget(target))<br>
+            if (os.path.isfile(core)):<br>
+                os.unlink(core)<br>
<br>
diff  --git a/lldb/test/API/functionalities/process_save_core_minidump/main.cpp b/lldb/test/API/functionalities/process_save_core_minidump/main.cpp<br>
new file mode 100644<br>
index 0000000000000..49b471a4cc517<br>
--- /dev/null<br>
+++ b/lldb/test/API/functionalities/process_save_core_minidump/main.cpp<br>
@@ -0,0 +1,30 @@<br>
+#include <cassert><br>
+#include <iostream><br>
+#include <thread><br>
+<br>
+using namespace std;<br>
+<br>
+void g() { assert(false); }<br>
+<br>
+void f() { g(); }<br>
+<br>
+size_t h() {<br>
+  size_t sum = 0;<br>
+  for (size_t i = 0; i < 1000000; ++i)<br>
+    for (size_t j = 0; j < 1000000; ++j)<br>
+      if ((i * j) % 2 == 0) {<br>
+        sum += 1;<br>
+      }<br>
+  return sum;<br>
+}<br>
+<br>
+int main() {<br>
+  thread t1(f);<br>
+<br>
+  size_t x = h();<br>
+<br>
+  t1.join();<br>
+<br>
+  cout << "X is " << x << "\n";<br>
+  return 0;<br>
+}<br>
\ No newline at end of file<br>
<br>
<br>
<br>
_______________________________________________<br>
lldb-commits mailing list<br>
<a href="mailto:lldb-commits@lists.llvm.org" target="_blank">lldb-commits@lists.llvm.org</a><br>
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits</a><br>
</blockquote></div>