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 ®ion) {
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 ®ion_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