180814287SRaphael Isemann //===-- ProcessMinidump.cpp -----------------------------------------------===//
27b18dd4fSDimitar Vlahovski //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67b18dd4fSDimitar Vlahovski //
77b18dd4fSDimitar Vlahovski //===----------------------------------------------------------------------===//
87b18dd4fSDimitar Vlahovski 
97b18dd4fSDimitar Vlahovski #include "ProcessMinidump.h"
10796ac80bSJonas Devlieghere 
117b18dd4fSDimitar Vlahovski #include "ThreadMinidump.h"
127b18dd4fSDimitar Vlahovski 
1348a28c16SGreg Clayton #include "lldb/Core/DumpDataExtractor.h"
147b18dd4fSDimitar Vlahovski #include "lldb/Core/Module.h"
157b18dd4fSDimitar Vlahovski #include "lldb/Core/ModuleSpec.h"
167b18dd4fSDimitar Vlahovski #include "lldb/Core/PluginManager.h"
177b18dd4fSDimitar Vlahovski #include "lldb/Core/Section.h"
1848a28c16SGreg Clayton #include "lldb/Interpreter/CommandInterpreter.h"
1948a28c16SGreg Clayton #include "lldb/Interpreter/CommandObject.h"
2048a28c16SGreg Clayton #include "lldb/Interpreter/CommandObjectMultiword.h"
2148a28c16SGreg Clayton #include "lldb/Interpreter/CommandReturnObject.h"
2248a28c16SGreg Clayton #include "lldb/Interpreter/OptionArgParser.h"
2348a28c16SGreg Clayton #include "lldb/Interpreter/OptionGroupBoolean.h"
2440b832eaSLeonard Mosescu #include "lldb/Target/JITLoaderList.h"
257b18dd4fSDimitar Vlahovski #include "lldb/Target/MemoryRegionInfo.h"
2647196a25SLeonard Mosescu #include "lldb/Target/SectionLoadList.h"
277b18dd4fSDimitar Vlahovski #include "lldb/Target/Target.h"
287b18dd4fSDimitar Vlahovski #include "lldb/Target/UnixSignals.h"
297b18dd4fSDimitar Vlahovski #include "lldb/Utility/LLDBAssert.h"
30c34698a8SPavel Labath #include "lldb/Utility/LLDBLog.h"
316f9e6901SZachary Turner #include "lldb/Utility/Log.h"
32d821c997SPavel Labath #include "lldb/Utility/State.h"
33f2ffb47fSPavel Labath #include "llvm/BinaryFormat/Magic.h"
343f4a4b36SZachary Turner #include "llvm/Support/MemoryBuffer.h"
35c5f28e2aSKamil Rytarowski #include "llvm/Support/Threading.h"
36c5f28e2aSKamil Rytarowski 
3719c8f394SGreg Clayton #include "Plugins/Process/Utility/StopInfoMachException.h"
380d057900SLeonard Mosescu 
39796ac80bSJonas Devlieghere #include <memory>
407b18dd4fSDimitar Vlahovski 
4147196a25SLeonard Mosescu using namespace lldb;
427b18dd4fSDimitar Vlahovski using namespace lldb_private;
437b18dd4fSDimitar Vlahovski using namespace minidump;
447b18dd4fSDimitar Vlahovski 
45bba9ba8dSJonas Devlieghere LLDB_PLUGIN_DEFINE(ProcessMinidump)
46fbb4d1e4SJonas Devlieghere 
47ee7ceacaSPavel Labath namespace {
48ee7ceacaSPavel Labath 
49ee7ceacaSPavel Labath /// A minimal ObjectFile implementation providing a dummy object file for the
50ee7ceacaSPavel Labath /// cases when the real module binary is not available. This allows the module
51ee7ceacaSPavel Labath /// to show up in "image list" and symbols to be added to it.
52ee7ceacaSPavel Labath class PlaceholderObjectFile : public ObjectFile {
5347196a25SLeonard Mosescu public:
PlaceholderObjectFile(const lldb::ModuleSP & module_sp,const ModuleSpec & module_spec,lldb::addr_t base,lldb::addr_t size)54ee7ceacaSPavel Labath   PlaceholderObjectFile(const lldb::ModuleSP &module_sp,
550156be59SGreg Clayton                         const ModuleSpec &module_spec, lldb::addr_t base,
560156be59SGreg Clayton                         lldb::addr_t size)
57ee7ceacaSPavel Labath       : ObjectFile(module_sp, &module_spec.GetFileSpec(), /*file_offset*/ 0,
58ee7ceacaSPavel Labath                    /*length*/ 0, /*data_sp*/ nullptr, /*data_offset*/ 0),
59ee7ceacaSPavel Labath         m_arch(module_spec.GetArchitecture()), m_uuid(module_spec.GetUUID()),
60ee7ceacaSPavel Labath         m_base(base), m_size(size) {
61a8f3ae7cSJonas Devlieghere     m_symtab_up = std::make_unique<Symtab>(this);
629fecd372SLeonard Mosescu   }
6347196a25SLeonard Mosescu 
GetStaticPluginName()640156be59SGreg Clayton   static ConstString GetStaticPluginName() {
650156be59SGreg Clayton     return ConstString("placeholder");
660156be59SGreg Clayton   }
GetPluginName()67a3939e15SPavel Labath   llvm::StringRef GetPluginName() override {
68a3939e15SPavel Labath     return GetStaticPluginName().GetStringRef();
69a3939e15SPavel Labath   }
ParseHeader()70ee7ceacaSPavel Labath   bool ParseHeader() override { return true; }
CalculateType()71ee7ceacaSPavel Labath   Type CalculateType() override { return eTypeUnknown; }
CalculateStrata()72ee7ceacaSPavel Labath   Strata CalculateStrata() override { return eStrataUnknown; }
GetDependentModules(FileSpecList & file_list)73ee7ceacaSPavel Labath   uint32_t GetDependentModules(FileSpecList &file_list) override { return 0; }
IsExecutable() const74ee7ceacaSPavel Labath   bool IsExecutable() const override { return false; }
GetArchitecture()75ee7ceacaSPavel Labath   ArchSpec GetArchitecture() override { return m_arch; }
GetUUID()76ee7ceacaSPavel Labath   UUID GetUUID() override { return m_uuid; }
ParseSymtab(lldb_private::Symtab & symtab)777e6df41fSGreg Clayton   void ParseSymtab(lldb_private::Symtab &symtab) override {}
IsStripped()78ee7ceacaSPavel Labath   bool IsStripped() override { return true; }
GetByteOrder() const79ee7ceacaSPavel Labath   ByteOrder GetByteOrder() const override { return m_arch.GetByteOrder(); }
80ee7ceacaSPavel Labath 
GetAddressByteSize() const81ee7ceacaSPavel Labath   uint32_t GetAddressByteSize() const override {
82ee7ceacaSPavel Labath     return m_arch.GetAddressByteSize();
83ee7ceacaSPavel Labath   }
84ee7ceacaSPavel Labath 
GetBaseAddress()85ee7ceacaSPavel Labath   Address GetBaseAddress() override {
86ee7ceacaSPavel Labath     return Address(m_sections_up->GetSectionAtIndex(0), 0);
87ee7ceacaSPavel Labath   }
88ee7ceacaSPavel Labath 
CreateSections(SectionList & unified_section_list)89ee7ceacaSPavel Labath   void CreateSections(SectionList &unified_section_list) override {
90a8f3ae7cSJonas Devlieghere     m_sections_up = std::make_unique<SectionList>();
91ee7ceacaSPavel Labath     auto section_sp = std::make_shared<Section>(
92ee7ceacaSPavel Labath         GetModule(), this, /*sect_id*/ 0, ConstString(".module_image"),
93ee7ceacaSPavel Labath         eSectionTypeOther, m_base, m_size, /*file_offset*/ 0, /*file_size*/ 0,
94ee7ceacaSPavel Labath         /*log2align*/ 0, /*flags*/ 0);
95ee7ceacaSPavel Labath     section_sp->SetPermissions(ePermissionsReadable | ePermissionsExecutable);
96ee7ceacaSPavel Labath     m_sections_up->AddSection(section_sp);
97ee7ceacaSPavel Labath     unified_section_list.AddSection(std::move(section_sp));
98ee7ceacaSPavel Labath   }
99ee7ceacaSPavel Labath 
SetLoadAddress(Target & target,addr_t value,bool value_is_offset)100ee7ceacaSPavel Labath   bool SetLoadAddress(Target &target, addr_t value,
101ee7ceacaSPavel Labath                       bool value_is_offset) override {
102ee7ceacaSPavel Labath     assert(!value_is_offset);
103ee7ceacaSPavel Labath     assert(value == m_base);
104ee7ceacaSPavel Labath 
105ee7ceacaSPavel Labath     // Create sections if they haven't been created already.
106ee7ceacaSPavel Labath     GetModule()->GetSectionList();
107ee7ceacaSPavel Labath     assert(m_sections_up->GetNumSections(0) == 1);
108ee7ceacaSPavel Labath 
10947196a25SLeonard Mosescu     target.GetSectionLoadList().SetSectionLoadAddress(
110ee7ceacaSPavel Labath         m_sections_up->GetSectionAtIndex(0), m_base);
111ee7ceacaSPavel Labath     return true;
11247196a25SLeonard Mosescu   }
11347196a25SLeonard Mosescu 
Dump(Stream * s)114ee7ceacaSPavel Labath   void Dump(Stream *s) override {
115ee7ceacaSPavel Labath     s->Format("Placeholder object file for {0} loaded at [{1:x}-{2:x})\n",
116ee7ceacaSPavel Labath               GetFileSpec(), m_base, m_base + m_size);
11795e29763SPavel Labath   }
118ee7ceacaSPavel Labath 
GetBaseImageAddress() const1190156be59SGreg Clayton   lldb::addr_t GetBaseImageAddress() const { return m_base; }
120ee7ceacaSPavel Labath private:
121ee7ceacaSPavel Labath   ArchSpec m_arch;
122ee7ceacaSPavel Labath   UUID m_uuid;
1230156be59SGreg Clayton   lldb::addr_t m_base;
1240156be59SGreg Clayton   lldb::addr_t m_size;
12547196a25SLeonard Mosescu };
1260e6c9a6eSGreg Clayton 
1270e6c9a6eSGreg Clayton /// Duplicate the HashElfTextSection() from the breakpad sources.
1280e6c9a6eSGreg Clayton ///
1290e6c9a6eSGreg Clayton /// Breakpad, a Google crash log reporting tool suite, creates minidump files
1300e6c9a6eSGreg Clayton /// for many different architectures. When using Breakpad to create ELF
1310e6c9a6eSGreg Clayton /// minidumps, it will check for a GNU build ID when creating a minidump file
1320e6c9a6eSGreg Clayton /// and if one doesn't exist in the file, it will say the UUID of the file is a
1330e6c9a6eSGreg Clayton /// checksum of up to the first 4096 bytes of the .text section. Facebook also
1340e6c9a6eSGreg Clayton /// uses breakpad and modified this hash to avoid collisions so we can
1350e6c9a6eSGreg Clayton /// calculate and check for this as well.
1360e6c9a6eSGreg Clayton ///
1370e6c9a6eSGreg Clayton /// The breakpad code might end up hashing up to 15 bytes that immediately
1380e6c9a6eSGreg Clayton /// follow the .text section in the file, so this code must do exactly what it
1390e6c9a6eSGreg Clayton /// does so we can get an exact match for the UUID.
1400e6c9a6eSGreg Clayton ///
1410e6c9a6eSGreg Clayton /// \param[in] module_sp The module to grab the .text section from.
1420e6c9a6eSGreg Clayton ///
14332f252a7SRaphael Isemann /// \param[in,out] breakpad_uuid A vector that will receive the calculated
1440e6c9a6eSGreg Clayton ///                breakpad .text hash.
1450e6c9a6eSGreg Clayton ///
14632f252a7SRaphael Isemann /// \param[in,out] facebook_uuid A vector that will receive the calculated
1470e6c9a6eSGreg Clayton ///                facebook .text hash.
1480e6c9a6eSGreg Clayton ///
HashElfTextSection(ModuleSP module_sp,std::vector<uint8_t> & breakpad_uuid,std::vector<uint8_t> & facebook_uuid)1490e6c9a6eSGreg Clayton void HashElfTextSection(ModuleSP module_sp, std::vector<uint8_t> &breakpad_uuid,
1500e6c9a6eSGreg Clayton                         std::vector<uint8_t> &facebook_uuid) {
1510e6c9a6eSGreg Clayton   SectionList *sect_list = module_sp->GetSectionList();
1520e6c9a6eSGreg Clayton   if (sect_list == nullptr)
1530e6c9a6eSGreg Clayton     return;
1540e6c9a6eSGreg Clayton   SectionSP sect_sp = sect_list->FindSectionByName(ConstString(".text"));
1550e6c9a6eSGreg Clayton   if (!sect_sp)
1560e6c9a6eSGreg Clayton     return;
1570e6c9a6eSGreg Clayton   constexpr size_t kMDGUIDSize = 16;
1580e6c9a6eSGreg Clayton   constexpr size_t kBreakpadPageSize = 4096;
1590e6c9a6eSGreg Clayton   // The breakpad code has a bug where it might access beyond the end of a
1600e6c9a6eSGreg Clayton   // .text section by up to 15 bytes, so we must ensure we round up to the
1610e6c9a6eSGreg Clayton   // next kMDGUIDSize byte boundary.
1620e6c9a6eSGreg Clayton   DataExtractor data;
1630e6c9a6eSGreg Clayton   const size_t text_size = sect_sp->GetFileSize();
1640e6c9a6eSGreg Clayton   const size_t read_size = std::min<size_t>(
1650e6c9a6eSGreg Clayton       llvm::alignTo(text_size, kMDGUIDSize), kBreakpadPageSize);
1660e6c9a6eSGreg Clayton   sect_sp->GetObjectFile()->GetData(sect_sp->GetFileOffset(), read_size, data);
1670e6c9a6eSGreg Clayton 
1680e6c9a6eSGreg Clayton   breakpad_uuid.assign(kMDGUIDSize, 0);
1690e6c9a6eSGreg Clayton   facebook_uuid.assign(kMDGUIDSize, 0);
1700e6c9a6eSGreg Clayton 
1710e6c9a6eSGreg Clayton   // The only difference between the breakpad hash and the facebook hash is the
1720e6c9a6eSGreg Clayton   // hashing of the text section size into the hash prior to hashing the .text
1730e6c9a6eSGreg Clayton   // contents.
1740e6c9a6eSGreg Clayton   for (size_t i = 0; i < kMDGUIDSize; i++)
1750e6c9a6eSGreg Clayton     facebook_uuid[i] ^= text_size % 255;
1760e6c9a6eSGreg Clayton 
1770e6c9a6eSGreg Clayton   // This code carefully duplicates how the hash was created in Breakpad
1780e6c9a6eSGreg Clayton   // sources, including the error where it might has an extra 15 bytes past the
1790e6c9a6eSGreg Clayton   // end of the .text section if the .text section is less than a page size in
1800e6c9a6eSGreg Clayton   // length.
1810e6c9a6eSGreg Clayton   const uint8_t *ptr = data.GetDataStart();
1820e6c9a6eSGreg Clayton   const uint8_t *ptr_end = data.GetDataEnd();
1830e6c9a6eSGreg Clayton   while (ptr < ptr_end) {
1840e6c9a6eSGreg Clayton     for (unsigned i = 0; i < kMDGUIDSize; i++) {
1850e6c9a6eSGreg Clayton       breakpad_uuid[i] ^= ptr[i];
1860e6c9a6eSGreg Clayton       facebook_uuid[i] ^= ptr[i];
1870e6c9a6eSGreg Clayton     }
1880e6c9a6eSGreg Clayton     ptr += kMDGUIDSize;
1890e6c9a6eSGreg Clayton   }
1900e6c9a6eSGreg Clayton }
1910e6c9a6eSGreg Clayton 
192ee7ceacaSPavel Labath } // namespace
19347196a25SLeonard Mosescu 
GetPluginDescriptionStatic()1945f4980f0SPavel Labath llvm::StringRef ProcessMinidump::GetPluginDescriptionStatic() {
1957b18dd4fSDimitar Vlahovski   return "Minidump plug-in.";
1967b18dd4fSDimitar Vlahovski }
1977b18dd4fSDimitar Vlahovski 
CreateInstance(lldb::TargetSP target_sp,lldb::ListenerSP listener_sp,const FileSpec * crash_file,bool can_connect)1987b18dd4fSDimitar Vlahovski lldb::ProcessSP ProcessMinidump::CreateInstance(lldb::TargetSP target_sp,
1997b18dd4fSDimitar Vlahovski                                                 lldb::ListenerSP listener_sp,
20018e4272aSMichał Górny                                                 const FileSpec *crash_file,
20118e4272aSMichał Górny                                                 bool can_connect) {
20218e4272aSMichał Górny   if (!crash_file || can_connect)
2037b18dd4fSDimitar Vlahovski     return nullptr;
2047b18dd4fSDimitar Vlahovski 
2057b18dd4fSDimitar Vlahovski   lldb::ProcessSP process_sp;
2067b18dd4fSDimitar Vlahovski   // Read enough data for the Minidump header
207f2ffb47fSPavel Labath   constexpr size_t header_size = sizeof(Header);
20887e403aaSJonas Devlieghere   auto DataPtr = FileSystem::Instance().CreateDataBuffer(crash_file->GetPath(),
20987e403aaSJonas Devlieghere                                                          header_size, 0);
2103f4a4b36SZachary Turner   if (!DataPtr)
2117b18dd4fSDimitar Vlahovski     return nullptr;
2127b18dd4fSDimitar Vlahovski 
2132ae3ec3bSLeonard Mosescu   lldbassert(DataPtr->GetByteSize() == header_size);
214f2ffb47fSPavel Labath   if (identify_magic(toStringRef(DataPtr->GetData())) != llvm::file_magic::minidump)
2157b18dd4fSDimitar Vlahovski     return nullptr;
2167b18dd4fSDimitar Vlahovski 
21787e403aaSJonas Devlieghere   auto AllData =
21887e403aaSJonas Devlieghere       FileSystem::Instance().CreateDataBuffer(crash_file->GetPath(), -1, 0);
2193f4a4b36SZachary Turner   if (!AllData)
2203f4a4b36SZachary Turner     return nullptr;
2213f4a4b36SZachary Turner 
2227b18dd4fSDimitar Vlahovski   return std::make_shared<ProcessMinidump>(target_sp, listener_sp, *crash_file,
223ab86d3daSPavel Labath                                            std::move(AllData));
2247b18dd4fSDimitar Vlahovski }
2257b18dd4fSDimitar Vlahovski 
CanDebug(lldb::TargetSP target_sp,bool plugin_specified_by_name)2267b18dd4fSDimitar Vlahovski bool ProcessMinidump::CanDebug(lldb::TargetSP target_sp,
2277b18dd4fSDimitar Vlahovski                                bool plugin_specified_by_name) {
2287b18dd4fSDimitar Vlahovski   return true;
2297b18dd4fSDimitar Vlahovski }
2307b18dd4fSDimitar Vlahovski 
ProcessMinidump(lldb::TargetSP target_sp,lldb::ListenerSP listener_sp,const FileSpec & core_file,DataBufferSP core_data)2317b18dd4fSDimitar Vlahovski ProcessMinidump::ProcessMinidump(lldb::TargetSP target_sp,
2327b18dd4fSDimitar Vlahovski                                  lldb::ListenerSP listener_sp,
2337b18dd4fSDimitar Vlahovski                                  const FileSpec &core_file,
234ab86d3daSPavel Labath                                  DataBufferSP core_data)
235fb19f11eSWalter Erquinigo     : PostMortemProcess(target_sp, listener_sp), m_core_file(core_file),
236*4871dfc6SSlava Gurevich       m_core_data(std::move(core_data)), m_active_exception(nullptr),
237*4871dfc6SSlava Gurevich       m_is_wow64(false) {}
2387b18dd4fSDimitar Vlahovski 
~ProcessMinidump()2397b18dd4fSDimitar Vlahovski ProcessMinidump::~ProcessMinidump() {
2407b18dd4fSDimitar Vlahovski   Clear();
24105097246SAdrian Prantl   // We need to call finalize on the process before destroying ourselves to
24205097246SAdrian Prantl   // make sure all of the broadcaster cleanup goes as planned. If we destruct
24305097246SAdrian Prantl   // this class, then Process::~Process() might have problems trying to fully
24405097246SAdrian Prantl   // destroy the broadcaster.
2457b18dd4fSDimitar Vlahovski   Finalize();
2467b18dd4fSDimitar Vlahovski }
2477b18dd4fSDimitar Vlahovski 
Initialize()2487b18dd4fSDimitar Vlahovski void ProcessMinidump::Initialize() {
249c5f28e2aSKamil Rytarowski   static llvm::once_flag g_once_flag;
2507b18dd4fSDimitar Vlahovski 
251c5f28e2aSKamil Rytarowski   llvm::call_once(g_once_flag, []() {
2527b18dd4fSDimitar Vlahovski     PluginManager::RegisterPlugin(GetPluginNameStatic(),
2537b18dd4fSDimitar Vlahovski                                   GetPluginDescriptionStatic(),
2547b18dd4fSDimitar Vlahovski                                   ProcessMinidump::CreateInstance);
2557b18dd4fSDimitar Vlahovski   });
2567b18dd4fSDimitar Vlahovski }
2577b18dd4fSDimitar Vlahovski 
Terminate()2587b18dd4fSDimitar Vlahovski void ProcessMinidump::Terminate() {
2597b18dd4fSDimitar Vlahovski   PluginManager::UnregisterPlugin(ProcessMinidump::CreateInstance);
2607b18dd4fSDimitar Vlahovski }
2617b18dd4fSDimitar Vlahovski 
DoLoadCore()26297206d57SZachary Turner Status ProcessMinidump::DoLoadCore() {
263ab86d3daSPavel Labath   auto expected_parser = MinidumpParser::Create(m_core_data);
264ab86d3daSPavel Labath   if (!expected_parser)
265ab86d3daSPavel Labath     return Status(expected_parser.takeError());
266ab86d3daSPavel Labath   m_minidump_parser = std::move(*expected_parser);
2677b18dd4fSDimitar Vlahovski 
268ab86d3daSPavel Labath   Status error;
2692ae3ec3bSLeonard Mosescu 
2702ae3ec3bSLeonard Mosescu   // Do we support the minidump's architecture?
2712ae3ec3bSLeonard Mosescu   ArchSpec arch = GetArchitecture();
2722ae3ec3bSLeonard Mosescu   switch (arch.GetMachine()) {
2732ae3ec3bSLeonard Mosescu   case llvm::Triple::x86:
2742ae3ec3bSLeonard Mosescu   case llvm::Triple::x86_64:
27519c8f394SGreg Clayton   case llvm::Triple::arm:
27619c8f394SGreg Clayton   case llvm::Triple::aarch64:
27719c8f394SGreg Clayton     // Any supported architectures must be listed here and also supported in
27819c8f394SGreg Clayton     // ThreadMinidump::CreateRegisterContextForFrame().
2792ae3ec3bSLeonard Mosescu     break;
2802ae3ec3bSLeonard Mosescu   default:
2812ae3ec3bSLeonard Mosescu     error.SetErrorStringWithFormat("unsupported minidump architecture: %s",
2822ae3ec3bSLeonard Mosescu                                    arch.GetArchitectureName());
2832ae3ec3bSLeonard Mosescu     return error;
2842ae3ec3bSLeonard Mosescu   }
28519c8f394SGreg Clayton   GetTarget().SetArchitecture(arch, true /*set_platform*/);
2862ae3ec3bSLeonard Mosescu 
287ab86d3daSPavel Labath   m_thread_list = m_minidump_parser->GetThreads();
288ab86d3daSPavel Labath   m_active_exception = m_minidump_parser->GetExceptionStream();
28977460d38SJoseph Tremoulet 
29077460d38SJoseph Tremoulet   SetUnixSignals(UnixSignals::Create(GetArchitecture()));
29177460d38SJoseph Tremoulet 
2927b18dd4fSDimitar Vlahovski   ReadModuleList();
2937b18dd4fSDimitar Vlahovski 
294ab86d3daSPavel Labath   llvm::Optional<lldb::pid_t> pid = m_minidump_parser->GetPid();
2957b18dd4fSDimitar Vlahovski   if (!pid) {
2962fc38b2bSJonas Devlieghere     Debugger::ReportWarning("unable to retrieve process ID from minidump file, "
2972fc38b2bSJonas Devlieghere                             "setting process ID to 1",
2982fc38b2bSJonas Devlieghere                             GetTarget().GetDebugger().GetID());
299468ca490SPavel Labath     pid = 1;
3007b18dd4fSDimitar Vlahovski   }
301ed8fceaaSKazu Hirata   SetID(*pid);
3027b18dd4fSDimitar Vlahovski 
3037b18dd4fSDimitar Vlahovski   return error;
3047b18dd4fSDimitar Vlahovski }
3057b18dd4fSDimitar Vlahovski 
DoDestroy()30697206d57SZachary Turner Status ProcessMinidump::DoDestroy() { return Status(); }
3077b18dd4fSDimitar Vlahovski 
RefreshStateAfterStop()3087b18dd4fSDimitar Vlahovski void ProcessMinidump::RefreshStateAfterStop() {
30977460d38SJoseph Tremoulet 
3107b18dd4fSDimitar Vlahovski   if (!m_active_exception)
3117b18dd4fSDimitar Vlahovski     return;
3127b18dd4fSDimitar Vlahovski 
313d094d97dSJoseph Tremoulet   constexpr uint32_t BreakpadDumpRequested = 0xFFFFFFFF;
314d094d97dSJoseph Tremoulet   if (m_active_exception->ExceptionRecord.ExceptionCode ==
315d094d97dSJoseph Tremoulet       BreakpadDumpRequested) {
316d094d97dSJoseph Tremoulet     // This "ExceptionCode" value is a sentinel that is sometimes used
317d094d97dSJoseph Tremoulet     // when generating a dump for a process that hasn't crashed.
318d094d97dSJoseph Tremoulet 
319d094d97dSJoseph Tremoulet     // TODO: The definition and use of this "dump requested" constant
320d094d97dSJoseph Tremoulet     // in Breakpad are actually Linux-specific, and for similar use
321e9264b74SKazuaki Ishizaki     // cases on Mac/Windows it defines different constants, referring
322d094d97dSJoseph Tremoulet     // to them as "simulated" exceptions; consider moving this check
323d094d97dSJoseph Tremoulet     // down to the OS-specific paths and checking each OS for its own
324d094d97dSJoseph Tremoulet     // constant.
3257b18dd4fSDimitar Vlahovski     return;
3267b18dd4fSDimitar Vlahovski   }
3277b18dd4fSDimitar Vlahovski 
3287b18dd4fSDimitar Vlahovski   lldb::StopInfoSP stop_info;
3297b18dd4fSDimitar Vlahovski   lldb::ThreadSP stop_thread;
3307b18dd4fSDimitar Vlahovski 
331d094d97dSJoseph Tremoulet   Process::m_thread_list.SetSelectedThreadByID(m_active_exception->ThreadId);
3327b18dd4fSDimitar Vlahovski   stop_thread = Process::m_thread_list.GetSelectedThread();
3337b18dd4fSDimitar Vlahovski   ArchSpec arch = GetArchitecture();
3347b18dd4fSDimitar Vlahovski 
3357b18dd4fSDimitar Vlahovski   if (arch.GetTriple().getOS() == llvm::Triple::Linux) {
33677460d38SJoseph Tremoulet     uint32_t signo = m_active_exception->ExceptionRecord.ExceptionCode;
33777460d38SJoseph Tremoulet 
33877460d38SJoseph Tremoulet     if (signo == 0) {
33977460d38SJoseph Tremoulet       // No stop.
34077460d38SJoseph Tremoulet       return;
34177460d38SJoseph Tremoulet     }
34277460d38SJoseph Tremoulet 
3437b18dd4fSDimitar Vlahovski     stop_info = StopInfo::CreateStopReasonWithSignal(
34477460d38SJoseph Tremoulet         *stop_thread, signo);
34519c8f394SGreg Clayton   } else if (arch.GetTriple().getVendor() == llvm::Triple::Apple) {
34619c8f394SGreg Clayton     stop_info = StopInfoMachException::CreateStopReasonWithMachException(
347d094d97dSJoseph Tremoulet         *stop_thread, m_active_exception->ExceptionRecord.ExceptionCode, 2,
348d094d97dSJoseph Tremoulet         m_active_exception->ExceptionRecord.ExceptionFlags,
349d094d97dSJoseph Tremoulet         m_active_exception->ExceptionRecord.ExceptionAddress, 0);
3507b18dd4fSDimitar Vlahovski   } else {
3517b18dd4fSDimitar Vlahovski     std::string desc;
3527b18dd4fSDimitar Vlahovski     llvm::raw_string_ostream desc_stream(desc);
3537b18dd4fSDimitar Vlahovski     desc_stream << "Exception "
3547b18dd4fSDimitar Vlahovski                 << llvm::format_hex(
355d094d97dSJoseph Tremoulet                        m_active_exception->ExceptionRecord.ExceptionCode, 8)
3567b18dd4fSDimitar Vlahovski                 << " encountered at address "
3577b18dd4fSDimitar Vlahovski                 << llvm::format_hex(
358d094d97dSJoseph Tremoulet                        m_active_exception->ExceptionRecord.ExceptionAddress, 8);
3597b18dd4fSDimitar Vlahovski     stop_info = StopInfo::CreateStopReasonWithException(
3607b18dd4fSDimitar Vlahovski         *stop_thread, desc_stream.str().c_str());
3617b18dd4fSDimitar Vlahovski   }
3627b18dd4fSDimitar Vlahovski 
3637b18dd4fSDimitar Vlahovski   stop_thread->SetStopInfo(stop_info);
3647b18dd4fSDimitar Vlahovski }
3657b18dd4fSDimitar Vlahovski 
IsAlive()3667b18dd4fSDimitar Vlahovski bool ProcessMinidump::IsAlive() { return true; }
3677b18dd4fSDimitar Vlahovski 
WarnBeforeDetach() const3687b18dd4fSDimitar Vlahovski bool ProcessMinidump::WarnBeforeDetach() const { return false; }
3697b18dd4fSDimitar Vlahovski 
ReadMemory(lldb::addr_t addr,void * buf,size_t size,Status & error)3707b18dd4fSDimitar Vlahovski size_t ProcessMinidump::ReadMemory(lldb::addr_t addr, void *buf, size_t size,
37197206d57SZachary Turner                                    Status &error) {
37205097246SAdrian Prantl   // Don't allow the caching that lldb_private::Process::ReadMemory does since
37305097246SAdrian Prantl   // we have it all cached in our dump file anyway.
3747b18dd4fSDimitar Vlahovski   return DoReadMemory(addr, buf, size, error);
3757b18dd4fSDimitar Vlahovski }
3767b18dd4fSDimitar Vlahovski 
DoReadMemory(lldb::addr_t addr,void * buf,size_t size,Status & error)3777b18dd4fSDimitar Vlahovski size_t ProcessMinidump::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
37897206d57SZachary Turner                                      Status &error) {
3797b18dd4fSDimitar Vlahovski 
380ab86d3daSPavel Labath   llvm::ArrayRef<uint8_t> mem = m_minidump_parser->GetMemory(addr, size);
3817b18dd4fSDimitar Vlahovski   if (mem.empty()) {
3827b18dd4fSDimitar Vlahovski     error.SetErrorString("could not parse memory info");
3837b18dd4fSDimitar Vlahovski     return 0;
3847b18dd4fSDimitar Vlahovski   }
3857b18dd4fSDimitar Vlahovski 
3867b18dd4fSDimitar Vlahovski   std::memcpy(buf, mem.data(), mem.size());
3877b18dd4fSDimitar Vlahovski   return mem.size();
3887b18dd4fSDimitar Vlahovski }
3897b18dd4fSDimitar Vlahovski 
GetArchitecture()3907b18dd4fSDimitar Vlahovski ArchSpec ProcessMinidump::GetArchitecture() {
3917b18dd4fSDimitar Vlahovski   if (!m_is_wow64) {
392ab86d3daSPavel Labath     return m_minidump_parser->GetArchitecture();
3937b18dd4fSDimitar Vlahovski   }
3947b18dd4fSDimitar Vlahovski 
3957b18dd4fSDimitar Vlahovski   llvm::Triple triple;
3967b18dd4fSDimitar Vlahovski   triple.setVendor(llvm::Triple::VendorType::UnknownVendor);
3977b18dd4fSDimitar Vlahovski   triple.setArch(llvm::Triple::ArchType::x86);
3987b18dd4fSDimitar Vlahovski   triple.setOS(llvm::Triple::OSType::Win32);
3997b18dd4fSDimitar Vlahovski   return ArchSpec(triple);
4007b18dd4fSDimitar Vlahovski }
4017b18dd4fSDimitar Vlahovski 
BuildMemoryRegions()402193a7bfbSPavel Labath void ProcessMinidump::BuildMemoryRegions() {
403193a7bfbSPavel Labath   if (m_memory_regions)
404193a7bfbSPavel Labath     return;
405193a7bfbSPavel Labath   m_memory_regions.emplace();
406193a7bfbSPavel Labath   bool is_complete;
407193a7bfbSPavel Labath   std::tie(*m_memory_regions, is_complete) =
408193a7bfbSPavel Labath       m_minidump_parser->BuildMemoryRegions();
409193a7bfbSPavel Labath 
410193a7bfbSPavel Labath   if (is_complete)
411193a7bfbSPavel Labath     return;
412193a7bfbSPavel Labath 
413193a7bfbSPavel Labath   MemoryRegionInfos to_add;
414193a7bfbSPavel Labath   ModuleList &modules = GetTarget().GetImages();
415193a7bfbSPavel Labath   SectionLoadList &load_list = GetTarget().GetSectionLoadList();
416193a7bfbSPavel Labath   modules.ForEach([&](const ModuleSP &module_sp) {
417193a7bfbSPavel Labath     SectionList *sections = module_sp->GetSectionList();
418193a7bfbSPavel Labath     for (size_t i = 0; i < sections->GetSize(); ++i) {
419193a7bfbSPavel Labath       SectionSP section_sp = sections->GetSectionAtIndex(i);
420193a7bfbSPavel Labath       addr_t load_addr = load_list.GetSectionLoadAddress(section_sp);
421193a7bfbSPavel Labath       if (load_addr == LLDB_INVALID_ADDRESS)
422193a7bfbSPavel Labath         continue;
423193a7bfbSPavel Labath       MemoryRegionInfo::RangeType section_range(load_addr,
424193a7bfbSPavel Labath                                                 section_sp->GetByteSize());
425193a7bfbSPavel Labath       MemoryRegionInfo region =
426c55db460SGreg Clayton           MinidumpParser::GetMemoryRegionInfo(*m_memory_regions, load_addr);
427193a7bfbSPavel Labath       if (region.GetMapped() != MemoryRegionInfo::eYes &&
428193a7bfbSPavel Labath           region.GetRange().GetRangeBase() <= section_range.GetRangeBase() &&
429193a7bfbSPavel Labath           section_range.GetRangeEnd() <= region.GetRange().GetRangeEnd()) {
430193a7bfbSPavel Labath         to_add.emplace_back();
431193a7bfbSPavel Labath         to_add.back().GetRange() = section_range;
432193a7bfbSPavel Labath         to_add.back().SetLLDBPermissions(section_sp->GetPermissions());
433193a7bfbSPavel Labath         to_add.back().SetMapped(MemoryRegionInfo::eYes);
434193a7bfbSPavel Labath         to_add.back().SetName(module_sp->GetFileSpec().GetPath().c_str());
435193a7bfbSPavel Labath       }
436193a7bfbSPavel Labath     }
437193a7bfbSPavel Labath     return true;
438193a7bfbSPavel Labath   });
439193a7bfbSPavel Labath   m_memory_regions->insert(m_memory_regions->end(), to_add.begin(),
440193a7bfbSPavel Labath                            to_add.end());
441193a7bfbSPavel Labath   llvm::sort(*m_memory_regions);
442193a7bfbSPavel Labath }
443193a7bfbSPavel Labath 
DoGetMemoryRegionInfo(lldb::addr_t load_addr,MemoryRegionInfo & region)4442937b282SDavid Spickett Status ProcessMinidump::DoGetMemoryRegionInfo(lldb::addr_t load_addr,
445193a7bfbSPavel Labath                                               MemoryRegionInfo &region) {
446193a7bfbSPavel Labath   BuildMemoryRegions();
447c55db460SGreg Clayton   region = MinidumpParser::GetMemoryRegionInfo(*m_memory_regions, load_addr);
4487c603a41SPavel Labath   return Status();
4497c603a41SPavel Labath }
4507c603a41SPavel Labath 
GetMemoryRegions(MemoryRegionInfos & region_list)4517c603a41SPavel Labath Status ProcessMinidump::GetMemoryRegions(MemoryRegionInfos &region_list) {
4527c603a41SPavel Labath   BuildMemoryRegions();
4537c603a41SPavel Labath   region_list = *m_memory_regions;
45492e5e360STatyana Krasnukha   return Status();
45592e5e360STatyana Krasnukha }
45692e5e360STatyana Krasnukha 
Clear()4577b18dd4fSDimitar Vlahovski void ProcessMinidump::Clear() { Process::m_thread_list.Clear(); }
4587b18dd4fSDimitar Vlahovski 
DoUpdateThreadList(ThreadList & old_thread_list,ThreadList & new_thread_list)4594bb62448SWalter Erquinigo bool ProcessMinidump::DoUpdateThreadList(ThreadList &old_thread_list,
4605a19c0ccSDimitar Vlahovski                                          ThreadList &new_thread_list) {
4616d40c29aSPavel Labath   for (const minidump::Thread &thread : m_thread_list) {
4626d40c29aSPavel Labath     LocationDescriptor context_location = thread.Context;
4637b18dd4fSDimitar Vlahovski 
4640d057900SLeonard Mosescu     // If the minidump contains an exception context, use it
4650d057900SLeonard Mosescu     if (m_active_exception != nullptr &&
466d094d97dSJoseph Tremoulet         m_active_exception->ThreadId == thread.ThreadId) {
467d094d97dSJoseph Tremoulet       context_location = m_active_exception->ThreadContext;
4680d057900SLeonard Mosescu     }
4690d057900SLeonard Mosescu 
4707b18dd4fSDimitar Vlahovski     llvm::ArrayRef<uint8_t> context;
4717b18dd4fSDimitar Vlahovski     if (!m_is_wow64)
472ab86d3daSPavel Labath       context = m_minidump_parser->GetThreadContext(context_location);
4737b18dd4fSDimitar Vlahovski     else
474ab86d3daSPavel Labath       context = m_minidump_parser->GetThreadContextWow64(thread);
4757b18dd4fSDimitar Vlahovski 
4760d057900SLeonard Mosescu     lldb::ThreadSP thread_sp(new ThreadMinidump(*this, thread, context));
4777b18dd4fSDimitar Vlahovski     new_thread_list.AddThread(thread_sp);
4787b18dd4fSDimitar Vlahovski   }
4797b18dd4fSDimitar Vlahovski   return new_thread_list.GetSize(false) > 0;
4807b18dd4fSDimitar Vlahovski }
4817b18dd4fSDimitar Vlahovski 
GetOrCreateModule(UUID minidump_uuid,llvm::StringRef name,ModuleSpec module_spec)482d30797b4SJoseph Tremoulet ModuleSP ProcessMinidump::GetOrCreateModule(UUID minidump_uuid,
483d30797b4SJoseph Tremoulet                                             llvm::StringRef name,
484d30797b4SJoseph Tremoulet                                             ModuleSpec module_spec) {
485a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::DynamicLoader);
486d30797b4SJoseph Tremoulet   Status error;
487d30797b4SJoseph Tremoulet 
488d30797b4SJoseph Tremoulet   ModuleSP module_sp =
489d30797b4SJoseph Tremoulet       GetTarget().GetOrCreateModule(module_spec, true /* notify */, &error);
490d30797b4SJoseph Tremoulet   if (!module_sp)
491d30797b4SJoseph Tremoulet     return module_sp;
492d30797b4SJoseph Tremoulet   // We consider the module to be a match if the minidump UUID is a
493d30797b4SJoseph Tremoulet   // prefix of the actual UUID, or if either of the UUIDs are empty.
494d30797b4SJoseph Tremoulet   const auto dmp_bytes = minidump_uuid.GetBytes();
495d30797b4SJoseph Tremoulet   const auto mod_bytes = module_sp->GetUUID().GetBytes();
496d30797b4SJoseph Tremoulet   const bool match = dmp_bytes.empty() || mod_bytes.empty() ||
497d30797b4SJoseph Tremoulet                      mod_bytes.take_front(dmp_bytes.size()) == dmp_bytes;
498d30797b4SJoseph Tremoulet   if (match) {
499d30797b4SJoseph Tremoulet     LLDB_LOG(log, "Partial uuid match for {0}.", name);
500d30797b4SJoseph Tremoulet     return module_sp;
501d30797b4SJoseph Tremoulet   }
502d30797b4SJoseph Tremoulet 
503d30797b4SJoseph Tremoulet   // Breakpad generates minindump files, and if there is no GNU build
504d30797b4SJoseph Tremoulet   // ID in the binary, it will calculate a UUID by hashing first 4096
505d30797b4SJoseph Tremoulet   // bytes of the .text section and using that as the UUID for a module
506d30797b4SJoseph Tremoulet   // in the minidump. Facebook uses a modified breakpad client that
507d30797b4SJoseph Tremoulet   // uses a slightly modified this hash to avoid collisions. Check for
508d30797b4SJoseph Tremoulet   // UUIDs from the minindump that match these cases and accept the
509d30797b4SJoseph Tremoulet   // module we find if they do match.
510d30797b4SJoseph Tremoulet   std::vector<uint8_t> breakpad_uuid;
511d30797b4SJoseph Tremoulet   std::vector<uint8_t> facebook_uuid;
512d30797b4SJoseph Tremoulet   HashElfTextSection(module_sp, breakpad_uuid, facebook_uuid);
513d30797b4SJoseph Tremoulet   if (dmp_bytes == llvm::ArrayRef<uint8_t>(breakpad_uuid)) {
514d30797b4SJoseph Tremoulet     LLDB_LOG(log, "Breakpad .text hash match for {0}.", name);
515d30797b4SJoseph Tremoulet     return module_sp;
516d30797b4SJoseph Tremoulet   }
517d30797b4SJoseph Tremoulet   if (dmp_bytes == llvm::ArrayRef<uint8_t>(facebook_uuid)) {
518d30797b4SJoseph Tremoulet     LLDB_LOG(log, "Facebook .text hash match for {0}.", name);
519d30797b4SJoseph Tremoulet     return module_sp;
520d30797b4SJoseph Tremoulet   }
521d30797b4SJoseph Tremoulet   // The UUID wasn't a partial match and didn't match the .text hash
522d30797b4SJoseph Tremoulet   // so remove the module from the target, we will need to create a
523d30797b4SJoseph Tremoulet   // placeholder object file.
524d30797b4SJoseph Tremoulet   GetTarget().GetImages().Remove(module_sp);
525d30797b4SJoseph Tremoulet   module_sp.reset();
526d30797b4SJoseph Tremoulet   return module_sp;
527d30797b4SJoseph Tremoulet }
528d30797b4SJoseph Tremoulet 
ReadModuleList()5297b18dd4fSDimitar Vlahovski void ProcessMinidump::ReadModuleList() {
530139e9f24SPavel Labath   std::vector<const minidump::Module *> filtered_modules =
531ab86d3daSPavel Labath       m_minidump_parser->GetFilteredModuleList();
5327b18dd4fSDimitar Vlahovski 
533a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::DynamicLoader);
534bbc428e9SGreg Clayton 
5357b18dd4fSDimitar Vlahovski   for (auto module : filtered_modules) {
536ff12913bSPavel Labath     std::string name = cantFail(m_minidump_parser->GetMinidumpFile().getString(
537139e9f24SPavel Labath         module->ModuleNameRVA));
5380156be59SGreg Clayton     const uint64_t load_addr = module->BaseOfImage;
5390156be59SGreg Clayton     const uint64_t load_size = module->SizeOfImage;
540ff12913bSPavel Labath     LLDB_LOG(log, "found module: name: {0} {1:x10}-{2:x10} size: {3}", name,
5410156be59SGreg Clayton              load_addr, load_addr + load_size, load_size);
5427b18dd4fSDimitar Vlahovski 
5437b18dd4fSDimitar Vlahovski     // check if the process is wow64 - a 32 bit windows process running on a
5447b18dd4fSDimitar Vlahovski     // 64 bit windows
545e50f9c41SMartin Storsjö     if (llvm::StringRef(name).endswith_insensitive("wow64.dll")) {
5467b18dd4fSDimitar Vlahovski       m_is_wow64 = true;
5477b18dd4fSDimitar Vlahovski     }
5487b18dd4fSDimitar Vlahovski 
549ab86d3daSPavel Labath     const auto uuid = m_minidump_parser->GetModuleUUID(module);
550ff12913bSPavel Labath     auto file_spec = FileSpec(name, GetArchitecture().GetTriple());
5519fecd372SLeonard Mosescu     ModuleSpec module_spec(file_spec, uuid);
552ee7ceacaSPavel Labath     module_spec.GetArchitecture() = GetArchitecture();
55397206d57SZachary Turner     Status error;
554bbc428e9SGreg Clayton     // Try and find a module with a full UUID that matches. This function will
555bbc428e9SGreg Clayton     // add the module to the target if it finds one.
5561724a179SJason Molenda     lldb::ModuleSP module_sp = GetTarget().GetOrCreateModule(module_spec,
5571724a179SJason Molenda                                                      true /* notify */, &error);
558bbc428e9SGreg Clayton     if (module_sp) {
5590e6c9a6eSGreg Clayton       LLDB_LOG(log, "Full uuid match for {0}.", name);
560d30797b4SJoseph Tremoulet     } else {
561d30797b4SJoseph Tremoulet       // We couldn't find a module with an exactly-matching UUID.  Sometimes
562d30797b4SJoseph Tremoulet       // a minidump UUID is only a partial match or is a hash.  So try again
563d30797b4SJoseph Tremoulet       // without specifying the UUID, then again without specifying the
564d30797b4SJoseph Tremoulet       // directory if that fails.  This will allow us to find modules with
565d30797b4SJoseph Tremoulet       // partial matches or hash UUIDs in user-provided sysroots or search
566d30797b4SJoseph Tremoulet       // directories (target.exec-search-paths).
567d30797b4SJoseph Tremoulet       ModuleSpec partial_module_spec = module_spec;
568d30797b4SJoseph Tremoulet       partial_module_spec.GetUUID().Clear();
569d30797b4SJoseph Tremoulet       module_sp = GetOrCreateModule(uuid, name, partial_module_spec);
570d30797b4SJoseph Tremoulet       if (!module_sp) {
5711b4b12a3SNico Weber         partial_module_spec.GetFileSpec().GetDirectory().Clear();
572d30797b4SJoseph Tremoulet         module_sp = GetOrCreateModule(uuid, name, partial_module_spec);
573d30797b4SJoseph Tremoulet       }
5740e6c9a6eSGreg Clayton     }
5750156be59SGreg Clayton     if (module_sp) {
5760156be59SGreg Clayton       // Watch out for place holder modules that have different paths, but the
5770156be59SGreg Clayton       // same UUID. If the base address is different, create a new module. If
5780156be59SGreg Clayton       // we don't then we will end up setting the load address of a different
5790156be59SGreg Clayton       // PlaceholderObjectFile and an assertion will fire.
5800156be59SGreg Clayton       auto *objfile = module_sp->GetObjectFile();
581a3939e15SPavel Labath       if (objfile &&
582a3939e15SPavel Labath           objfile->GetPluginName() ==
583a3939e15SPavel Labath               PlaceholderObjectFile::GetStaticPluginName().GetStringRef()) {
5840156be59SGreg Clayton         if (((PlaceholderObjectFile *)objfile)->GetBaseImageAddress() !=
5850156be59SGreg Clayton             load_addr)
5860156be59SGreg Clayton           module_sp.reset();
5870156be59SGreg Clayton       }
5880156be59SGreg Clayton     }
589bbc428e9SGreg Clayton     if (!module_sp) {
59005097246SAdrian Prantl       // We failed to locate a matching local object file. Fortunately, the
59105097246SAdrian Prantl       // minidump format encodes enough information about each module's memory
59205097246SAdrian Prantl       // range to allow us to create placeholder modules.
59347196a25SLeonard Mosescu       //
59447196a25SLeonard Mosescu       // This enables most LLDB functionality involving address-to-module
59547196a25SLeonard Mosescu       // translations (ex. identifing the module for a stack frame PC) and
59647196a25SLeonard Mosescu       // modules/sections commands (ex. target modules list, ...)
597ff12913bSPavel Labath       LLDB_LOG(log,
598ff12913bSPavel Labath                "Unable to locate the matching object file, creating a "
599ff12913bSPavel Labath                "placeholder module for: {0}",
600ff12913bSPavel Labath                name);
6019ba51579SLeonard Mosescu 
602ee7ceacaSPavel Labath       module_sp = Module::CreateModuleFromObjectFile<PlaceholderObjectFile>(
6030156be59SGreg Clayton           module_spec, load_addr, load_size);
6041724a179SJason Molenda       GetTarget().GetImages().Append(module_sp, true /* notify */);
6057b18dd4fSDimitar Vlahovski     }
6067b18dd4fSDimitar Vlahovski 
6077b18dd4fSDimitar Vlahovski     bool load_addr_changed = false;
6080156be59SGreg Clayton     module_sp->SetLoadAddress(GetTarget(), load_addr, false,
6097b18dd4fSDimitar Vlahovski                               load_addr_changed);
6107b18dd4fSDimitar Vlahovski   }
6117b18dd4fSDimitar Vlahovski }
6125a19c0ccSDimitar Vlahovski 
GetProcessInfo(ProcessInstanceInfo & info)6135a19c0ccSDimitar Vlahovski bool ProcessMinidump::GetProcessInfo(ProcessInstanceInfo &info) {
6145a19c0ccSDimitar Vlahovski   info.Clear();
6155a19c0ccSDimitar Vlahovski   info.SetProcessID(GetID());
6165a19c0ccSDimitar Vlahovski   info.SetArchitecture(GetArchitecture());
6175a19c0ccSDimitar Vlahovski   lldb::ModuleSP module_sp = GetTarget().GetExecutableModule();
6185a19c0ccSDimitar Vlahovski   if (module_sp) {
6195a19c0ccSDimitar Vlahovski     const bool add_exe_file_as_first_arg = false;
6205a19c0ccSDimitar Vlahovski     info.SetExecutableFile(GetTarget().GetExecutableModule()->GetFileSpec(),
6215a19c0ccSDimitar Vlahovski                            add_exe_file_as_first_arg);
6225a19c0ccSDimitar Vlahovski   }
6235a19c0ccSDimitar Vlahovski   return true;
6245a19c0ccSDimitar Vlahovski }
62540b832eaSLeonard Mosescu 
62640b832eaSLeonard Mosescu // For minidumps there's no runtime generated code so we don't need JITLoader(s)
62740b832eaSLeonard Mosescu // Avoiding them will also speed up minidump loading since JITLoaders normally
62840b832eaSLeonard Mosescu // try to set up symbolic breakpoints, which in turn may force loading more
62940b832eaSLeonard Mosescu // debug information than needed.
GetJITLoaders()63040b832eaSLeonard Mosescu JITLoaderList &ProcessMinidump::GetJITLoaders() {
631d5b44036SJonas Devlieghere   if (!m_jit_loaders_up) {
632a8f3ae7cSJonas Devlieghere     m_jit_loaders_up = std::make_unique<JITLoaderList>();
63340b832eaSLeonard Mosescu   }
634d5b44036SJonas Devlieghere   return *m_jit_loaders_up;
63540b832eaSLeonard Mosescu }
63648a28c16SGreg Clayton 
63748a28c16SGreg Clayton #define INIT_BOOL(VAR, LONG, SHORT, DESC) \
63848a28c16SGreg Clayton     VAR(LLDB_OPT_SET_1, false, LONG, SHORT, DESC, false, true)
63948a28c16SGreg Clayton #define APPEND_OPT(VAR) \
64048a28c16SGreg Clayton     m_option_group.Append(&VAR, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1)
64148a28c16SGreg Clayton 
64248a28c16SGreg Clayton class CommandObjectProcessMinidumpDump : public CommandObjectParsed {
64348a28c16SGreg Clayton private:
64448a28c16SGreg Clayton   OptionGroupOptions m_option_group;
64548a28c16SGreg Clayton   OptionGroupBoolean m_dump_all;
64648a28c16SGreg Clayton   OptionGroupBoolean m_dump_directory;
64748a28c16SGreg Clayton   OptionGroupBoolean m_dump_linux_cpuinfo;
64848a28c16SGreg Clayton   OptionGroupBoolean m_dump_linux_proc_status;
64948a28c16SGreg Clayton   OptionGroupBoolean m_dump_linux_lsb_release;
65048a28c16SGreg Clayton   OptionGroupBoolean m_dump_linux_cmdline;
65148a28c16SGreg Clayton   OptionGroupBoolean m_dump_linux_environ;
65248a28c16SGreg Clayton   OptionGroupBoolean m_dump_linux_auxv;
65348a28c16SGreg Clayton   OptionGroupBoolean m_dump_linux_maps;
65448a28c16SGreg Clayton   OptionGroupBoolean m_dump_linux_proc_stat;
65548a28c16SGreg Clayton   OptionGroupBoolean m_dump_linux_proc_uptime;
65648a28c16SGreg Clayton   OptionGroupBoolean m_dump_linux_proc_fd;
65748a28c16SGreg Clayton   OptionGroupBoolean m_dump_linux_all;
658cc6ec692SGreg Clayton   OptionGroupBoolean m_fb_app_data;
659cc6ec692SGreg Clayton   OptionGroupBoolean m_fb_build_id;
660cc6ec692SGreg Clayton   OptionGroupBoolean m_fb_version;
661cc6ec692SGreg Clayton   OptionGroupBoolean m_fb_java_stack;
662cc6ec692SGreg Clayton   OptionGroupBoolean m_fb_dalvik;
663cc6ec692SGreg Clayton   OptionGroupBoolean m_fb_unwind;
664cc6ec692SGreg Clayton   OptionGroupBoolean m_fb_error_log;
665cc6ec692SGreg Clayton   OptionGroupBoolean m_fb_app_state;
666cc6ec692SGreg Clayton   OptionGroupBoolean m_fb_abort;
667cc6ec692SGreg Clayton   OptionGroupBoolean m_fb_thread;
668cc6ec692SGreg Clayton   OptionGroupBoolean m_fb_logcat;
669cc6ec692SGreg Clayton   OptionGroupBoolean m_fb_all;
67048a28c16SGreg Clayton 
SetDefaultOptionsIfNoneAreSet()67148a28c16SGreg Clayton   void SetDefaultOptionsIfNoneAreSet() {
67248a28c16SGreg Clayton     if (m_dump_all.GetOptionValue().GetCurrentValue() ||
67348a28c16SGreg Clayton         m_dump_linux_all.GetOptionValue().GetCurrentValue() ||
674cc6ec692SGreg Clayton         m_fb_all.GetOptionValue().GetCurrentValue() ||
67548a28c16SGreg Clayton         m_dump_directory.GetOptionValue().GetCurrentValue() ||
67648a28c16SGreg Clayton         m_dump_linux_cpuinfo.GetOptionValue().GetCurrentValue() ||
67748a28c16SGreg Clayton         m_dump_linux_proc_status.GetOptionValue().GetCurrentValue() ||
67848a28c16SGreg Clayton         m_dump_linux_lsb_release.GetOptionValue().GetCurrentValue() ||
67948a28c16SGreg Clayton         m_dump_linux_cmdline.GetOptionValue().GetCurrentValue() ||
68048a28c16SGreg Clayton         m_dump_linux_environ.GetOptionValue().GetCurrentValue() ||
68148a28c16SGreg Clayton         m_dump_linux_auxv.GetOptionValue().GetCurrentValue() ||
68248a28c16SGreg Clayton         m_dump_linux_maps.GetOptionValue().GetCurrentValue() ||
68348a28c16SGreg Clayton         m_dump_linux_proc_stat.GetOptionValue().GetCurrentValue() ||
68448a28c16SGreg Clayton         m_dump_linux_proc_uptime.GetOptionValue().GetCurrentValue() ||
685cc6ec692SGreg Clayton         m_dump_linux_proc_fd.GetOptionValue().GetCurrentValue() ||
686cc6ec692SGreg Clayton         m_fb_app_data.GetOptionValue().GetCurrentValue() ||
687cc6ec692SGreg Clayton         m_fb_build_id.GetOptionValue().GetCurrentValue() ||
688cc6ec692SGreg Clayton         m_fb_version.GetOptionValue().GetCurrentValue() ||
689cc6ec692SGreg Clayton         m_fb_java_stack.GetOptionValue().GetCurrentValue() ||
690cc6ec692SGreg Clayton         m_fb_dalvik.GetOptionValue().GetCurrentValue() ||
691cc6ec692SGreg Clayton         m_fb_unwind.GetOptionValue().GetCurrentValue() ||
692cc6ec692SGreg Clayton         m_fb_error_log.GetOptionValue().GetCurrentValue() ||
693cc6ec692SGreg Clayton         m_fb_app_state.GetOptionValue().GetCurrentValue() ||
694cc6ec692SGreg Clayton         m_fb_abort.GetOptionValue().GetCurrentValue() ||
695cc6ec692SGreg Clayton         m_fb_thread.GetOptionValue().GetCurrentValue() ||
696cc6ec692SGreg Clayton         m_fb_logcat.GetOptionValue().GetCurrentValue())
69748a28c16SGreg Clayton       return;
69848a28c16SGreg Clayton     // If no options were set, then dump everything
69948a28c16SGreg Clayton     m_dump_all.GetOptionValue().SetCurrentValue(true);
70048a28c16SGreg Clayton   }
DumpAll() const70148a28c16SGreg Clayton   bool DumpAll() const {
70248a28c16SGreg Clayton     return m_dump_all.GetOptionValue().GetCurrentValue();
70348a28c16SGreg Clayton   }
DumpDirectory() const70448a28c16SGreg Clayton   bool DumpDirectory() const {
70548a28c16SGreg Clayton     return DumpAll() ||
70648a28c16SGreg Clayton         m_dump_directory.GetOptionValue().GetCurrentValue();
70748a28c16SGreg Clayton   }
DumpLinux() const70848a28c16SGreg Clayton   bool DumpLinux() const {
70948a28c16SGreg Clayton     return DumpAll() || m_dump_linux_all.GetOptionValue().GetCurrentValue();
71048a28c16SGreg Clayton   }
DumpLinuxCPUInfo() const71148a28c16SGreg Clayton   bool DumpLinuxCPUInfo() const {
71248a28c16SGreg Clayton     return DumpLinux() ||
71348a28c16SGreg Clayton         m_dump_linux_cpuinfo.GetOptionValue().GetCurrentValue();
71448a28c16SGreg Clayton   }
DumpLinuxProcStatus() const71548a28c16SGreg Clayton   bool DumpLinuxProcStatus() const {
71648a28c16SGreg Clayton     return DumpLinux() ||
71748a28c16SGreg Clayton         m_dump_linux_proc_status.GetOptionValue().GetCurrentValue();
71848a28c16SGreg Clayton   }
DumpLinuxProcStat() const71948a28c16SGreg Clayton   bool DumpLinuxProcStat() const {
72048a28c16SGreg Clayton     return DumpLinux() ||
72148a28c16SGreg Clayton         m_dump_linux_proc_stat.GetOptionValue().GetCurrentValue();
72248a28c16SGreg Clayton   }
DumpLinuxLSBRelease() const72348a28c16SGreg Clayton   bool DumpLinuxLSBRelease() const {
72448a28c16SGreg Clayton     return DumpLinux() ||
72548a28c16SGreg Clayton         m_dump_linux_lsb_release.GetOptionValue().GetCurrentValue();
72648a28c16SGreg Clayton   }
DumpLinuxCMDLine() const72748a28c16SGreg Clayton   bool DumpLinuxCMDLine() const {
72848a28c16SGreg Clayton     return DumpLinux() ||
72948a28c16SGreg Clayton         m_dump_linux_cmdline.GetOptionValue().GetCurrentValue();
73048a28c16SGreg Clayton   }
DumpLinuxEnviron() const73148a28c16SGreg Clayton   bool DumpLinuxEnviron() const {
73248a28c16SGreg Clayton     return DumpLinux() ||
73348a28c16SGreg Clayton         m_dump_linux_environ.GetOptionValue().GetCurrentValue();
73448a28c16SGreg Clayton   }
DumpLinuxAuxv() const73548a28c16SGreg Clayton   bool DumpLinuxAuxv() const {
73648a28c16SGreg Clayton     return DumpLinux() ||
73748a28c16SGreg Clayton         m_dump_linux_auxv.GetOptionValue().GetCurrentValue();
73848a28c16SGreg Clayton   }
DumpLinuxMaps() const73948a28c16SGreg Clayton   bool DumpLinuxMaps() const {
74048a28c16SGreg Clayton     return DumpLinux() ||
74148a28c16SGreg Clayton         m_dump_linux_maps.GetOptionValue().GetCurrentValue();
74248a28c16SGreg Clayton   }
DumpLinuxProcUptime() const74348a28c16SGreg Clayton   bool DumpLinuxProcUptime() const {
74448a28c16SGreg Clayton     return DumpLinux() ||
74548a28c16SGreg Clayton         m_dump_linux_proc_uptime.GetOptionValue().GetCurrentValue();
74648a28c16SGreg Clayton   }
DumpLinuxProcFD() const74748a28c16SGreg Clayton   bool DumpLinuxProcFD() const {
74848a28c16SGreg Clayton     return DumpLinux() ||
74948a28c16SGreg Clayton         m_dump_linux_proc_fd.GetOptionValue().GetCurrentValue();
75048a28c16SGreg Clayton   }
DumpFacebook() const751cc6ec692SGreg Clayton   bool DumpFacebook() const {
752cc6ec692SGreg Clayton     return DumpAll() || m_fb_all.GetOptionValue().GetCurrentValue();
753cc6ec692SGreg Clayton   }
DumpFacebookAppData() const754cc6ec692SGreg Clayton   bool DumpFacebookAppData() const {
755cc6ec692SGreg Clayton     return DumpFacebook() || m_fb_app_data.GetOptionValue().GetCurrentValue();
756cc6ec692SGreg Clayton   }
DumpFacebookBuildID() const757cc6ec692SGreg Clayton   bool DumpFacebookBuildID() const {
758cc6ec692SGreg Clayton     return DumpFacebook() || m_fb_build_id.GetOptionValue().GetCurrentValue();
759cc6ec692SGreg Clayton   }
DumpFacebookVersionName() const760cc6ec692SGreg Clayton   bool DumpFacebookVersionName() const {
761cc6ec692SGreg Clayton     return DumpFacebook() || m_fb_version.GetOptionValue().GetCurrentValue();
762cc6ec692SGreg Clayton   }
DumpFacebookJavaStack() const763cc6ec692SGreg Clayton   bool DumpFacebookJavaStack() const {
764cc6ec692SGreg Clayton     return DumpFacebook() || m_fb_java_stack.GetOptionValue().GetCurrentValue();
765cc6ec692SGreg Clayton   }
DumpFacebookDalvikInfo() const766cc6ec692SGreg Clayton   bool DumpFacebookDalvikInfo() const {
767cc6ec692SGreg Clayton     return DumpFacebook() || m_fb_dalvik.GetOptionValue().GetCurrentValue();
768cc6ec692SGreg Clayton   }
DumpFacebookUnwindSymbols() const769cc6ec692SGreg Clayton   bool DumpFacebookUnwindSymbols() const {
770cc6ec692SGreg Clayton     return DumpFacebook() || m_fb_unwind.GetOptionValue().GetCurrentValue();
771cc6ec692SGreg Clayton   }
DumpFacebookErrorLog() const772cc6ec692SGreg Clayton   bool DumpFacebookErrorLog() const {
773cc6ec692SGreg Clayton     return DumpFacebook() || m_fb_error_log.GetOptionValue().GetCurrentValue();
774cc6ec692SGreg Clayton   }
DumpFacebookAppStateLog() const775cc6ec692SGreg Clayton   bool DumpFacebookAppStateLog() const {
776cc6ec692SGreg Clayton     return DumpFacebook() || m_fb_app_state.GetOptionValue().GetCurrentValue();
777cc6ec692SGreg Clayton   }
DumpFacebookAbortReason() const778cc6ec692SGreg Clayton   bool DumpFacebookAbortReason() const {
779cc6ec692SGreg Clayton     return DumpFacebook() || m_fb_abort.GetOptionValue().GetCurrentValue();
780cc6ec692SGreg Clayton   }
DumpFacebookThreadName() const781cc6ec692SGreg Clayton   bool DumpFacebookThreadName() const {
782cc6ec692SGreg Clayton     return DumpFacebook() || m_fb_thread.GetOptionValue().GetCurrentValue();
783cc6ec692SGreg Clayton   }
DumpFacebookLogcat() const784cc6ec692SGreg Clayton   bool DumpFacebookLogcat() const {
785cc6ec692SGreg Clayton     return DumpFacebook() || m_fb_logcat.GetOptionValue().GetCurrentValue();
786cc6ec692SGreg Clayton   }
78748a28c16SGreg Clayton public:
CommandObjectProcessMinidumpDump(CommandInterpreter & interpreter)78848a28c16SGreg Clayton   CommandObjectProcessMinidumpDump(CommandInterpreter &interpreter)
78948a28c16SGreg Clayton   : CommandObjectParsed(interpreter, "process plugin dump",
790248a1305SKonrad Kleine       "Dump information from the minidump file.", nullptr),
79148a28c16SGreg Clayton     m_option_group(),
79248a28c16SGreg Clayton     INIT_BOOL(m_dump_all, "all", 'a',
79348a28c16SGreg Clayton               "Dump the everything in the minidump."),
79448a28c16SGreg Clayton     INIT_BOOL(m_dump_directory, "directory", 'd',
79548a28c16SGreg Clayton               "Dump the minidump directory map."),
79648a28c16SGreg Clayton     INIT_BOOL(m_dump_linux_cpuinfo, "cpuinfo", 'C',
79748a28c16SGreg Clayton               "Dump linux /proc/cpuinfo."),
79848a28c16SGreg Clayton     INIT_BOOL(m_dump_linux_proc_status, "status", 's',
79948a28c16SGreg Clayton               "Dump linux /proc/<pid>/status."),
80048a28c16SGreg Clayton     INIT_BOOL(m_dump_linux_lsb_release, "lsb-release", 'r',
80148a28c16SGreg Clayton               "Dump linux /etc/lsb-release."),
80248a28c16SGreg Clayton     INIT_BOOL(m_dump_linux_cmdline, "cmdline", 'c',
80348a28c16SGreg Clayton               "Dump linux /proc/<pid>/cmdline."),
80448a28c16SGreg Clayton     INIT_BOOL(m_dump_linux_environ, "environ", 'e',
80548a28c16SGreg Clayton               "Dump linux /proc/<pid>/environ."),
80648a28c16SGreg Clayton     INIT_BOOL(m_dump_linux_auxv, "auxv", 'x',
80748a28c16SGreg Clayton               "Dump linux /proc/<pid>/auxv."),
80848a28c16SGreg Clayton     INIT_BOOL(m_dump_linux_maps, "maps", 'm',
80948a28c16SGreg Clayton               "Dump linux /proc/<pid>/maps."),
81048a28c16SGreg Clayton     INIT_BOOL(m_dump_linux_proc_stat, "stat", 'S',
81148a28c16SGreg Clayton               "Dump linux /proc/<pid>/stat."),
81248a28c16SGreg Clayton     INIT_BOOL(m_dump_linux_proc_uptime, "uptime", 'u',
81348a28c16SGreg Clayton               "Dump linux process uptime."),
81448a28c16SGreg Clayton     INIT_BOOL(m_dump_linux_proc_fd, "fd", 'f',
81548a28c16SGreg Clayton               "Dump linux /proc/<pid>/fd."),
81648a28c16SGreg Clayton     INIT_BOOL(m_dump_linux_all, "linux", 'l',
817cc6ec692SGreg Clayton               "Dump all linux streams."),
818cc6ec692SGreg Clayton     INIT_BOOL(m_fb_app_data, "fb-app-data", 1,
819cc6ec692SGreg Clayton               "Dump Facebook application custom data."),
820cc6ec692SGreg Clayton     INIT_BOOL(m_fb_build_id, "fb-build-id", 2,
821cc6ec692SGreg Clayton               "Dump the Facebook build ID."),
822cc6ec692SGreg Clayton     INIT_BOOL(m_fb_version, "fb-version", 3,
823cc6ec692SGreg Clayton               "Dump Facebook application version string."),
824cc6ec692SGreg Clayton     INIT_BOOL(m_fb_java_stack, "fb-java-stack", 4,
825cc6ec692SGreg Clayton               "Dump Facebook java stack."),
826cc6ec692SGreg Clayton     INIT_BOOL(m_fb_dalvik, "fb-dalvik-info", 5,
827cc6ec692SGreg Clayton               "Dump Facebook Dalvik info."),
828cc6ec692SGreg Clayton     INIT_BOOL(m_fb_unwind, "fb-unwind-symbols", 6,
829cc6ec692SGreg Clayton               "Dump Facebook unwind symbols."),
830cc6ec692SGreg Clayton     INIT_BOOL(m_fb_error_log, "fb-error-log", 7,
831cc6ec692SGreg Clayton               "Dump Facebook error log."),
832cc6ec692SGreg Clayton     INIT_BOOL(m_fb_app_state, "fb-app-state-log", 8,
833cc6ec692SGreg Clayton               "Dump Facebook java stack."),
834cc6ec692SGreg Clayton     INIT_BOOL(m_fb_abort, "fb-abort-reason", 9,
835cc6ec692SGreg Clayton               "Dump Facebook abort reason."),
836cc6ec692SGreg Clayton     INIT_BOOL(m_fb_thread, "fb-thread-name", 10,
837cc6ec692SGreg Clayton               "Dump Facebook thread name."),
838cc6ec692SGreg Clayton     INIT_BOOL(m_fb_logcat, "fb-logcat", 11,
839cc6ec692SGreg Clayton               "Dump Facebook logcat."),
840cc6ec692SGreg Clayton     INIT_BOOL(m_fb_all, "facebook", 12, "Dump all Facebook streams.") {
84148a28c16SGreg Clayton     APPEND_OPT(m_dump_all);
84248a28c16SGreg Clayton     APPEND_OPT(m_dump_directory);
84348a28c16SGreg Clayton     APPEND_OPT(m_dump_linux_cpuinfo);
84448a28c16SGreg Clayton     APPEND_OPT(m_dump_linux_proc_status);
84548a28c16SGreg Clayton     APPEND_OPT(m_dump_linux_lsb_release);
84648a28c16SGreg Clayton     APPEND_OPT(m_dump_linux_cmdline);
84748a28c16SGreg Clayton     APPEND_OPT(m_dump_linux_environ);
84848a28c16SGreg Clayton     APPEND_OPT(m_dump_linux_auxv);
84948a28c16SGreg Clayton     APPEND_OPT(m_dump_linux_maps);
85048a28c16SGreg Clayton     APPEND_OPT(m_dump_linux_proc_stat);
85148a28c16SGreg Clayton     APPEND_OPT(m_dump_linux_proc_uptime);
85248a28c16SGreg Clayton     APPEND_OPT(m_dump_linux_proc_fd);
85348a28c16SGreg Clayton     APPEND_OPT(m_dump_linux_all);
854cc6ec692SGreg Clayton     APPEND_OPT(m_fb_app_data);
855cc6ec692SGreg Clayton     APPEND_OPT(m_fb_build_id);
856cc6ec692SGreg Clayton     APPEND_OPT(m_fb_version);
857cc6ec692SGreg Clayton     APPEND_OPT(m_fb_java_stack);
858cc6ec692SGreg Clayton     APPEND_OPT(m_fb_dalvik);
859cc6ec692SGreg Clayton     APPEND_OPT(m_fb_unwind);
860cc6ec692SGreg Clayton     APPEND_OPT(m_fb_error_log);
861cc6ec692SGreg Clayton     APPEND_OPT(m_fb_app_state);
862cc6ec692SGreg Clayton     APPEND_OPT(m_fb_abort);
863cc6ec692SGreg Clayton     APPEND_OPT(m_fb_thread);
864cc6ec692SGreg Clayton     APPEND_OPT(m_fb_logcat);
865cc6ec692SGreg Clayton     APPEND_OPT(m_fb_all);
86648a28c16SGreg Clayton     m_option_group.Finalize();
86748a28c16SGreg Clayton   }
86848a28c16SGreg Clayton 
869fd2433e1SJonas Devlieghere   ~CommandObjectProcessMinidumpDump() override = default;
87048a28c16SGreg Clayton 
GetOptions()87148a28c16SGreg Clayton   Options *GetOptions() override { return &m_option_group; }
87248a28c16SGreg Clayton 
DoExecute(Args & command,CommandReturnObject & result)87348a28c16SGreg Clayton   bool DoExecute(Args &command, CommandReturnObject &result) override {
87448a28c16SGreg Clayton     const size_t argc = command.GetArgumentCount();
87548a28c16SGreg Clayton     if (argc > 0) {
87648a28c16SGreg Clayton       result.AppendErrorWithFormat("'%s' take no arguments, only options",
87748a28c16SGreg Clayton                                    m_cmd_name.c_str());
87848a28c16SGreg Clayton       return false;
87948a28c16SGreg Clayton     }
88048a28c16SGreg Clayton     SetDefaultOptionsIfNoneAreSet();
88148a28c16SGreg Clayton 
88248a28c16SGreg Clayton     ProcessMinidump *process = static_cast<ProcessMinidump *>(
88348a28c16SGreg Clayton         m_interpreter.GetExecutionContext().GetProcessPtr());
88448a28c16SGreg Clayton     result.SetStatus(eReturnStatusSuccessFinishResult);
88548a28c16SGreg Clayton     Stream &s = result.GetOutputStream();
886ab86d3daSPavel Labath     MinidumpParser &minidump = *process->m_minidump_parser;
88748a28c16SGreg Clayton     if (DumpDirectory()) {
888d2b48888SPavel Labath       s.Printf("RVA        SIZE       TYPE       StreamType\n");
88948a28c16SGreg Clayton       s.Printf("---------- ---------- ---------- --------------------------\n");
89098edcd9bSPavel Labath       for (const auto &stream_desc : minidump.GetMinidumpFile().streams())
89198edcd9bSPavel Labath         s.Printf(
89298edcd9bSPavel Labath             "0x%8.8x 0x%8.8x 0x%8.8x %s\n", (uint32_t)stream_desc.Location.RVA,
89398edcd9bSPavel Labath             (uint32_t)stream_desc.Location.DataSize,
89498edcd9bSPavel Labath             (unsigned)(StreamType)stream_desc.Type,
89598edcd9bSPavel Labath             MinidumpParser::GetStreamTypeAsString(stream_desc.Type).data());
89648a28c16SGreg Clayton       s.Printf("\n");
89748a28c16SGreg Clayton     }
898d2b48888SPavel Labath     auto DumpTextStream = [&](StreamType stream_type,
899796984d6SPavel Labath                               llvm::StringRef label) -> void {
90048a28c16SGreg Clayton       auto bytes = minidump.GetStream(stream_type);
90148a28c16SGreg Clayton       if (!bytes.empty()) {
90248a28c16SGreg Clayton         if (label.empty())
903f2ffb47fSPavel Labath           label = MinidumpParser::GetStreamTypeAsString(stream_type);
90448a28c16SGreg Clayton         s.Printf("%s:\n%s\n\n", label.data(), bytes.data());
90548a28c16SGreg Clayton       }
90648a28c16SGreg Clayton     };
907d2b48888SPavel Labath     auto DumpBinaryStream = [&](StreamType stream_type,
908796984d6SPavel Labath                                 llvm::StringRef label) -> void {
90948a28c16SGreg Clayton       auto bytes = minidump.GetStream(stream_type);
91048a28c16SGreg Clayton       if (!bytes.empty()) {
91148a28c16SGreg Clayton         if (label.empty())
912f2ffb47fSPavel Labath           label = MinidumpParser::GetStreamTypeAsString(stream_type);
91348a28c16SGreg Clayton         s.Printf("%s:\n", label.data());
91448a28c16SGreg Clayton         DataExtractor data(bytes.data(), bytes.size(), eByteOrderLittle,
91548a28c16SGreg Clayton                            process->GetAddressByteSize());
91648a28c16SGreg Clayton         DumpDataExtractor(data, &s, 0, lldb::eFormatBytesWithASCII, 1,
91748a28c16SGreg Clayton                           bytes.size(), 16, 0, 0, 0);
91848a28c16SGreg Clayton         s.Printf("\n\n");
91948a28c16SGreg Clayton       }
92048a28c16SGreg Clayton     };
92148a28c16SGreg Clayton 
92248a28c16SGreg Clayton     if (DumpLinuxCPUInfo())
923d2b48888SPavel Labath       DumpTextStream(StreamType::LinuxCPUInfo, "/proc/cpuinfo");
92448a28c16SGreg Clayton     if (DumpLinuxProcStatus())
925d2b48888SPavel Labath       DumpTextStream(StreamType::LinuxProcStatus, "/proc/PID/status");
92648a28c16SGreg Clayton     if (DumpLinuxLSBRelease())
927d2b48888SPavel Labath       DumpTextStream(StreamType::LinuxLSBRelease, "/etc/lsb-release");
92848a28c16SGreg Clayton     if (DumpLinuxCMDLine())
929d2b48888SPavel Labath       DumpTextStream(StreamType::LinuxCMDLine, "/proc/PID/cmdline");
93048a28c16SGreg Clayton     if (DumpLinuxEnviron())
931d2b48888SPavel Labath       DumpTextStream(StreamType::LinuxEnviron, "/proc/PID/environ");
93248a28c16SGreg Clayton     if (DumpLinuxAuxv())
933d2b48888SPavel Labath       DumpBinaryStream(StreamType::LinuxAuxv, "/proc/PID/auxv");
93448a28c16SGreg Clayton     if (DumpLinuxMaps())
935d2b48888SPavel Labath       DumpTextStream(StreamType::LinuxMaps, "/proc/PID/maps");
93648a28c16SGreg Clayton     if (DumpLinuxProcStat())
937d2b48888SPavel Labath       DumpTextStream(StreamType::LinuxProcStat, "/proc/PID/stat");
93848a28c16SGreg Clayton     if (DumpLinuxProcUptime())
939d2b48888SPavel Labath       DumpTextStream(StreamType::LinuxProcUptime, "uptime");
94048a28c16SGreg Clayton     if (DumpLinuxProcFD())
941d2b48888SPavel Labath       DumpTextStream(StreamType::LinuxProcFD, "/proc/PID/fd");
942cc6ec692SGreg Clayton     if (DumpFacebookAppData())
943d2b48888SPavel Labath       DumpTextStream(StreamType::FacebookAppCustomData,
944cc6ec692SGreg Clayton                      "Facebook App Data");
945cc6ec692SGreg Clayton     if (DumpFacebookBuildID()) {
946d2b48888SPavel Labath       auto bytes = minidump.GetStream(StreamType::FacebookBuildID);
947cc6ec692SGreg Clayton       if (bytes.size() >= 4) {
948cc6ec692SGreg Clayton         DataExtractor data(bytes.data(), bytes.size(), eByteOrderLittle,
949cc6ec692SGreg Clayton                            process->GetAddressByteSize());
950cc6ec692SGreg Clayton         lldb::offset_t offset = 0;
951cc6ec692SGreg Clayton         uint32_t build_id = data.GetU32(&offset);
952cc6ec692SGreg Clayton         s.Printf("Facebook Build ID:\n");
953cc6ec692SGreg Clayton         s.Printf("%u\n", build_id);
954cc6ec692SGreg Clayton         s.Printf("\n");
955cc6ec692SGreg Clayton       }
956cc6ec692SGreg Clayton     }
957cc6ec692SGreg Clayton     if (DumpFacebookVersionName())
958d2b48888SPavel Labath       DumpTextStream(StreamType::FacebookAppVersionName,
959cc6ec692SGreg Clayton                      "Facebook Version String");
960cc6ec692SGreg Clayton     if (DumpFacebookJavaStack())
961d2b48888SPavel Labath       DumpTextStream(StreamType::FacebookJavaStack,
962cc6ec692SGreg Clayton                      "Facebook Java Stack");
963cc6ec692SGreg Clayton     if (DumpFacebookDalvikInfo())
964d2b48888SPavel Labath       DumpTextStream(StreamType::FacebookDalvikInfo,
965cc6ec692SGreg Clayton                      "Facebook Dalvik Info");
966cc6ec692SGreg Clayton     if (DumpFacebookUnwindSymbols())
967d2b48888SPavel Labath       DumpBinaryStream(StreamType::FacebookUnwindSymbols,
968cc6ec692SGreg Clayton                        "Facebook Unwind Symbols Bytes");
969cc6ec692SGreg Clayton     if (DumpFacebookErrorLog())
970d2b48888SPavel Labath       DumpTextStream(StreamType::FacebookDumpErrorLog,
971cc6ec692SGreg Clayton                      "Facebook Error Log");
972cc6ec692SGreg Clayton     if (DumpFacebookAppStateLog())
973d2b48888SPavel Labath       DumpTextStream(StreamType::FacebookAppStateLog,
974cc6ec692SGreg Clayton                      "Faceook Application State Log");
975cc6ec692SGreg Clayton     if (DumpFacebookAbortReason())
976d2b48888SPavel Labath       DumpTextStream(StreamType::FacebookAbortReason,
977cc6ec692SGreg Clayton                      "Facebook Abort Reason");
978cc6ec692SGreg Clayton     if (DumpFacebookThreadName())
979d2b48888SPavel Labath       DumpTextStream(StreamType::FacebookThreadName,
980cc6ec692SGreg Clayton                      "Facebook Thread Name");
981cc6ec692SGreg Clayton     if (DumpFacebookLogcat())
982d2b48888SPavel Labath       DumpTextStream(StreamType::FacebookLogcat,
983cc6ec692SGreg Clayton                      "Facebook Logcat");
98448a28c16SGreg Clayton     return true;
98548a28c16SGreg Clayton   }
98648a28c16SGreg Clayton };
98748a28c16SGreg Clayton 
98848a28c16SGreg Clayton class CommandObjectMultiwordProcessMinidump : public CommandObjectMultiword {
98948a28c16SGreg Clayton public:
CommandObjectMultiwordProcessMinidump(CommandInterpreter & interpreter)99048a28c16SGreg Clayton   CommandObjectMultiwordProcessMinidump(CommandInterpreter &interpreter)
99148a28c16SGreg Clayton     : CommandObjectMultiword(interpreter, "process plugin",
99248a28c16SGreg Clayton           "Commands for operating on a ProcessMinidump process.",
99348a28c16SGreg Clayton           "process plugin <subcommand> [<subcommand-options>]") {
99448a28c16SGreg Clayton     LoadSubCommand("dump",
99548a28c16SGreg Clayton         CommandObjectSP(new CommandObjectProcessMinidumpDump(interpreter)));
99648a28c16SGreg Clayton   }
99748a28c16SGreg Clayton 
998fd2433e1SJonas Devlieghere   ~CommandObjectMultiwordProcessMinidump() override = default;
99948a28c16SGreg Clayton };
100048a28c16SGreg Clayton 
GetPluginCommandObject()100148a28c16SGreg Clayton CommandObject *ProcessMinidump::GetPluginCommandObject() {
100248a28c16SGreg Clayton   if (!m_command_sp)
1003796ac80bSJonas Devlieghere     m_command_sp = std::make_shared<CommandObjectMultiwordProcessMinidump>(
1004796ac80bSJonas Devlieghere         GetTarget().GetDebugger().GetCommandInterpreter());
100548a28c16SGreg Clayton   return m_command_sp.get();
100648a28c16SGreg Clayton }
1007