[Lldb-commits] [lldb] eee687a - [lldb] Add minidump save-core functionality to ELF object files

Raphael Isemann via lldb-commits lldb-commits at lists.llvm.org
Mon Sep 6 03:21:03 PDT 2021


Not sure if there is a public builder with sanitizer enabled, but
compiling LLDB with -DLLVM_USE_SANITIZER=Memory and then doing ninja
check-lldb should be enough to reproduce this IIUC.

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


More information about the lldb-commits mailing list