blob: c702d843809e6eeeab13b2a86987f21bcd1b1ec7 [file] [log] [blame]
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +00001//===-- ProcessMinidump.cpp -------------------------------------*- C++ -*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +00006//
7//===----------------------------------------------------------------------===//
8
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +00009#include "ProcessMinidump.h"
Jonas Devlieghere796ac802019-02-11 23:13:08 +000010
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +000011#include "ThreadMinidump.h"
12
Greg Clayton48a28c12018-12-18 00:50:11 +000013#include "lldb/Core/DumpDataExtractor.h"
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +000014#include "lldb/Core/Module.h"
15#include "lldb/Core/ModuleSpec.h"
16#include "lldb/Core/PluginManager.h"
17#include "lldb/Core/Section.h"
Greg Clayton48a28c12018-12-18 00:50:11 +000018#include "lldb/Interpreter/CommandInterpreter.h"
19#include "lldb/Interpreter/CommandObject.h"
20#include "lldb/Interpreter/CommandObjectMultiword.h"
21#include "lldb/Interpreter/CommandReturnObject.h"
22#include "lldb/Interpreter/OptionArgParser.h"
23#include "lldb/Interpreter/OptionGroupBoolean.h"
Leonard Mosescu40b832e2018-08-23 21:34:33 +000024#include "lldb/Target/JITLoaderList.h"
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +000025#include "lldb/Target/MemoryRegionInfo.h"
Leonard Mosescu47196a22018-04-18 23:10:46 +000026#include "lldb/Target/SectionLoadList.h"
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +000027#include "lldb/Target/Target.h"
28#include "lldb/Target/UnixSignals.h"
29#include "lldb/Utility/LLDBAssert.h"
Zachary Turner6f9e6902017-03-03 20:56:28 +000030#include "lldb/Utility/Log.h"
Pavel Labathd821c992018-08-07 11:07:21 +000031#include "lldb/Utility/State.h"
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +000032
Zachary Turner3f4a4b32017-02-24 18:56:49 +000033#include "llvm/Support/MemoryBuffer.h"
Kamil Rytarowskic5f28e22017-02-06 17:55:02 +000034#include "llvm/Support/Threading.h"
35
Greg Clayton19c8f392018-08-06 16:56:10 +000036#include "Plugins/Process/Utility/StopInfoMachException.h"
Leonard Mosescu0d057902019-01-07 17:55:42 +000037
Jonas Devlieghere796ac802019-02-11 23:13:08 +000038#include <memory>
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +000039
Leonard Mosescu47196a22018-04-18 23:10:46 +000040using namespace lldb;
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +000041using namespace lldb_private;
42using namespace minidump;
43
Pavel Labathcfc3f752019-02-11 10:30:24 +000044//------------------------------------------------------------------
45/// A placeholder module used for minidumps, where the original
46/// object files may not be available (so we can't parse the object
47/// files to extract the set of sections/segments)
48///
49/// This placeholder module has a single synthetic section (.module_image)
50/// which represents the module memory range covering the whole module.
51//------------------------------------------------------------------
52class PlaceholderModule : public Module {
Leonard Mosescu47196a22018-04-18 23:10:46 +000053public:
Pavel Labathcfc3f752019-02-11 10:30:24 +000054 PlaceholderModule(const ModuleSpec &module_spec) :
55 Module(module_spec.GetFileSpec(), module_spec.GetArchitecture()) {
56 if (module_spec.GetUUID().IsValid())
57 SetUUID(module_spec.GetUUID());
Leonard Mosescu9fecd372018-05-02 20:06:17 +000058 }
Leonard Mosescu47196a22018-04-18 23:10:46 +000059
Pavel Labathcfc3f752019-02-11 10:30:24 +000060 // Creates a synthetic module section covering the whole module image (and
61 // sets the section load address as well)
62 void CreateImageSection(const MinidumpModule *module, Target& target) {
63 const ConstString section_name(".module_image");
64 lldb::SectionSP section_sp(new Section(
65 shared_from_this(), // Module to which this section belongs.
66 nullptr, // ObjectFile
67 0, // Section ID.
68 section_name, // Section name.
69 eSectionTypeContainer, // Section type.
70 module->base_of_image, // VM address.
71 module->size_of_image, // VM size in bytes of this section.
72 0, // Offset of this section in the file.
73 module->size_of_image, // Size of the section as found in the file.
74 12, // Alignment of the section (log2)
75 0, // Flags for this section.
76 1)); // Number of host bytes per target byte
77 section_sp->SetPermissions(ePermissionsExecutable | ePermissionsReadable);
78 GetSectionList()->AddSection(section_sp);
Leonard Mosescu47196a22018-04-18 23:10:46 +000079 target.GetSectionLoadList().SetSectionLoadAddress(
Pavel Labathcfc3f752019-02-11 10:30:24 +000080 section_sp, module->base_of_image);
Leonard Mosescu47196a22018-04-18 23:10:46 +000081 }
82
Pavel Labathcfc3f752019-02-11 10:30:24 +000083ObjectFile *GetObjectFile() override { return nullptr; }
Pavel Labath734648b2019-02-11 09:32:08 +000084
Pavel Labathcfc3f752019-02-11 10:30:24 +000085 SectionList *GetSectionList() override {
86 return Module::GetUnifiedSectionList();
87 }
Leonard Mosescu47196a22018-04-18 23:10:46 +000088};
89
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +000090ConstString ProcessMinidump::GetPluginNameStatic() {
91 static ConstString g_name("minidump");
92 return g_name;
93}
94
95const char *ProcessMinidump::GetPluginDescriptionStatic() {
96 return "Minidump plug-in.";
97}
98
99lldb::ProcessSP ProcessMinidump::CreateInstance(lldb::TargetSP target_sp,
100 lldb::ListenerSP listener_sp,
101 const FileSpec *crash_file) {
102 if (!crash_file)
103 return nullptr;
104
105 lldb::ProcessSP process_sp;
106 // Read enough data for the Minidump header
Zachary Turner3f4a4b32017-02-24 18:56:49 +0000107 constexpr size_t header_size = sizeof(MinidumpHeader);
Jonas Devlieghere87e403a2018-11-12 21:24:50 +0000108 auto DataPtr = FileSystem::Instance().CreateDataBuffer(crash_file->GetPath(),
109 header_size, 0);
Zachary Turner3f4a4b32017-02-24 18:56:49 +0000110 if (!DataPtr)
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000111 return nullptr;
112
Leonard Mosescu2ae3ec32018-07-12 17:27:18 +0000113 lldbassert(DataPtr->GetByteSize() == header_size);
Zachary Turner3f4a4b32017-02-24 18:56:49 +0000114
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000115 // first, only try to parse the header, beacuse we need to be fast
Zachary Turner3f4a4b32017-02-24 18:56:49 +0000116 llvm::ArrayRef<uint8_t> HeaderBytes = DataPtr->GetData();
117 const MinidumpHeader *header = MinidumpHeader::Parse(HeaderBytes);
118 if (header == nullptr)
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000119 return nullptr;
120
Jonas Devlieghere87e403a2018-11-12 21:24:50 +0000121 auto AllData =
122 FileSystem::Instance().CreateDataBuffer(crash_file->GetPath(), -1, 0);
Zachary Turner3f4a4b32017-02-24 18:56:49 +0000123 if (!AllData)
124 return nullptr;
125
126 auto minidump_parser = MinidumpParser::Create(AllData);
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000127 // check if the parser object is valid
Pavel Labath222fd132016-11-09 10:16:11 +0000128 if (!minidump_parser)
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000129 return nullptr;
130
131 return std::make_shared<ProcessMinidump>(target_sp, listener_sp, *crash_file,
132 minidump_parser.getValue());
133}
134
135bool ProcessMinidump::CanDebug(lldb::TargetSP target_sp,
136 bool plugin_specified_by_name) {
137 return true;
138}
139
140ProcessMinidump::ProcessMinidump(lldb::TargetSP target_sp,
141 lldb::ListenerSP listener_sp,
142 const FileSpec &core_file,
143 MinidumpParser minidump_parser)
144 : Process(target_sp, listener_sp), m_minidump_parser(minidump_parser),
145 m_core_file(core_file), m_is_wow64(false) {}
146
147ProcessMinidump::~ProcessMinidump() {
148 Clear();
Adrian Prantl05097242018-04-30 16:49:04 +0000149 // We need to call finalize on the process before destroying ourselves to
150 // make sure all of the broadcaster cleanup goes as planned. If we destruct
151 // this class, then Process::~Process() might have problems trying to fully
152 // destroy the broadcaster.
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000153 Finalize();
154}
155
156void ProcessMinidump::Initialize() {
Kamil Rytarowskic5f28e22017-02-06 17:55:02 +0000157 static llvm::once_flag g_once_flag;
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000158
Kamil Rytarowskic5f28e22017-02-06 17:55:02 +0000159 llvm::call_once(g_once_flag, []() {
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000160 PluginManager::RegisterPlugin(GetPluginNameStatic(),
161 GetPluginDescriptionStatic(),
162 ProcessMinidump::CreateInstance);
163 });
164}
165
166void ProcessMinidump::Terminate() {
167 PluginManager::UnregisterPlugin(ProcessMinidump::CreateInstance);
168}
169
Zachary Turner97206d52017-05-12 04:51:55 +0000170Status ProcessMinidump::DoLoadCore() {
171 Status error;
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000172
Leonard Mosescu2ae3ec32018-07-12 17:27:18 +0000173 // Minidump parser initialization & consistency checks
174 error = m_minidump_parser.Initialize();
175 if (error.Fail())
176 return error;
177
178 // Do we support the minidump's architecture?
179 ArchSpec arch = GetArchitecture();
180 switch (arch.GetMachine()) {
181 case llvm::Triple::x86:
182 case llvm::Triple::x86_64:
Greg Clayton19c8f392018-08-06 16:56:10 +0000183 case llvm::Triple::arm:
184 case llvm::Triple::aarch64:
185 // Any supported architectures must be listed here and also supported in
186 // ThreadMinidump::CreateRegisterContextForFrame().
Leonard Mosescu2ae3ec32018-07-12 17:27:18 +0000187 break;
Leonard Mosescu2ae3ec32018-07-12 17:27:18 +0000188 default:
189 error.SetErrorStringWithFormat("unsupported minidump architecture: %s",
190 arch.GetArchitectureName());
191 return error;
192 }
Greg Clayton19c8f392018-08-06 16:56:10 +0000193 GetTarget().SetArchitecture(arch, true /*set_platform*/);
Leonard Mosescu2ae3ec32018-07-12 17:27:18 +0000194
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000195 m_thread_list = m_minidump_parser.GetThreads();
196 m_active_exception = m_minidump_parser.GetExceptionStream();
197 ReadModuleList();
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000198
199 llvm::Optional<lldb::pid_t> pid = m_minidump_parser.GetPid();
200 if (!pid) {
201 error.SetErrorString("failed to parse PID");
202 return error;
203 }
204 SetID(pid.getValue());
205
206 return error;
207}
208
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000209ConstString ProcessMinidump::GetPluginName() { return GetPluginNameStatic(); }
210
211uint32_t ProcessMinidump::GetPluginVersion() { return 1; }
212
Zachary Turner97206d52017-05-12 04:51:55 +0000213Status ProcessMinidump::DoDestroy() { return Status(); }
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000214
215void ProcessMinidump::RefreshStateAfterStop() {
216 if (!m_active_exception)
217 return;
218
219 if (m_active_exception->exception_record.exception_code ==
220 MinidumpException::DumpRequested) {
221 return;
222 }
223
224 lldb::StopInfoSP stop_info;
225 lldb::ThreadSP stop_thread;
226
227 Process::m_thread_list.SetSelectedThreadByID(m_active_exception->thread_id);
228 stop_thread = Process::m_thread_list.GetSelectedThread();
229 ArchSpec arch = GetArchitecture();
230
231 if (arch.GetTriple().getOS() == llvm::Triple::Linux) {
232 stop_info = StopInfo::CreateStopReasonWithSignal(
233 *stop_thread, m_active_exception->exception_record.exception_code);
Greg Clayton19c8f392018-08-06 16:56:10 +0000234 } else if (arch.GetTriple().getVendor() == llvm::Triple::Apple) {
235 stop_info = StopInfoMachException::CreateStopReasonWithMachException(
236 *stop_thread, m_active_exception->exception_record.exception_code, 2,
237 m_active_exception->exception_record.exception_flags,
238 m_active_exception->exception_record.exception_address, 0);
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000239 } else {
240 std::string desc;
241 llvm::raw_string_ostream desc_stream(desc);
242 desc_stream << "Exception "
243 << llvm::format_hex(
244 m_active_exception->exception_record.exception_code, 8)
245 << " encountered at address "
246 << llvm::format_hex(
247 m_active_exception->exception_record.exception_address,
248 8);
249 stop_info = StopInfo::CreateStopReasonWithException(
250 *stop_thread, desc_stream.str().c_str());
251 }
252
253 stop_thread->SetStopInfo(stop_info);
254}
255
256bool ProcessMinidump::IsAlive() { return true; }
257
258bool ProcessMinidump::WarnBeforeDetach() const { return false; }
259
260size_t ProcessMinidump::ReadMemory(lldb::addr_t addr, void *buf, size_t size,
Zachary Turner97206d52017-05-12 04:51:55 +0000261 Status &error) {
Adrian Prantl05097242018-04-30 16:49:04 +0000262 // Don't allow the caching that lldb_private::Process::ReadMemory does since
263 // we have it all cached in our dump file anyway.
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000264 return DoReadMemory(addr, buf, size, error);
265}
266
267size_t ProcessMinidump::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
Zachary Turner97206d52017-05-12 04:51:55 +0000268 Status &error) {
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000269
270 llvm::ArrayRef<uint8_t> mem = m_minidump_parser.GetMemory(addr, size);
271 if (mem.empty()) {
272 error.SetErrorString("could not parse memory info");
273 return 0;
274 }
275
276 std::memcpy(buf, mem.data(), mem.size());
277 return mem.size();
278}
279
280ArchSpec ProcessMinidump::GetArchitecture() {
281 if (!m_is_wow64) {
282 return m_minidump_parser.GetArchitecture();
283 }
284
285 llvm::Triple triple;
286 triple.setVendor(llvm::Triple::VendorType::UnknownVendor);
287 triple.setArch(llvm::Triple::ArchType::x86);
288 triple.setOS(llvm::Triple::OSType::Win32);
289 return ArchSpec(triple);
290}
291
Zachary Turner97206d52017-05-12 04:51:55 +0000292Status ProcessMinidump::GetMemoryRegionInfo(lldb::addr_t load_addr,
293 MemoryRegionInfo &range_info) {
Greg Clayton026e1bf2018-12-14 19:36:01 +0000294 range_info = m_minidump_parser.GetMemoryRegionInfo(load_addr);
295 return Status();
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000296}
297
Tatyana Krasnukha92e5e362018-12-20 15:05:43 +0000298Status ProcessMinidump::GetMemoryRegions(
299 lldb_private::MemoryRegionInfos &region_list) {
300 region_list = m_minidump_parser.GetMemoryRegions();
301 return Status();
302}
303
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000304void ProcessMinidump::Clear() { Process::m_thread_list.Clear(); }
305
Dimitar Vlahovski5a19c0c2016-11-01 15:48:24 +0000306bool ProcessMinidump::UpdateThreadList(ThreadList &old_thread_list,
307 ThreadList &new_thread_list) {
Leonard Mosescu0d057902019-01-07 17:55:42 +0000308 for (const MinidumpThread& thread : m_thread_list) {
309 MinidumpLocationDescriptor context_location = thread.thread_context;
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000310
Leonard Mosescu0d057902019-01-07 17:55:42 +0000311 // If the minidump contains an exception context, use it
312 if (m_active_exception != nullptr &&
313 m_active_exception->thread_id == thread.thread_id) {
314 context_location = m_active_exception->thread_context;
315 }
316
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000317 llvm::ArrayRef<uint8_t> context;
318 if (!m_is_wow64)
Leonard Mosescu0d057902019-01-07 17:55:42 +0000319 context = m_minidump_parser.GetThreadContext(context_location);
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000320 else
Leonard Mosescu0d057902019-01-07 17:55:42 +0000321 context = m_minidump_parser.GetThreadContextWow64(thread);
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000322
Leonard Mosescu0d057902019-01-07 17:55:42 +0000323 lldb::ThreadSP thread_sp(new ThreadMinidump(*this, thread, context));
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000324 new_thread_list.AddThread(thread_sp);
325 }
326 return new_thread_list.GetSize(false) > 0;
327}
328
329void ProcessMinidump::ReadModuleList() {
330 std::vector<const MinidumpModule *> filtered_modules =
331 m_minidump_parser.GetFilteredModuleList();
332
333 for (auto module : filtered_modules) {
334 llvm::Optional<std::string> name =
335 m_minidump_parser.GetMinidumpString(module->module_name_rva);
336
337 if (!name)
338 continue;
339
340 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES));
341 if (log) {
Pavel Labatheaa419c2016-11-02 10:29:47 +0000342 log->Printf("ProcessMinidump::%s found module: name: %s %#010" PRIx64
343 "-%#010" PRIx64 " size: %" PRIu32,
344 __FUNCTION__, name.getValue().c_str(),
345 uint64_t(module->base_of_image),
346 module->base_of_image + module->size_of_image,
347 uint32_t(module->size_of_image));
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000348 }
349
350 // check if the process is wow64 - a 32 bit windows process running on a
351 // 64 bit windows
352 if (llvm::StringRef(name.getValue()).endswith_lower("wow64.dll")) {
353 m_is_wow64 = true;
354 }
355
Leonard Mosescu9fecd372018-05-02 20:06:17 +0000356 const auto uuid = m_minidump_parser.GetModuleUUID(module);
Jonas Devlieghere8f3be7a2018-11-01 21:05:36 +0000357 auto file_spec = FileSpec(name.getValue(), GetArchitecture().GetTriple());
358 FileSystem::Instance().Resolve(file_spec);
Leonard Mosescu9fecd372018-05-02 20:06:17 +0000359 ModuleSpec module_spec(file_spec, uuid);
Zachary Turner97206d52017-05-12 04:51:55 +0000360 Status error;
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000361 lldb::ModuleSP module_sp = GetTarget().GetSharedModule(module_spec, &error);
362 if (!module_sp || error.Fail()) {
Adrian Prantl05097242018-04-30 16:49:04 +0000363 // We failed to locate a matching local object file. Fortunately, the
364 // minidump format encodes enough information about each module's memory
365 // range to allow us to create placeholder modules.
Leonard Mosescu47196a22018-04-18 23:10:46 +0000366 //
367 // This enables most LLDB functionality involving address-to-module
368 // translations (ex. identifing the module for a stack frame PC) and
369 // modules/sections commands (ex. target modules list, ...)
Leonard Mosescu9ba51572018-08-07 18:00:30 +0000370 if (log) {
371 log->Printf("Unable to locate the matching object file, creating a "
372 "placeholder module for: %s",
373 name.getValue().c_str());
374 }
375
Pavel Labathcfc3f752019-02-11 10:30:24 +0000376 auto placeholder_module =
377 std::make_shared<PlaceholderModule>(module_spec);
378 placeholder_module->CreateImageSection(module, GetTarget());
379 module_sp = placeholder_module;
Leonard Mosescu47196a22018-04-18 23:10:46 +0000380 GetTarget().GetImages().Append(module_sp);
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000381 }
382
383 if (log) {
384 log->Printf("ProcessMinidump::%s load module: name: %s", __FUNCTION__,
385 name.getValue().c_str());
386 }
387
388 bool load_addr_changed = false;
389 module_sp->SetLoadAddress(GetTarget(), module->base_of_image, false,
390 load_addr_changed);
391 }
392}
Dimitar Vlahovski5a19c0c2016-11-01 15:48:24 +0000393
394bool ProcessMinidump::GetProcessInfo(ProcessInstanceInfo &info) {
395 info.Clear();
396 info.SetProcessID(GetID());
397 info.SetArchitecture(GetArchitecture());
398 lldb::ModuleSP module_sp = GetTarget().GetExecutableModule();
399 if (module_sp) {
400 const bool add_exe_file_as_first_arg = false;
401 info.SetExecutableFile(GetTarget().GetExecutableModule()->GetFileSpec(),
402 add_exe_file_as_first_arg);
403 }
404 return true;
405}
Leonard Mosescu40b832e2018-08-23 21:34:33 +0000406
407// For minidumps there's no runtime generated code so we don't need JITLoader(s)
408// Avoiding them will also speed up minidump loading since JITLoaders normally
409// try to set up symbolic breakpoints, which in turn may force loading more
410// debug information than needed.
411JITLoaderList &ProcessMinidump::GetJITLoaders() {
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000412 if (!m_jit_loaders_up) {
413 m_jit_loaders_up = llvm::make_unique<JITLoaderList>();
Leonard Mosescu40b832e2018-08-23 21:34:33 +0000414 }
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000415 return *m_jit_loaders_up;
Leonard Mosescu40b832e2018-08-23 21:34:33 +0000416}
Greg Clayton48a28c12018-12-18 00:50:11 +0000417
418#define INIT_BOOL(VAR, LONG, SHORT, DESC) \
419 VAR(LLDB_OPT_SET_1, false, LONG, SHORT, DESC, false, true)
420#define APPEND_OPT(VAR) \
421 m_option_group.Append(&VAR, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1)
422
423class CommandObjectProcessMinidumpDump : public CommandObjectParsed {
424private:
425 OptionGroupOptions m_option_group;
426 OptionGroupBoolean m_dump_all;
427 OptionGroupBoolean m_dump_directory;
428 OptionGroupBoolean m_dump_linux_cpuinfo;
429 OptionGroupBoolean m_dump_linux_proc_status;
430 OptionGroupBoolean m_dump_linux_lsb_release;
431 OptionGroupBoolean m_dump_linux_cmdline;
432 OptionGroupBoolean m_dump_linux_environ;
433 OptionGroupBoolean m_dump_linux_auxv;
434 OptionGroupBoolean m_dump_linux_maps;
435 OptionGroupBoolean m_dump_linux_proc_stat;
436 OptionGroupBoolean m_dump_linux_proc_uptime;
437 OptionGroupBoolean m_dump_linux_proc_fd;
438 OptionGroupBoolean m_dump_linux_all;
439
440 void SetDefaultOptionsIfNoneAreSet() {
441 if (m_dump_all.GetOptionValue().GetCurrentValue() ||
442 m_dump_linux_all.GetOptionValue().GetCurrentValue() ||
443 m_dump_directory.GetOptionValue().GetCurrentValue() ||
444 m_dump_linux_cpuinfo.GetOptionValue().GetCurrentValue() ||
445 m_dump_linux_proc_status.GetOptionValue().GetCurrentValue() ||
446 m_dump_linux_lsb_release.GetOptionValue().GetCurrentValue() ||
447 m_dump_linux_cmdline.GetOptionValue().GetCurrentValue() ||
448 m_dump_linux_environ.GetOptionValue().GetCurrentValue() ||
449 m_dump_linux_auxv.GetOptionValue().GetCurrentValue() ||
450 m_dump_linux_maps.GetOptionValue().GetCurrentValue() ||
451 m_dump_linux_proc_stat.GetOptionValue().GetCurrentValue() ||
452 m_dump_linux_proc_uptime.GetOptionValue().GetCurrentValue() ||
453 m_dump_linux_proc_fd.GetOptionValue().GetCurrentValue())
454 return;
455 // If no options were set, then dump everything
456 m_dump_all.GetOptionValue().SetCurrentValue(true);
457 }
458 bool DumpAll() const {
459 return m_dump_all.GetOptionValue().GetCurrentValue();
460 }
461 bool DumpDirectory() const {
462 return DumpAll() ||
463 m_dump_directory.GetOptionValue().GetCurrentValue();
464 }
465 bool DumpLinux() const {
466 return DumpAll() || m_dump_linux_all.GetOptionValue().GetCurrentValue();
467 }
468 bool DumpLinuxCPUInfo() const {
469 return DumpLinux() ||
470 m_dump_linux_cpuinfo.GetOptionValue().GetCurrentValue();
471 }
472 bool DumpLinuxProcStatus() const {
473 return DumpLinux() ||
474 m_dump_linux_proc_status.GetOptionValue().GetCurrentValue();
475 }
476 bool DumpLinuxProcStat() const {
477 return DumpLinux() ||
478 m_dump_linux_proc_stat.GetOptionValue().GetCurrentValue();
479 }
480 bool DumpLinuxLSBRelease() const {
481 return DumpLinux() ||
482 m_dump_linux_lsb_release.GetOptionValue().GetCurrentValue();
483 }
484 bool DumpLinuxCMDLine() const {
485 return DumpLinux() ||
486 m_dump_linux_cmdline.GetOptionValue().GetCurrentValue();
487 }
488 bool DumpLinuxEnviron() const {
489 return DumpLinux() ||
490 m_dump_linux_environ.GetOptionValue().GetCurrentValue();
491 }
492 bool DumpLinuxAuxv() const {
493 return DumpLinux() ||
494 m_dump_linux_auxv.GetOptionValue().GetCurrentValue();
495 }
496 bool DumpLinuxMaps() const {
497 return DumpLinux() ||
498 m_dump_linux_maps.GetOptionValue().GetCurrentValue();
499 }
500 bool DumpLinuxProcUptime() const {
501 return DumpLinux() ||
502 m_dump_linux_proc_uptime.GetOptionValue().GetCurrentValue();
503 }
504 bool DumpLinuxProcFD() const {
505 return DumpLinux() ||
506 m_dump_linux_proc_fd.GetOptionValue().GetCurrentValue();
507 }
508public:
509
510 CommandObjectProcessMinidumpDump(CommandInterpreter &interpreter)
511 : CommandObjectParsed(interpreter, "process plugin dump",
512 "Dump information from the minidump file.", NULL),
513 m_option_group(),
514 INIT_BOOL(m_dump_all, "all", 'a',
515 "Dump the everything in the minidump."),
516 INIT_BOOL(m_dump_directory, "directory", 'd',
517 "Dump the minidump directory map."),
518 INIT_BOOL(m_dump_linux_cpuinfo, "cpuinfo", 'C',
519 "Dump linux /proc/cpuinfo."),
520 INIT_BOOL(m_dump_linux_proc_status, "status", 's',
521 "Dump linux /proc/<pid>/status."),
522 INIT_BOOL(m_dump_linux_lsb_release, "lsb-release", 'r',
523 "Dump linux /etc/lsb-release."),
524 INIT_BOOL(m_dump_linux_cmdline, "cmdline", 'c',
525 "Dump linux /proc/<pid>/cmdline."),
526 INIT_BOOL(m_dump_linux_environ, "environ", 'e',
527 "Dump linux /proc/<pid>/environ."),
528 INIT_BOOL(m_dump_linux_auxv, "auxv", 'x',
529 "Dump linux /proc/<pid>/auxv."),
530 INIT_BOOL(m_dump_linux_maps, "maps", 'm',
531 "Dump linux /proc/<pid>/maps."),
532 INIT_BOOL(m_dump_linux_proc_stat, "stat", 'S',
533 "Dump linux /proc/<pid>/stat."),
534 INIT_BOOL(m_dump_linux_proc_uptime, "uptime", 'u',
535 "Dump linux process uptime."),
536 INIT_BOOL(m_dump_linux_proc_fd, "fd", 'f',
537 "Dump linux /proc/<pid>/fd."),
538 INIT_BOOL(m_dump_linux_all, "linux", 'l',
539 "Dump all linux streams.") {
540 APPEND_OPT(m_dump_all);
541 APPEND_OPT(m_dump_directory);
542 APPEND_OPT(m_dump_linux_cpuinfo);
543 APPEND_OPT(m_dump_linux_proc_status);
544 APPEND_OPT(m_dump_linux_lsb_release);
545 APPEND_OPT(m_dump_linux_cmdline);
546 APPEND_OPT(m_dump_linux_environ);
547 APPEND_OPT(m_dump_linux_auxv);
548 APPEND_OPT(m_dump_linux_maps);
549 APPEND_OPT(m_dump_linux_proc_stat);
550 APPEND_OPT(m_dump_linux_proc_uptime);
551 APPEND_OPT(m_dump_linux_proc_fd);
552 APPEND_OPT(m_dump_linux_all);
553 m_option_group.Finalize();
554 }
Leonard Mosescu0d057902019-01-07 17:55:42 +0000555
Greg Clayton48a28c12018-12-18 00:50:11 +0000556 ~CommandObjectProcessMinidumpDump() {}
Leonard Mosescu0d057902019-01-07 17:55:42 +0000557
Greg Clayton48a28c12018-12-18 00:50:11 +0000558 Options *GetOptions() override { return &m_option_group; }
559
560 bool DoExecute(Args &command, CommandReturnObject &result) override {
561 const size_t argc = command.GetArgumentCount();
562 if (argc > 0) {
563 result.AppendErrorWithFormat("'%s' take no arguments, only options",
564 m_cmd_name.c_str());
565 result.SetStatus(eReturnStatusFailed);
566 return false;
567 }
568 SetDefaultOptionsIfNoneAreSet();
Leonard Mosescu0d057902019-01-07 17:55:42 +0000569
Greg Clayton48a28c12018-12-18 00:50:11 +0000570 ProcessMinidump *process = static_cast<ProcessMinidump *>(
571 m_interpreter.GetExecutionContext().GetProcessPtr());
572 result.SetStatus(eReturnStatusSuccessFinishResult);
573 Stream &s = result.GetOutputStream();
574 MinidumpParser &minidump = process->m_minidump_parser;
575 if (DumpDirectory()) {
576 s.Printf("RVA SIZE TYPE MinidumpStreamType\n");
577 s.Printf("---------- ---------- ---------- --------------------------\n");
578 for (const auto &pair: minidump.GetDirectoryMap())
579 s.Printf("0x%8.8x 0x%8.8x 0x%8.8x %s\n", (uint32_t)pair.second.rva,
580 (uint32_t)pair.second.data_size, pair.first,
581 MinidumpParser::GetStreamTypeAsString(pair.first).data());
582 s.Printf("\n");
583 }
584 auto DumpTextStream = [&](MinidumpStreamType stream_type,
Pavel Labath796984d2018-12-27 09:44:32 +0000585 llvm::StringRef label) -> void {
Greg Clayton48a28c12018-12-18 00:50:11 +0000586 auto bytes = minidump.GetStream(stream_type);
587 if (!bytes.empty()) {
588 if (label.empty())
589 label = MinidumpParser::GetStreamTypeAsString((uint32_t)stream_type);
590 s.Printf("%s:\n%s\n\n", label.data(), bytes.data());
591 }
592 };
593 auto DumpBinaryStream = [&](MinidumpStreamType stream_type,
Pavel Labath796984d2018-12-27 09:44:32 +0000594 llvm::StringRef label) -> void {
Greg Clayton48a28c12018-12-18 00:50:11 +0000595 auto bytes = minidump.GetStream(stream_type);
596 if (!bytes.empty()) {
597 if (label.empty())
598 label = MinidumpParser::GetStreamTypeAsString((uint32_t)stream_type);
599 s.Printf("%s:\n", label.data());
600 DataExtractor data(bytes.data(), bytes.size(), eByteOrderLittle,
601 process->GetAddressByteSize());
602 DumpDataExtractor(data, &s, 0, lldb::eFormatBytesWithASCII, 1,
603 bytes.size(), 16, 0, 0, 0);
604 s.Printf("\n\n");
605 }
606 };
607
608 if (DumpLinuxCPUInfo())
609 DumpTextStream(MinidumpStreamType::LinuxCPUInfo, "/proc/cpuinfo");
610 if (DumpLinuxProcStatus())
611 DumpTextStream(MinidumpStreamType::LinuxProcStatus, "/proc/PID/status");
612 if (DumpLinuxLSBRelease())
613 DumpTextStream(MinidumpStreamType::LinuxLSBRelease, "/etc/lsb-release");
614 if (DumpLinuxCMDLine())
615 DumpTextStream(MinidumpStreamType::LinuxCMDLine, "/proc/PID/cmdline");
616 if (DumpLinuxEnviron())
617 DumpTextStream(MinidumpStreamType::LinuxEnviron, "/proc/PID/environ");
618 if (DumpLinuxAuxv())
619 DumpBinaryStream(MinidumpStreamType::LinuxAuxv, "/proc/PID/auxv");
620 if (DumpLinuxMaps())
621 DumpTextStream(MinidumpStreamType::LinuxMaps, "/proc/PID/maps");
622 if (DumpLinuxProcStat())
623 DumpTextStream(MinidumpStreamType::LinuxProcStat, "/proc/PID/stat");
624 if (DumpLinuxProcUptime())
625 DumpTextStream(MinidumpStreamType::LinuxProcUptime, "uptime");
626 if (DumpLinuxProcFD())
627 DumpTextStream(MinidumpStreamType::LinuxProcFD, "/proc/PID/fd");
628 return true;
629 }
630};
631
632class CommandObjectMultiwordProcessMinidump : public CommandObjectMultiword {
633public:
634 CommandObjectMultiwordProcessMinidump(CommandInterpreter &interpreter)
635 : CommandObjectMultiword(interpreter, "process plugin",
636 "Commands for operating on a ProcessMinidump process.",
637 "process plugin <subcommand> [<subcommand-options>]") {
638 LoadSubCommand("dump",
639 CommandObjectSP(new CommandObjectProcessMinidumpDump(interpreter)));
640 }
Leonard Mosescu0d057902019-01-07 17:55:42 +0000641
Greg Clayton48a28c12018-12-18 00:50:11 +0000642 ~CommandObjectMultiwordProcessMinidump() {}
643};
644
645CommandObject *ProcessMinidump::GetPluginCommandObject() {
646 if (!m_command_sp)
Jonas Devlieghere796ac802019-02-11 23:13:08 +0000647 m_command_sp = std::make_shared<CommandObjectMultiwordProcessMinidump>(
648 GetTarget().GetDebugger().GetCommandInterpreter());
Greg Clayton48a28c12018-12-18 00:50:11 +0000649 return m_command_sp.get();
650}