Aj0SK updated this revision to Diff 368765.
Aj0SK added a comment.

Change ObjectFileMinidump plugin to inherit from PluginInterface


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D108233/new/

https://reviews.llvm.org/D108233

Files:
  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
  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

Index: lldb/test/API/functionalities/process_save_core_minidump/main.cpp
===================================================================
--- /dev/null
+++ 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
Index: lldb/test/API/functionalities/process_save_core_minidump/TestProcessSaveCoreMinidump.py
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/process_save_core_minidump/TestProcessSaveCoreMinidump.py
@@ -0,0 +1,78 @@
+"""
+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__)
+
+    @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 " + 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)
Index: lldb/test/API/functionalities/process_save_core_minidump/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/process_save_core_minidump/Makefile
@@ -0,0 +1,6 @@
+CXX_SOURCES := main.cpp
+
+CFLAGS_EXTRAS := -lpthread
+
+include Makefile.rules
+
Index: lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.h
===================================================================
--- /dev/null
+++ 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
Index: lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp
===================================================================
--- /dev/null
+++ lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp
@@ -0,0 +1,114 @@
+//===-- 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 (!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;
+}
Index: lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h
===================================================================
--- /dev/null
+++ lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h
@@ -0,0 +1,93 @@
+//===-- MinidumpFileBuilder.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
+/// 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
Index: lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp
===================================================================
--- /dev/null
+++ lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp
@@ -0,0 +1,741 @@
+//===-- 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/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::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;
+}
+
+// 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();
+
+    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->GetObjectFile()->GetByteSize());
+    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 range_error = process_sp->GetMemoryRegionInfo(0, range_info);
+
+  if (range_error.Fail())
+    return llvm::createStringError(
+        std::errc::not_supported,
+        "process doesn't support getting memory region info");
+
+  while (range_info.GetRange().GetRangeBase() != LLDB_INVALID_ADDRESS) {
+    const addr_t addr = range_info.GetRange().GetRangeBase();
+    const addr_t size = range_info.GetRange().GetByteSize();
+
+    if (rsp >= addr && rsp <= addr + size)
+      return std::make_pair(addr, size);
+
+    if (size == 0)
+      break;
+
+    range_error = process_sp->GetMemoryRegionInfo(
+        range_info.GetRange().GetRangeEnd(), range_info);
+    if (range_error.Fail())
+      break;
+  }
+
+  return llvm::createStringError(
+      std::errc::not_supported,
+      "process doesn't support getting memory region info");
+}
+
+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);
+    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>(size);
+    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(), size);
+
+    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;
+  MemoryRegionInfo range_info;
+  error = process_sp->GetMemoryRegionInfo(0, range_info);
+
+  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;
+
+  while (range_info.GetRange().GetRangeBase() != LLDB_INVALID_ADDRESS) {
+    const addr_t addr = range_info.GetRange().GetRangeBase();
+    const addr_t size = range_info.GetRange().GetByteSize();
+
+    bool is_interesting = false;
+    for (size_t interesting_address : interesting_addresses)
+      if (interesting_address >= addr && interesting_address < addr + size) {
+        is_interesting = true;
+        break;
+      }
+
+    if (is_interesting) {
+      LocationDescriptor memory_dump;
+      memory_dump.DataSize = static_cast<llvm::support::ulittle32_t>(size);
+      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);
+
+      auto data_up = std::make_unique<DataBufferHeap>(size, 0);
+      process_sp->ReadMemory(addr, data_up->GetBytes(), size, error);
+
+      m_data.AppendData(data_up->GetBytes(), size);
+    }
+
+    if (size == 0)
+      break;
+
+    error = process_sp->GetMemoryRegionInfo(range_info.GetRange().GetRangeEnd(),
+                                            range_info);
+    if (error.Fail()) {
+      error = Status();
+      break;
+    }
+  }
+
+  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();
+      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
Index: lldb/source/Plugins/ObjectFile/Minidump/CMakeLists.txt
===================================================================
--- /dev/null
+++ 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
+  )
Index: lldb/source/Plugins/ObjectFile/CMakeLists.txt
===================================================================
--- lldb/source/Plugins/ObjectFile/CMakeLists.txt
+++ 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)
Index: lldb/source/Core/PluginManager.cpp
===================================================================
--- lldb/source/Core/PluginManager.cpp
+++ lldb/source/Core/PluginManager.cpp
@@ -685,10 +685,13 @@
 
 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;
Index: lldb/source/Commands/Options.td
===================================================================
--- lldb/source/Commands/Options.td
+++ lldb/source/Commands/Options.td
@@ -742,6 +742,9 @@
   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 different formats.">;
 }
 
 let Command = "script import" in {
Index: lldb/source/Commands/CommandObjectProcess.cpp
===================================================================
--- lldb/source/Commands/CommandObjectProcess.cpp
+++ lldb/source/Commands/CommandObjectProcess.cpp
@@ -1180,12 +1180,13 @@
 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 @@
       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 @@
 
     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 @@
         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) {
Index: lldb/source/API/SBProcess.cpp
===================================================================
--- lldb/source/API/SBProcess.cpp
+++ lldb/source/API/SBProcess.cpp
@@ -1228,7 +1228,8 @@
 
   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);
 }
 
Index: lldb/include/lldb/Core/PluginManager.h
===================================================================
--- lldb/include/lldb/Core/PluginManager.h
+++ lldb/include/lldb/Core/PluginManager.h
@@ -192,7 +192,8 @@
 
   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
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to