Andy Yankovsky via llvm-dev
2022-Jan-03 15:21 UTC
[llvm-dev] [Lldb-commits] [lldb] eee687a - [lldb] Add minidump save-core functionality to ELF object files
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/llvm-dev/attachments/20220103/1741561c/attachment-0001.html>