[Lldb-commits] [lldb] eee687a - [lldb] Add minidump save-core functionality to ELF object files
Andy Yankovsky via lldb-commits
lldb-commits at lists.llvm.org
Mon Jan 3 07:21:39 PST 2022
Hi, sorry for the delay, I will try to take a look sometime soon. To
simplify things for me, can you provide the build/test instruction for
reproducing this failure? I have a Windows and a Linux machine, either will
work.
On Wed, 15 Dec 2021 at 01:38, Richard Smith <richard at metafoo.co.uk> wrote:
> Ping, this test is still failing under msan:
>
> Uninitialized bytes in __interceptor_write at offset 2 inside
> [0x7f4c189cb000, 19480578)
> ==9551==WARNING: MemorySanitizer: use-of-uninitialized-value
> #0 0x5590de0ce979 in RetryAfterSignal<int, long (int, const void *,
> unsigned long), int, const void *, unsigned long>
> third_party/llvm/llvm-project/llvm/include/llvm/Support/Errno.h:38:11
> #1 0x5590de0ce979 in lldb_private::NativeFile::Write(void const*,
> unsigned long&)
> third_party/llvm/llvm-project/lldb/source/Host/common/File.cpp:585:9
> #2 0x5590dda1a5c5 in
> MinidumpFileBuilder::Dump(std::__msan::unique_ptr<lldb_private::File,
> std::__msan::default_delete<lldb_private::File> >&) const
> third_party/llvm/llvm-project/lldb/source/Plugins/O
> bjectFile/Minidump/MinidumpFileBuilder.cpp:741:22
> #3 0x5590dda1ce9c in
> ObjectFileMinidump::SaveCore(std::__msan::shared_ptr<lldb_private::Process>
> const&, lldb_private::FileSpec const&, lldb::SaveCoreStyle&,
> lldb_private::Status&) third_party/llvm/ll
>
> vm-project/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp:109:19
> #4 0x5590dd3a3faa in
> lldb_private::PluginManager::SaveCore(std::__msan::shared_ptr<lldb_private::Process>
> const&, lldb_private::FileSpec const&, lldb::SaveCoreStyle&,
> llvm::StringRef) third_party/llvm
> /llvm-project/lldb/source/Core/PluginManager.cpp:709:11
> #5 0x5590dd13d114 in
> CommandObjectProcessSaveCore::DoExecute(lldb_private::Args&,
> lldb_private::CommandReturnObject&)
> third_party/llvm/llvm-project/lldb/source/Commands/CommandObjectProcess.cpp:1272:1
> 3
> #6 0x5590dd596f7f in lldb_private::CommandObjectParsed::Execute(char
> const*, lldb_private::CommandReturnObject&)
> third_party/llvm/llvm-project/lldb/source/Interpreter/CommandObject.cpp:998:19
> #7 0x5590dd571d28 in
> lldb_private::CommandInterpreter::HandleCommand(char const*,
> lldb_private::LazyBool, lldb_private::CommandReturnObject&)
> third_party/llvm/llvm-project/lldb/source/Interpreter/Comm
> andInterpreter.cpp:1971:14
> #8 0x7f4c2162fba5 in lldb::SBCommandInterpreter::HandleCommand(char
> const*, lldb::SBExecutionContext&, lldb::SBCommandReturnObject&, bool)
> third_party/llvm/llvm-project/lldb/source/API/SBCommandInterp
> reter.cpp:183:21
> #9 0x7f4c2162f434 in lldb::SBCommandInterpreter::HandleCommand(char
> const*, lldb::SBCommandReturnObject&, bool)
> third_party/llvm/llvm-project/lldb/source/API/SBCommandInterpreter.cpp:163:10
>
> On Sat, 25 Sept 2021 at 23:25, Raphael Isemann <teemperor at gmail.com>
> wrote:
>
>> I guess you might have already figured that out in a Google-internal
>> chat, but msan actually requires that the used libc++ is also compiled
>> with msan enabled. Totally forgot that this is a requirement for msan
>> (sorry).
>>
>> I don't think there is a public LLDB msan bot (?), but you can
>> probably try the msan bot script as described here and then just see
>> if you can patch it to enable LLDB:
>> https://github.com/google/sanitizers/wiki/SanitizerBotReproduceBuild
>>
>>
>> Am Di., 7. Sept. 2021 um 10:43 Uhr schrieb Andy Yankovsky <
>> werat at google.com>:
>> >
>> > Replying on behalf of Andrej, since there's some issue with his email
>> policy
>> >
>> > Andrej Korman:
>> >
>> > Hi,
>> >
>> > unfortunately I was not able to reproduce this as build with
>> MemorySanitizer fails earlier with:
>> >
>> > Uninitialized bytes in __interceptor_memchr at offset 6 inside
>> [0x7020000006c0, 7) ==3708245==WARNING: MemorySanitizer:
>> use-of-uninitialized-value #0 0x4f9908 in llvm::StringRef::find(char,
>> unsigned long) const
>> /usr/local/google/home/andrejkorman/work/llvm-project/llvm/include/llvm/ADT/StringRef.h:319:29
>> #1 0xcb7639 in
>> llvm::StringRef::split(llvm::SmallVectorImpl<llvm::StringRef>&, char, int,
>> bool) const
>> /usr/local/google/home/andrejkorman/work/llvm-project/llvm/lib/Support/StringRef.cpp:341:20
>> #2 0xcd0dbd in llvm::Triple::Triple(llvm::Twine const&)
>> /usr/local/google/home/andrejkorman/work/llvm-project/llvm/lib/Support/Triple.cpp:770:19
>> #3 0xd85899 in llvm::sys::getProcessTriple[abi:cxx11]()
>> /usr/local/google/home/andrejkorman/work/llvm-project/llvm/lib/Support/Host.cpp:1750:10
>> #4 0xc18393 in (anonymous
>> namespace)::CommandLineParser::ParseCommandLineOptions(int, char const*
>> const*, llvm::StringRef, llvm::raw_ostream*, bool)
>> /usr/local/google/home/andrejkorman/work/llvm-project/llvm/lib/Support/CommandLine.cpp:1353:17
>> #5 0xc17fc4 in llvm::cl::ParseCommandLineOptions(int, char const* const*,
>> llvm::StringRef, llvm::raw_ostream*, char const*, bool)
>> /usr/local/google/home/andrejkorman/work/llvm-project/llvm/lib/Support/CommandLine.cpp:1320:24
>> #6 0xb9a3cc in main
>> /usr/local/google/home/andrejkorman/work/llvm-project/llvm/utils/TableGen/TableGen.cpp:283:3
>> #7 0x7f5fc9d30d09 in __libc_start_main csu/../csu/libc-start.c:308:16 #8
>> 0x42ad99 in _start
>> (/usr/local/google/home/andrejkorman/work/llvm-project/build_x64/bin/llvm-tblgen+0x42ad99)
>> >
>> > and the same with the lldb-tblgen and clang-tblgen. The command used
>> for the build was:
>> >
>> > cmake -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
>> -DLLVM_PARALLEL_LINK_JOBS=5 -DLLVM_BUILD_TESTS=ON
>> -DLLVM_USE_SANITIZER=Memory -DLLVM_ENABLE_PROJECTS='lldb;clang' ../llvm
>> >
>> > After providing -DLLVM_TABLEGEN, -DLLDB_TABLEGEN and -DCLANG_TABLEGEN
>> builded separately, it fails on clang-ast-dump. This exact issue also
>> happened on 2 more Linux machines running on x86_64. I wonder if this is
>> expected and if possible how to get past this errors.
>> >
>> > Thank you for any information on this issue and sorry for the
>> inconvenience. I wasn't, unfortunately, able to find the root cause only by
>> looking at the code that is producing this memory issue.
>> >
>> > On Mon, 6 Sept 2021 at 12:21, Raphael Isemann <teemperor at gmail.com>
>> wrote:
>> >>
>> >> 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 ®_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 ®_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 ®_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
>> ®_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
>> ®_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
>> ®_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
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/lldb-commits/attachments/20220103/1741561c/attachment-0001.html>
More information about the lldb-commits
mailing list