diff options
Diffstat (limited to 'source/Plugins/Process/minidump/ProcessMinidump.cpp')
-rw-r--r-- | source/Plugins/Process/minidump/ProcessMinidump.cpp | 334 |
1 files changed, 298 insertions, 36 deletions
diff --git a/source/Plugins/Process/minidump/ProcessMinidump.cpp b/source/Plugins/Process/minidump/ProcessMinidump.cpp index b43f22382eaca..c5cca7ea62c69 100644 --- a/source/Plugins/Process/minidump/ProcessMinidump.cpp +++ b/source/Plugins/Process/minidump/ProcessMinidump.cpp @@ -7,28 +7,34 @@ // //===----------------------------------------------------------------------===// -// Project includes #include "ProcessMinidump.h" #include "ThreadMinidump.h" -// Other libraries and framework includes +#include "lldb/Core/DumpDataExtractor.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" -#include "lldb/Core/State.h" -#include "lldb/Target/DynamicLoader.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandObject.h" +#include "lldb/Interpreter/CommandObjectMultiword.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/OptionArgParser.h" +#include "lldb/Interpreter/OptionGroupBoolean.h" +#include "lldb/Target/JITLoaderList.h" #include "lldb/Target/MemoryRegionInfo.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" #include "lldb/Target/UnixSignals.h" -#include "lldb/Utility/DataBufferLLVM.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Threading.h" +#include "Plugins/Process/Utility/StopInfoMachException.h" + // C includes // C++ includes @@ -75,7 +81,7 @@ public: section_sp, module->base_of_image); } - ObjectFile *GetObjectFile() override { return nullptr; } +ObjectFile *GetObjectFile() override { return nullptr; } SectionList *GetSectionList() override { return Module::GetUnifiedSectionList(); @@ -100,8 +106,8 @@ lldb::ProcessSP ProcessMinidump::CreateInstance(lldb::TargetSP target_sp, lldb::ProcessSP process_sp; // Read enough data for the Minidump header constexpr size_t header_size = sizeof(MinidumpHeader); - auto DataPtr = - DataBufferLLVM::CreateSliceFromPath(crash_file->GetPath(), header_size, 0); + auto DataPtr = FileSystem::Instance().CreateDataBuffer(crash_file->GetPath(), + header_size, 0); if (!DataPtr) return nullptr; @@ -113,7 +119,8 @@ lldb::ProcessSP ProcessMinidump::CreateInstance(lldb::TargetSP target_sp, if (header == nullptr) return nullptr; - auto AllData = DataBufferLLVM::CreateSliceFromPath(crash_file->GetPath(), -1, 0); + auto AllData = + FileSystem::Instance().CreateDataBuffer(crash_file->GetPath(), -1, 0); if (!AllData) return nullptr; @@ -174,19 +181,21 @@ Status ProcessMinidump::DoLoadCore() { switch (arch.GetMachine()) { case llvm::Triple::x86: case llvm::Triple::x86_64: - // supported + case llvm::Triple::arm: + case llvm::Triple::aarch64: + // Any supported architectures must be listed here and also supported in + // ThreadMinidump::CreateRegisterContextForFrame(). break; - default: error.SetErrorStringWithFormat("unsupported minidump architecture: %s", arch.GetArchitectureName()); return error; } + GetTarget().SetArchitecture(arch, true /*set_platform*/); m_thread_list = m_minidump_parser.GetThreads(); m_active_exception = m_minidump_parser.GetExceptionStream(); ReadModuleList(); - GetTarget().SetArchitecture(arch); llvm::Optional<lldb::pid_t> pid = m_minidump_parser.GetPid(); if (!pid) { @@ -198,12 +207,6 @@ Status ProcessMinidump::DoLoadCore() { return error; } -DynamicLoader *ProcessMinidump::GetDynamicLoader() { - if (m_dyld_ap.get() == nullptr) - m_dyld_ap.reset(DynamicLoader::FindPlugin(this, nullptr)); - return m_dyld_ap.get(); -} - ConstString ProcessMinidump::GetPluginName() { return GetPluginNameStatic(); } uint32_t ProcessMinidump::GetPluginVersion() { return 1; } @@ -229,6 +232,11 @@ void ProcessMinidump::RefreshStateAfterStop() { if (arch.GetTriple().getOS() == llvm::Triple::Linux) { stop_info = StopInfo::CreateStopReasonWithSignal( *stop_thread, m_active_exception->exception_record.exception_code); + } else if (arch.GetTriple().getVendor() == llvm::Triple::Apple) { + stop_info = StopInfoMachException::CreateStopReasonWithMachException( + *stop_thread, m_active_exception->exception_record.exception_code, 2, + m_active_exception->exception_record.exception_flags, + m_active_exception->exception_record.exception_address, 0); } else { std::string desc; llvm::raw_string_ostream desc_stream(desc); @@ -284,33 +292,36 @@ ArchSpec ProcessMinidump::GetArchitecture() { Status ProcessMinidump::GetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo &range_info) { - Status error; - auto info = m_minidump_parser.GetMemoryRegionInfo(load_addr); - if (!info) { - error.SetErrorString("No valid MemoryRegionInfo found!"); - return error; - } - range_info = info.getValue(); - return error; + range_info = m_minidump_parser.GetMemoryRegionInfo(load_addr); + return Status(); +} + +Status ProcessMinidump::GetMemoryRegions( + lldb_private::MemoryRegionInfos ®ion_list) { + region_list = m_minidump_parser.GetMemoryRegions(); + return Status(); } void ProcessMinidump::Clear() { Process::m_thread_list.Clear(); } bool ProcessMinidump::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list) { - uint32_t num_threads = 0; - if (m_thread_list.size() > 0) - num_threads = m_thread_list.size(); + for (const MinidumpThread& thread : m_thread_list) { + MinidumpLocationDescriptor context_location = thread.thread_context; + + // If the minidump contains an exception context, use it + if (m_active_exception != nullptr && + m_active_exception->thread_id == thread.thread_id) { + context_location = m_active_exception->thread_context; + } - for (lldb::tid_t tid = 0; tid < num_threads; ++tid) { llvm::ArrayRef<uint8_t> context; if (!m_is_wow64) - context = m_minidump_parser.GetThreadContext(m_thread_list[tid]); + context = m_minidump_parser.GetThreadContext(context_location); else - context = m_minidump_parser.GetThreadContextWow64(m_thread_list[tid]); + context = m_minidump_parser.GetThreadContextWow64(thread); - lldb::ThreadSP thread_sp( - new ThreadMinidump(*this, m_thread_list[tid], context)); + lldb::ThreadSP thread_sp(new ThreadMinidump(*this, thread, context)); new_thread_list.AddThread(thread_sp); } return new_thread_list.GetSize(false) > 0; @@ -344,8 +355,8 @@ void ProcessMinidump::ReadModuleList() { } const auto uuid = m_minidump_parser.GetModuleUUID(module); - const auto file_spec = - FileSpec(name.getValue(), true, GetArchitecture().GetTriple()); + auto file_spec = FileSpec(name.getValue(), GetArchitecture().GetTriple()); + FileSystem::Instance().Resolve(file_spec); ModuleSpec module_spec(file_spec, uuid); Status error; lldb::ModuleSP module_sp = GetTarget().GetSharedModule(module_spec, &error); @@ -357,6 +368,12 @@ void ProcessMinidump::ReadModuleList() { // This enables most LLDB functionality involving address-to-module // translations (ex. identifing the module for a stack frame PC) and // modules/sections commands (ex. target modules list, ...) + if (log) { + log->Printf("Unable to locate the matching object file, creating a " + "placeholder module for: %s", + name.getValue().c_str()); + } + auto placeholder_module = std::make_shared<PlaceholderModule>(module_spec); placeholder_module->CreateImageSection(module, GetTarget()); @@ -387,3 +404,248 @@ bool ProcessMinidump::GetProcessInfo(ProcessInstanceInfo &info) { } return true; } + +// For minidumps there's no runtime generated code so we don't need JITLoader(s) +// Avoiding them will also speed up minidump loading since JITLoaders normally +// try to set up symbolic breakpoints, which in turn may force loading more +// debug information than needed. +JITLoaderList &ProcessMinidump::GetJITLoaders() { + if (!m_jit_loaders_ap) { + m_jit_loaders_ap = llvm::make_unique<JITLoaderList>(); + } + return *m_jit_loaders_ap; +} + +#define INIT_BOOL(VAR, LONG, SHORT, DESC) \ + VAR(LLDB_OPT_SET_1, false, LONG, SHORT, DESC, false, true) +#define APPEND_OPT(VAR) \ + m_option_group.Append(&VAR, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1) + +class CommandObjectProcessMinidumpDump : public CommandObjectParsed { +private: + OptionGroupOptions m_option_group; + OptionGroupBoolean m_dump_all; + OptionGroupBoolean m_dump_directory; + OptionGroupBoolean m_dump_linux_cpuinfo; + OptionGroupBoolean m_dump_linux_proc_status; + OptionGroupBoolean m_dump_linux_lsb_release; + OptionGroupBoolean m_dump_linux_cmdline; + OptionGroupBoolean m_dump_linux_environ; + OptionGroupBoolean m_dump_linux_auxv; + OptionGroupBoolean m_dump_linux_maps; + OptionGroupBoolean m_dump_linux_proc_stat; + OptionGroupBoolean m_dump_linux_proc_uptime; + OptionGroupBoolean m_dump_linux_proc_fd; + OptionGroupBoolean m_dump_linux_all; + + void SetDefaultOptionsIfNoneAreSet() { + if (m_dump_all.GetOptionValue().GetCurrentValue() || + m_dump_linux_all.GetOptionValue().GetCurrentValue() || + m_dump_directory.GetOptionValue().GetCurrentValue() || + m_dump_linux_cpuinfo.GetOptionValue().GetCurrentValue() || + m_dump_linux_proc_status.GetOptionValue().GetCurrentValue() || + m_dump_linux_lsb_release.GetOptionValue().GetCurrentValue() || + m_dump_linux_cmdline.GetOptionValue().GetCurrentValue() || + m_dump_linux_environ.GetOptionValue().GetCurrentValue() || + m_dump_linux_auxv.GetOptionValue().GetCurrentValue() || + m_dump_linux_maps.GetOptionValue().GetCurrentValue() || + m_dump_linux_proc_stat.GetOptionValue().GetCurrentValue() || + m_dump_linux_proc_uptime.GetOptionValue().GetCurrentValue() || + m_dump_linux_proc_fd.GetOptionValue().GetCurrentValue()) + return; + // If no options were set, then dump everything + m_dump_all.GetOptionValue().SetCurrentValue(true); + } + bool DumpAll() const { + return m_dump_all.GetOptionValue().GetCurrentValue(); + } + bool DumpDirectory() const { + return DumpAll() || + m_dump_directory.GetOptionValue().GetCurrentValue(); + } + bool DumpLinux() const { + return DumpAll() || m_dump_linux_all.GetOptionValue().GetCurrentValue(); + } + bool DumpLinuxCPUInfo() const { + return DumpLinux() || + m_dump_linux_cpuinfo.GetOptionValue().GetCurrentValue(); + } + bool DumpLinuxProcStatus() const { + return DumpLinux() || + m_dump_linux_proc_status.GetOptionValue().GetCurrentValue(); + } + bool DumpLinuxProcStat() const { + return DumpLinux() || + m_dump_linux_proc_stat.GetOptionValue().GetCurrentValue(); + } + bool DumpLinuxLSBRelease() const { + return DumpLinux() || + m_dump_linux_lsb_release.GetOptionValue().GetCurrentValue(); + } + bool DumpLinuxCMDLine() const { + return DumpLinux() || + m_dump_linux_cmdline.GetOptionValue().GetCurrentValue(); + } + bool DumpLinuxEnviron() const { + return DumpLinux() || + m_dump_linux_environ.GetOptionValue().GetCurrentValue(); + } + bool DumpLinuxAuxv() const { + return DumpLinux() || + m_dump_linux_auxv.GetOptionValue().GetCurrentValue(); + } + bool DumpLinuxMaps() const { + return DumpLinux() || + m_dump_linux_maps.GetOptionValue().GetCurrentValue(); + } + bool DumpLinuxProcUptime() const { + return DumpLinux() || + m_dump_linux_proc_uptime.GetOptionValue().GetCurrentValue(); + } + bool DumpLinuxProcFD() const { + return DumpLinux() || + m_dump_linux_proc_fd.GetOptionValue().GetCurrentValue(); + } +public: + + CommandObjectProcessMinidumpDump(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "process plugin dump", + "Dump information from the minidump file.", NULL), + m_option_group(), + INIT_BOOL(m_dump_all, "all", 'a', + "Dump the everything in the minidump."), + INIT_BOOL(m_dump_directory, "directory", 'd', + "Dump the minidump directory map."), + INIT_BOOL(m_dump_linux_cpuinfo, "cpuinfo", 'C', + "Dump linux /proc/cpuinfo."), + INIT_BOOL(m_dump_linux_proc_status, "status", 's', + "Dump linux /proc/<pid>/status."), + INIT_BOOL(m_dump_linux_lsb_release, "lsb-release", 'r', + "Dump linux /etc/lsb-release."), + INIT_BOOL(m_dump_linux_cmdline, "cmdline", 'c', + "Dump linux /proc/<pid>/cmdline."), + INIT_BOOL(m_dump_linux_environ, "environ", 'e', + "Dump linux /proc/<pid>/environ."), + INIT_BOOL(m_dump_linux_auxv, "auxv", 'x', + "Dump linux /proc/<pid>/auxv."), + INIT_BOOL(m_dump_linux_maps, "maps", 'm', + "Dump linux /proc/<pid>/maps."), + INIT_BOOL(m_dump_linux_proc_stat, "stat", 'S', + "Dump linux /proc/<pid>/stat."), + INIT_BOOL(m_dump_linux_proc_uptime, "uptime", 'u', + "Dump linux process uptime."), + INIT_BOOL(m_dump_linux_proc_fd, "fd", 'f', + "Dump linux /proc/<pid>/fd."), + INIT_BOOL(m_dump_linux_all, "linux", 'l', + "Dump all linux streams.") { + APPEND_OPT(m_dump_all); + APPEND_OPT(m_dump_directory); + APPEND_OPT(m_dump_linux_cpuinfo); + APPEND_OPT(m_dump_linux_proc_status); + APPEND_OPT(m_dump_linux_lsb_release); + APPEND_OPT(m_dump_linux_cmdline); + APPEND_OPT(m_dump_linux_environ); + APPEND_OPT(m_dump_linux_auxv); + APPEND_OPT(m_dump_linux_maps); + APPEND_OPT(m_dump_linux_proc_stat); + APPEND_OPT(m_dump_linux_proc_uptime); + APPEND_OPT(m_dump_linux_proc_fd); + APPEND_OPT(m_dump_linux_all); + m_option_group.Finalize(); + } + + ~CommandObjectProcessMinidumpDump() {} + + Options *GetOptions() override { return &m_option_group; } + + bool DoExecute(Args &command, CommandReturnObject &result) override { + const size_t argc = command.GetArgumentCount(); + if (argc > 0) { + result.AppendErrorWithFormat("'%s' take no arguments, only options", + m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + SetDefaultOptionsIfNoneAreSet(); + + ProcessMinidump *process = static_cast<ProcessMinidump *>( + m_interpreter.GetExecutionContext().GetProcessPtr()); + result.SetStatus(eReturnStatusSuccessFinishResult); + Stream &s = result.GetOutputStream(); + MinidumpParser &minidump = process->m_minidump_parser; + if (DumpDirectory()) { + s.Printf("RVA SIZE TYPE MinidumpStreamType\n"); + s.Printf("---------- ---------- ---------- --------------------------\n"); + for (const auto &pair: minidump.GetDirectoryMap()) + s.Printf("0x%8.8x 0x%8.8x 0x%8.8x %s\n", (uint32_t)pair.second.rva, + (uint32_t)pair.second.data_size, pair.first, + MinidumpParser::GetStreamTypeAsString(pair.first).data()); + s.Printf("\n"); + } + auto DumpTextStream = [&](MinidumpStreamType stream_type, + llvm::StringRef label) -> void { + auto bytes = minidump.GetStream(stream_type); + if (!bytes.empty()) { + if (label.empty()) + label = MinidumpParser::GetStreamTypeAsString((uint32_t)stream_type); + s.Printf("%s:\n%s\n\n", label.data(), bytes.data()); + } + }; + auto DumpBinaryStream = [&](MinidumpStreamType stream_type, + llvm::StringRef label) -> void { + auto bytes = minidump.GetStream(stream_type); + if (!bytes.empty()) { + if (label.empty()) + label = MinidumpParser::GetStreamTypeAsString((uint32_t)stream_type); + s.Printf("%s:\n", label.data()); + DataExtractor data(bytes.data(), bytes.size(), eByteOrderLittle, + process->GetAddressByteSize()); + DumpDataExtractor(data, &s, 0, lldb::eFormatBytesWithASCII, 1, + bytes.size(), 16, 0, 0, 0); + s.Printf("\n\n"); + } + }; + + if (DumpLinuxCPUInfo()) + DumpTextStream(MinidumpStreamType::LinuxCPUInfo, "/proc/cpuinfo"); + if (DumpLinuxProcStatus()) + DumpTextStream(MinidumpStreamType::LinuxProcStatus, "/proc/PID/status"); + if (DumpLinuxLSBRelease()) + DumpTextStream(MinidumpStreamType::LinuxLSBRelease, "/etc/lsb-release"); + if (DumpLinuxCMDLine()) + DumpTextStream(MinidumpStreamType::LinuxCMDLine, "/proc/PID/cmdline"); + if (DumpLinuxEnviron()) + DumpTextStream(MinidumpStreamType::LinuxEnviron, "/proc/PID/environ"); + if (DumpLinuxAuxv()) + DumpBinaryStream(MinidumpStreamType::LinuxAuxv, "/proc/PID/auxv"); + if (DumpLinuxMaps()) + DumpTextStream(MinidumpStreamType::LinuxMaps, "/proc/PID/maps"); + if (DumpLinuxProcStat()) + DumpTextStream(MinidumpStreamType::LinuxProcStat, "/proc/PID/stat"); + if (DumpLinuxProcUptime()) + DumpTextStream(MinidumpStreamType::LinuxProcUptime, "uptime"); + if (DumpLinuxProcFD()) + DumpTextStream(MinidumpStreamType::LinuxProcFD, "/proc/PID/fd"); + return true; + } +}; + +class CommandObjectMultiwordProcessMinidump : public CommandObjectMultiword { +public: + CommandObjectMultiwordProcessMinidump(CommandInterpreter &interpreter) + : CommandObjectMultiword(interpreter, "process plugin", + "Commands for operating on a ProcessMinidump process.", + "process plugin <subcommand> [<subcommand-options>]") { + LoadSubCommand("dump", + CommandObjectSP(new CommandObjectProcessMinidumpDump(interpreter))); + } + + ~CommandObjectMultiwordProcessMinidump() {} +}; + +CommandObject *ProcessMinidump::GetPluginCommandObject() { + if (!m_command_sp) + m_command_sp.reset(new CommandObjectMultiwordProcessMinidump( + GetTarget().GetDebugger().GetCommandInterpreter())); + return m_command_sp.get(); +} |