blob: c5cca7ea62c69efb89aafd00d59e8ddfca3cb327 [file] [log] [blame]
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +00001//===-- ProcessMinidump.cpp -------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +000010#include "ProcessMinidump.h"
11#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
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +000038// C includes
39// C++ includes
40
Leonard Mosescu47196a22018-04-18 23:10:46 +000041using namespace lldb;
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +000042using namespace lldb_private;
43using namespace minidump;
44
Leonard Mosescu47196a22018-04-18 23:10:46 +000045//------------------------------------------------------------------
46/// A placeholder module used for minidumps, where the original
47/// object files may not be available (so we can't parse the object
48/// files to extract the set of sections/segments)
49///
50/// This placeholder module has a single synthetic section (.module_image)
51/// which represents the module memory range covering the whole module.
52//------------------------------------------------------------------
53class PlaceholderModule : public Module {
54public:
Leonard Mosescu9fecd372018-05-02 20:06:17 +000055 PlaceholderModule(const ModuleSpec &module_spec) :
56 Module(module_spec.GetFileSpec(), module_spec.GetArchitecture()) {
57 if (module_spec.GetUUID().IsValid())
58 SetUUID(module_spec.GetUUID());
59 }
Leonard Mosescu47196a22018-04-18 23:10:46 +000060
Adrian Prantl05097242018-04-30 16:49:04 +000061 // Creates a synthetic module section covering the whole module image (and
62 // sets the section load address as well)
Leonard Mosescu47196a22018-04-18 23:10:46 +000063 void CreateImageSection(const MinidumpModule *module, Target& target) {
64 const ConstString section_name(".module_image");
65 lldb::SectionSP section_sp(new Section(
66 shared_from_this(), // Module to which this section belongs.
67 nullptr, // ObjectFile
68 0, // Section ID.
69 section_name, // Section name.
70 eSectionTypeContainer, // Section type.
71 module->base_of_image, // VM address.
72 module->size_of_image, // VM size in bytes of this section.
73 0, // Offset of this section in the file.
74 module->size_of_image, // Size of the section as found in the file.
75 12, // Alignment of the section (log2)
76 0, // Flags for this section.
77 1)); // Number of host bytes per target byte
78 section_sp->SetPermissions(ePermissionsExecutable | ePermissionsReadable);
79 GetSectionList()->AddSection(section_sp);
80 target.GetSectionLoadList().SetSectionLoadAddress(
81 section_sp, module->base_of_image);
82 }
83
Leonard Mosescu0d057902019-01-07 17:55:42 +000084ObjectFile *GetObjectFile() override { return nullptr; }
Leonard Mosescu47196a22018-04-18 23:10:46 +000085
86 SectionList *GetSectionList() override {
87 return Module::GetUnifiedSectionList();
88 }
89};
90
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +000091ConstString ProcessMinidump::GetPluginNameStatic() {
92 static ConstString g_name("minidump");
93 return g_name;
94}
95
96const char *ProcessMinidump::GetPluginDescriptionStatic() {
97 return "Minidump plug-in.";
98}
99
100lldb::ProcessSP ProcessMinidump::CreateInstance(lldb::TargetSP target_sp,
101 lldb::ListenerSP listener_sp,
102 const FileSpec *crash_file) {
103 if (!crash_file)
104 return nullptr;
105
106 lldb::ProcessSP process_sp;
107 // Read enough data for the Minidump header
Zachary Turner3f4a4b32017-02-24 18:56:49 +0000108 constexpr size_t header_size = sizeof(MinidumpHeader);
Jonas Devlieghere87e403a2018-11-12 21:24:50 +0000109 auto DataPtr = FileSystem::Instance().CreateDataBuffer(crash_file->GetPath(),
110 header_size, 0);
Zachary Turner3f4a4b32017-02-24 18:56:49 +0000111 if (!DataPtr)
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000112 return nullptr;
113
Leonard Mosescu2ae3ec32018-07-12 17:27:18 +0000114 lldbassert(DataPtr->GetByteSize() == header_size);
Zachary Turner3f4a4b32017-02-24 18:56:49 +0000115
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000116 // first, only try to parse the header, beacuse we need to be fast
Zachary Turner3f4a4b32017-02-24 18:56:49 +0000117 llvm::ArrayRef<uint8_t> HeaderBytes = DataPtr->GetData();
118 const MinidumpHeader *header = MinidumpHeader::Parse(HeaderBytes);
119 if (header == nullptr)
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000120 return nullptr;
121
Jonas Devlieghere87e403a2018-11-12 21:24:50 +0000122 auto AllData =
123 FileSystem::Instance().CreateDataBuffer(crash_file->GetPath(), -1, 0);
Zachary Turner3f4a4b32017-02-24 18:56:49 +0000124 if (!AllData)
125 return nullptr;
126
127 auto minidump_parser = MinidumpParser::Create(AllData);
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000128 // check if the parser object is valid
Pavel Labath222fd132016-11-09 10:16:11 +0000129 if (!minidump_parser)
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000130 return nullptr;
131
132 return std::make_shared<ProcessMinidump>(target_sp, listener_sp, *crash_file,
133 minidump_parser.getValue());
134}
135
136bool ProcessMinidump::CanDebug(lldb::TargetSP target_sp,
137 bool plugin_specified_by_name) {
138 return true;
139}
140
141ProcessMinidump::ProcessMinidump(lldb::TargetSP target_sp,
142 lldb::ListenerSP listener_sp,
143 const FileSpec &core_file,
144 MinidumpParser minidump_parser)
145 : Process(target_sp, listener_sp), m_minidump_parser(minidump_parser),
146 m_core_file(core_file), m_is_wow64(false) {}
147
148ProcessMinidump::~ProcessMinidump() {
149 Clear();
Adrian Prantl05097242018-04-30 16:49:04 +0000150 // We need to call finalize on the process before destroying ourselves to
151 // make sure all of the broadcaster cleanup goes as planned. If we destruct
152 // this class, then Process::~Process() might have problems trying to fully
153 // destroy the broadcaster.
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000154 Finalize();
155}
156
157void ProcessMinidump::Initialize() {
Kamil Rytarowskic5f28e22017-02-06 17:55:02 +0000158 static llvm::once_flag g_once_flag;
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000159
Kamil Rytarowskic5f28e22017-02-06 17:55:02 +0000160 llvm::call_once(g_once_flag, []() {
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000161 PluginManager::RegisterPlugin(GetPluginNameStatic(),
162 GetPluginDescriptionStatic(),
163 ProcessMinidump::CreateInstance);
164 });
165}
166
167void ProcessMinidump::Terminate() {
168 PluginManager::UnregisterPlugin(ProcessMinidump::CreateInstance);
169}
170
Zachary Turner97206d52017-05-12 04:51:55 +0000171Status ProcessMinidump::DoLoadCore() {
172 Status error;
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000173
Leonard Mosescu2ae3ec32018-07-12 17:27:18 +0000174 // Minidump parser initialization & consistency checks
175 error = m_minidump_parser.Initialize();
176 if (error.Fail())
177 return error;
178
179 // Do we support the minidump's architecture?
180 ArchSpec arch = GetArchitecture();
181 switch (arch.GetMachine()) {
182 case llvm::Triple::x86:
183 case llvm::Triple::x86_64:
Greg Clayton19c8f392018-08-06 16:56:10 +0000184 case llvm::Triple::arm:
185 case llvm::Triple::aarch64:
186 // Any supported architectures must be listed here and also supported in
187 // ThreadMinidump::CreateRegisterContextForFrame().
Leonard Mosescu2ae3ec32018-07-12 17:27:18 +0000188 break;
Leonard Mosescu2ae3ec32018-07-12 17:27:18 +0000189 default:
190 error.SetErrorStringWithFormat("unsupported minidump architecture: %s",
191 arch.GetArchitectureName());
192 return error;
193 }
Greg Clayton19c8f392018-08-06 16:56:10 +0000194 GetTarget().SetArchitecture(arch, true /*set_platform*/);
Leonard Mosescu2ae3ec32018-07-12 17:27:18 +0000195
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000196 m_thread_list = m_minidump_parser.GetThreads();
197 m_active_exception = m_minidump_parser.GetExceptionStream();
198 ReadModuleList();
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000199
200 llvm::Optional<lldb::pid_t> pid = m_minidump_parser.GetPid();
201 if (!pid) {
202 error.SetErrorString("failed to parse PID");
203 return error;
204 }
205 SetID(pid.getValue());
206
207 return error;
208}
209
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000210ConstString ProcessMinidump::GetPluginName() { return GetPluginNameStatic(); }
211
212uint32_t ProcessMinidump::GetPluginVersion() { return 1; }
213
Zachary Turner97206d52017-05-12 04:51:55 +0000214Status ProcessMinidump::DoDestroy() { return Status(); }
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000215
216void ProcessMinidump::RefreshStateAfterStop() {
217 if (!m_active_exception)
218 return;
219
220 if (m_active_exception->exception_record.exception_code ==
221 MinidumpException::DumpRequested) {
222 return;
223 }
224
225 lldb::StopInfoSP stop_info;
226 lldb::ThreadSP stop_thread;
227
228 Process::m_thread_list.SetSelectedThreadByID(m_active_exception->thread_id);
229 stop_thread = Process::m_thread_list.GetSelectedThread();
230 ArchSpec arch = GetArchitecture();
231
232 if (arch.GetTriple().getOS() == llvm::Triple::Linux) {
233 stop_info = StopInfo::CreateStopReasonWithSignal(
234 *stop_thread, m_active_exception->exception_record.exception_code);
Greg Clayton19c8f392018-08-06 16:56:10 +0000235 } else if (arch.GetTriple().getVendor() == llvm::Triple::Apple) {
236 stop_info = StopInfoMachException::CreateStopReasonWithMachException(
237 *stop_thread, m_active_exception->exception_record.exception_code, 2,
238 m_active_exception->exception_record.exception_flags,
239 m_active_exception->exception_record.exception_address, 0);
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000240 } else {
241 std::string desc;
242 llvm::raw_string_ostream desc_stream(desc);
243 desc_stream << "Exception "
244 << llvm::format_hex(
245 m_active_exception->exception_record.exception_code, 8)
246 << " encountered at address "
247 << llvm::format_hex(
248 m_active_exception->exception_record.exception_address,
249 8);
250 stop_info = StopInfo::CreateStopReasonWithException(
251 *stop_thread, desc_stream.str().c_str());
252 }
253
254 stop_thread->SetStopInfo(stop_info);
255}
256
257bool ProcessMinidump::IsAlive() { return true; }
258
259bool ProcessMinidump::WarnBeforeDetach() const { return false; }
260
261size_t ProcessMinidump::ReadMemory(lldb::addr_t addr, void *buf, size_t size,
Zachary Turner97206d52017-05-12 04:51:55 +0000262 Status &error) {
Adrian Prantl05097242018-04-30 16:49:04 +0000263 // Don't allow the caching that lldb_private::Process::ReadMemory does since
264 // we have it all cached in our dump file anyway.
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000265 return DoReadMemory(addr, buf, size, error);
266}
267
268size_t ProcessMinidump::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
Zachary Turner97206d52017-05-12 04:51:55 +0000269 Status &error) {
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000270
271 llvm::ArrayRef<uint8_t> mem = m_minidump_parser.GetMemory(addr, size);
272 if (mem.empty()) {
273 error.SetErrorString("could not parse memory info");
274 return 0;
275 }
276
277 std::memcpy(buf, mem.data(), mem.size());
278 return mem.size();
279}
280
281ArchSpec ProcessMinidump::GetArchitecture() {
282 if (!m_is_wow64) {
283 return m_minidump_parser.GetArchitecture();
284 }
285
286 llvm::Triple triple;
287 triple.setVendor(llvm::Triple::VendorType::UnknownVendor);
288 triple.setArch(llvm::Triple::ArchType::x86);
289 triple.setOS(llvm::Triple::OSType::Win32);
290 return ArchSpec(triple);
291}
292
Zachary Turner97206d52017-05-12 04:51:55 +0000293Status ProcessMinidump::GetMemoryRegionInfo(lldb::addr_t load_addr,
294 MemoryRegionInfo &range_info) {
Greg Clayton026e1bf2018-12-14 19:36:01 +0000295 range_info = m_minidump_parser.GetMemoryRegionInfo(load_addr);
296 return Status();
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000297}
298
Tatyana Krasnukha92e5e362018-12-20 15:05:43 +0000299Status ProcessMinidump::GetMemoryRegions(
300 lldb_private::MemoryRegionInfos &region_list) {
301 region_list = m_minidump_parser.GetMemoryRegions();
302 return Status();
303}
304
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000305void ProcessMinidump::Clear() { Process::m_thread_list.Clear(); }
306
Dimitar Vlahovski5a19c0c2016-11-01 15:48:24 +0000307bool ProcessMinidump::UpdateThreadList(ThreadList &old_thread_list,
308 ThreadList &new_thread_list) {
Leonard Mosescu0d057902019-01-07 17:55:42 +0000309 for (const MinidumpThread& thread : m_thread_list) {
310 MinidumpLocationDescriptor context_location = thread.thread_context;
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000311
Leonard Mosescu0d057902019-01-07 17:55:42 +0000312 // If the minidump contains an exception context, use it
313 if (m_active_exception != nullptr &&
314 m_active_exception->thread_id == thread.thread_id) {
315 context_location = m_active_exception->thread_context;
316 }
317
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000318 llvm::ArrayRef<uint8_t> context;
319 if (!m_is_wow64)
Leonard Mosescu0d057902019-01-07 17:55:42 +0000320 context = m_minidump_parser.GetThreadContext(context_location);
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000321 else
Leonard Mosescu0d057902019-01-07 17:55:42 +0000322 context = m_minidump_parser.GetThreadContextWow64(thread);
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000323
Leonard Mosescu0d057902019-01-07 17:55:42 +0000324 lldb::ThreadSP thread_sp(new ThreadMinidump(*this, thread, context));
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000325 new_thread_list.AddThread(thread_sp);
326 }
327 return new_thread_list.GetSize(false) > 0;
328}
329
330void ProcessMinidump::ReadModuleList() {
331 std::vector<const MinidumpModule *> filtered_modules =
332 m_minidump_parser.GetFilteredModuleList();
333
334 for (auto module : filtered_modules) {
335 llvm::Optional<std::string> name =
336 m_minidump_parser.GetMinidumpString(module->module_name_rva);
337
338 if (!name)
339 continue;
340
341 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES));
342 if (log) {
Pavel Labatheaa419c2016-11-02 10:29:47 +0000343 log->Printf("ProcessMinidump::%s found module: name: %s %#010" PRIx64
344 "-%#010" PRIx64 " size: %" PRIu32,
345 __FUNCTION__, name.getValue().c_str(),
346 uint64_t(module->base_of_image),
347 module->base_of_image + module->size_of_image,
348 uint32_t(module->size_of_image));
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000349 }
350
351 // check if the process is wow64 - a 32 bit windows process running on a
352 // 64 bit windows
353 if (llvm::StringRef(name.getValue()).endswith_lower("wow64.dll")) {
354 m_is_wow64 = true;
355 }
356
Leonard Mosescu9fecd372018-05-02 20:06:17 +0000357 const auto uuid = m_minidump_parser.GetModuleUUID(module);
Jonas Devlieghere8f3be7a2018-11-01 21:05:36 +0000358 auto file_spec = FileSpec(name.getValue(), GetArchitecture().GetTriple());
359 FileSystem::Instance().Resolve(file_spec);
Leonard Mosescu9fecd372018-05-02 20:06:17 +0000360 ModuleSpec module_spec(file_spec, uuid);
Zachary Turner97206d52017-05-12 04:51:55 +0000361 Status error;
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000362 lldb::ModuleSP module_sp = GetTarget().GetSharedModule(module_spec, &error);
363 if (!module_sp || error.Fail()) {
Adrian Prantl05097242018-04-30 16:49:04 +0000364 // We failed to locate a matching local object file. Fortunately, the
365 // minidump format encodes enough information about each module's memory
366 // range to allow us to create placeholder modules.
Leonard Mosescu47196a22018-04-18 23:10:46 +0000367 //
368 // This enables most LLDB functionality involving address-to-module
369 // translations (ex. identifing the module for a stack frame PC) and
370 // modules/sections commands (ex. target modules list, ...)
Leonard Mosescu9ba51572018-08-07 18:00:30 +0000371 if (log) {
372 log->Printf("Unable to locate the matching object file, creating a "
373 "placeholder module for: %s",
374 name.getValue().c_str());
375 }
376
Leonard Mosescu47196a22018-04-18 23:10:46 +0000377 auto placeholder_module =
Leonard Mosescu9fecd372018-05-02 20:06:17 +0000378 std::make_shared<PlaceholderModule>(module_spec);
Leonard Mosescu47196a22018-04-18 23:10:46 +0000379 placeholder_module->CreateImageSection(module, GetTarget());
380 module_sp = placeholder_module;
381 GetTarget().GetImages().Append(module_sp);
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000382 }
383
384 if (log) {
385 log->Printf("ProcessMinidump::%s load module: name: %s", __FUNCTION__,
386 name.getValue().c_str());
387 }
388
389 bool load_addr_changed = false;
390 module_sp->SetLoadAddress(GetTarget(), module->base_of_image, false,
391 load_addr_changed);
392 }
393}
Dimitar Vlahovski5a19c0c2016-11-01 15:48:24 +0000394
395bool ProcessMinidump::GetProcessInfo(ProcessInstanceInfo &info) {
396 info.Clear();
397 info.SetProcessID(GetID());
398 info.SetArchitecture(GetArchitecture());
399 lldb::ModuleSP module_sp = GetTarget().GetExecutableModule();
400 if (module_sp) {
401 const bool add_exe_file_as_first_arg = false;
402 info.SetExecutableFile(GetTarget().GetExecutableModule()->GetFileSpec(),
403 add_exe_file_as_first_arg);
404 }
405 return true;
406}
Leonard Mosescu40b832e2018-08-23 21:34:33 +0000407
408// For minidumps there's no runtime generated code so we don't need JITLoader(s)
409// Avoiding them will also speed up minidump loading since JITLoaders normally
410// try to set up symbolic breakpoints, which in turn may force loading more
411// debug information than needed.
412JITLoaderList &ProcessMinidump::GetJITLoaders() {
413 if (!m_jit_loaders_ap) {
414 m_jit_loaders_ap = llvm::make_unique<JITLoaderList>();
415 }
416 return *m_jit_loaders_ap;
417}
Greg Clayton48a28c12018-12-18 00:50:11 +0000418
419#define INIT_BOOL(VAR, LONG, SHORT, DESC) \
420 VAR(LLDB_OPT_SET_1, false, LONG, SHORT, DESC, false, true)
421#define APPEND_OPT(VAR) \
422 m_option_group.Append(&VAR, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1)
423
424class CommandObjectProcessMinidumpDump : public CommandObjectParsed {
425private:
426 OptionGroupOptions m_option_group;
427 OptionGroupBoolean m_dump_all;
428 OptionGroupBoolean m_dump_directory;
429 OptionGroupBoolean m_dump_linux_cpuinfo;
430 OptionGroupBoolean m_dump_linux_proc_status;
431 OptionGroupBoolean m_dump_linux_lsb_release;
432 OptionGroupBoolean m_dump_linux_cmdline;
433 OptionGroupBoolean m_dump_linux_environ;
434 OptionGroupBoolean m_dump_linux_auxv;
435 OptionGroupBoolean m_dump_linux_maps;
436 OptionGroupBoolean m_dump_linux_proc_stat;
437 OptionGroupBoolean m_dump_linux_proc_uptime;
438 OptionGroupBoolean m_dump_linux_proc_fd;
439 OptionGroupBoolean m_dump_linux_all;
440
441 void SetDefaultOptionsIfNoneAreSet() {
442 if (m_dump_all.GetOptionValue().GetCurrentValue() ||
443 m_dump_linux_all.GetOptionValue().GetCurrentValue() ||
444 m_dump_directory.GetOptionValue().GetCurrentValue() ||
445 m_dump_linux_cpuinfo.GetOptionValue().GetCurrentValue() ||
446 m_dump_linux_proc_status.GetOptionValue().GetCurrentValue() ||
447 m_dump_linux_lsb_release.GetOptionValue().GetCurrentValue() ||
448 m_dump_linux_cmdline.GetOptionValue().GetCurrentValue() ||
449 m_dump_linux_environ.GetOptionValue().GetCurrentValue() ||
450 m_dump_linux_auxv.GetOptionValue().GetCurrentValue() ||
451 m_dump_linux_maps.GetOptionValue().GetCurrentValue() ||
452 m_dump_linux_proc_stat.GetOptionValue().GetCurrentValue() ||
453 m_dump_linux_proc_uptime.GetOptionValue().GetCurrentValue() ||
454 m_dump_linux_proc_fd.GetOptionValue().GetCurrentValue())
455 return;
456 // If no options were set, then dump everything
457 m_dump_all.GetOptionValue().SetCurrentValue(true);
458 }
459 bool DumpAll() const {
460 return m_dump_all.GetOptionValue().GetCurrentValue();
461 }
462 bool DumpDirectory() const {
463 return DumpAll() ||
464 m_dump_directory.GetOptionValue().GetCurrentValue();
465 }
466 bool DumpLinux() const {
467 return DumpAll() || m_dump_linux_all.GetOptionValue().GetCurrentValue();
468 }
469 bool DumpLinuxCPUInfo() const {
470 return DumpLinux() ||
471 m_dump_linux_cpuinfo.GetOptionValue().GetCurrentValue();
472 }
473 bool DumpLinuxProcStatus() const {
474 return DumpLinux() ||
475 m_dump_linux_proc_status.GetOptionValue().GetCurrentValue();
476 }
477 bool DumpLinuxProcStat() const {
478 return DumpLinux() ||
479 m_dump_linux_proc_stat.GetOptionValue().GetCurrentValue();
480 }
481 bool DumpLinuxLSBRelease() const {
482 return DumpLinux() ||
483 m_dump_linux_lsb_release.GetOptionValue().GetCurrentValue();
484 }
485 bool DumpLinuxCMDLine() const {
486 return DumpLinux() ||
487 m_dump_linux_cmdline.GetOptionValue().GetCurrentValue();
488 }
489 bool DumpLinuxEnviron() const {
490 return DumpLinux() ||
491 m_dump_linux_environ.GetOptionValue().GetCurrentValue();
492 }
493 bool DumpLinuxAuxv() const {
494 return DumpLinux() ||
495 m_dump_linux_auxv.GetOptionValue().GetCurrentValue();
496 }
497 bool DumpLinuxMaps() const {
498 return DumpLinux() ||
499 m_dump_linux_maps.GetOptionValue().GetCurrentValue();
500 }
501 bool DumpLinuxProcUptime() const {
502 return DumpLinux() ||
503 m_dump_linux_proc_uptime.GetOptionValue().GetCurrentValue();
504 }
505 bool DumpLinuxProcFD() const {
506 return DumpLinux() ||
507 m_dump_linux_proc_fd.GetOptionValue().GetCurrentValue();
508 }
509public:
510
511 CommandObjectProcessMinidumpDump(CommandInterpreter &interpreter)
512 : CommandObjectParsed(interpreter, "process plugin dump",
513 "Dump information from the minidump file.", NULL),
514 m_option_group(),
515 INIT_BOOL(m_dump_all, "all", 'a',
516 "Dump the everything in the minidump."),
517 INIT_BOOL(m_dump_directory, "directory", 'd',
518 "Dump the minidump directory map."),
519 INIT_BOOL(m_dump_linux_cpuinfo, "cpuinfo", 'C',
520 "Dump linux /proc/cpuinfo."),
521 INIT_BOOL(m_dump_linux_proc_status, "status", 's',
522 "Dump linux /proc/<pid>/status."),
523 INIT_BOOL(m_dump_linux_lsb_release, "lsb-release", 'r',
524 "Dump linux /etc/lsb-release."),
525 INIT_BOOL(m_dump_linux_cmdline, "cmdline", 'c',
526 "Dump linux /proc/<pid>/cmdline."),
527 INIT_BOOL(m_dump_linux_environ, "environ", 'e',
528 "Dump linux /proc/<pid>/environ."),
529 INIT_BOOL(m_dump_linux_auxv, "auxv", 'x',
530 "Dump linux /proc/<pid>/auxv."),
531 INIT_BOOL(m_dump_linux_maps, "maps", 'm',
532 "Dump linux /proc/<pid>/maps."),
533 INIT_BOOL(m_dump_linux_proc_stat, "stat", 'S',
534 "Dump linux /proc/<pid>/stat."),
535 INIT_BOOL(m_dump_linux_proc_uptime, "uptime", 'u',
536 "Dump linux process uptime."),
537 INIT_BOOL(m_dump_linux_proc_fd, "fd", 'f',
538 "Dump linux /proc/<pid>/fd."),
539 INIT_BOOL(m_dump_linux_all, "linux", 'l',
540 "Dump all linux streams.") {
541 APPEND_OPT(m_dump_all);
542 APPEND_OPT(m_dump_directory);
543 APPEND_OPT(m_dump_linux_cpuinfo);
544 APPEND_OPT(m_dump_linux_proc_status);
545 APPEND_OPT(m_dump_linux_lsb_release);
546 APPEND_OPT(m_dump_linux_cmdline);
547 APPEND_OPT(m_dump_linux_environ);
548 APPEND_OPT(m_dump_linux_auxv);
549 APPEND_OPT(m_dump_linux_maps);
550 APPEND_OPT(m_dump_linux_proc_stat);
551 APPEND_OPT(m_dump_linux_proc_uptime);
552 APPEND_OPT(m_dump_linux_proc_fd);
553 APPEND_OPT(m_dump_linux_all);
554 m_option_group.Finalize();
555 }
Leonard Mosescu0d057902019-01-07 17:55:42 +0000556
Greg Clayton48a28c12018-12-18 00:50:11 +0000557 ~CommandObjectProcessMinidumpDump() {}
Leonard Mosescu0d057902019-01-07 17:55:42 +0000558
Greg Clayton48a28c12018-12-18 00:50:11 +0000559 Options *GetOptions() override { return &m_option_group; }
560
561 bool DoExecute(Args &command, CommandReturnObject &result) override {
562 const size_t argc = command.GetArgumentCount();
563 if (argc > 0) {
564 result.AppendErrorWithFormat("'%s' take no arguments, only options",
565 m_cmd_name.c_str());
566 result.SetStatus(eReturnStatusFailed);
567 return false;
568 }
569 SetDefaultOptionsIfNoneAreSet();
Leonard Mosescu0d057902019-01-07 17:55:42 +0000570
Greg Clayton48a28c12018-12-18 00:50:11 +0000571 ProcessMinidump *process = static_cast<ProcessMinidump *>(
572 m_interpreter.GetExecutionContext().GetProcessPtr());
573 result.SetStatus(eReturnStatusSuccessFinishResult);
574 Stream &s = result.GetOutputStream();
575 MinidumpParser &minidump = process->m_minidump_parser;
576 if (DumpDirectory()) {
577 s.Printf("RVA SIZE TYPE MinidumpStreamType\n");
578 s.Printf("---------- ---------- ---------- --------------------------\n");
579 for (const auto &pair: minidump.GetDirectoryMap())
580 s.Printf("0x%8.8x 0x%8.8x 0x%8.8x %s\n", (uint32_t)pair.second.rva,
581 (uint32_t)pair.second.data_size, pair.first,
582 MinidumpParser::GetStreamTypeAsString(pair.first).data());
583 s.Printf("\n");
584 }
585 auto DumpTextStream = [&](MinidumpStreamType stream_type,
Pavel Labath796984d2018-12-27 09:44:32 +0000586 llvm::StringRef label) -> void {
Greg Clayton48a28c12018-12-18 00:50:11 +0000587 auto bytes = minidump.GetStream(stream_type);
588 if (!bytes.empty()) {
589 if (label.empty())
590 label = MinidumpParser::GetStreamTypeAsString((uint32_t)stream_type);
591 s.Printf("%s:\n%s\n\n", label.data(), bytes.data());
592 }
593 };
594 auto DumpBinaryStream = [&](MinidumpStreamType stream_type,
Pavel Labath796984d2018-12-27 09:44:32 +0000595 llvm::StringRef label) -> void {
Greg Clayton48a28c12018-12-18 00:50:11 +0000596 auto bytes = minidump.GetStream(stream_type);
597 if (!bytes.empty()) {
598 if (label.empty())
599 label = MinidumpParser::GetStreamTypeAsString((uint32_t)stream_type);
600 s.Printf("%s:\n", label.data());
601 DataExtractor data(bytes.data(), bytes.size(), eByteOrderLittle,
602 process->GetAddressByteSize());
603 DumpDataExtractor(data, &s, 0, lldb::eFormatBytesWithASCII, 1,
604 bytes.size(), 16, 0, 0, 0);
605 s.Printf("\n\n");
606 }
607 };
608
609 if (DumpLinuxCPUInfo())
610 DumpTextStream(MinidumpStreamType::LinuxCPUInfo, "/proc/cpuinfo");
611 if (DumpLinuxProcStatus())
612 DumpTextStream(MinidumpStreamType::LinuxProcStatus, "/proc/PID/status");
613 if (DumpLinuxLSBRelease())
614 DumpTextStream(MinidumpStreamType::LinuxLSBRelease, "/etc/lsb-release");
615 if (DumpLinuxCMDLine())
616 DumpTextStream(MinidumpStreamType::LinuxCMDLine, "/proc/PID/cmdline");
617 if (DumpLinuxEnviron())
618 DumpTextStream(MinidumpStreamType::LinuxEnviron, "/proc/PID/environ");
619 if (DumpLinuxAuxv())
620 DumpBinaryStream(MinidumpStreamType::LinuxAuxv, "/proc/PID/auxv");
621 if (DumpLinuxMaps())
622 DumpTextStream(MinidumpStreamType::LinuxMaps, "/proc/PID/maps");
623 if (DumpLinuxProcStat())
624 DumpTextStream(MinidumpStreamType::LinuxProcStat, "/proc/PID/stat");
625 if (DumpLinuxProcUptime())
626 DumpTextStream(MinidumpStreamType::LinuxProcUptime, "uptime");
627 if (DumpLinuxProcFD())
628 DumpTextStream(MinidumpStreamType::LinuxProcFD, "/proc/PID/fd");
629 return true;
630 }
631};
632
633class CommandObjectMultiwordProcessMinidump : public CommandObjectMultiword {
634public:
635 CommandObjectMultiwordProcessMinidump(CommandInterpreter &interpreter)
636 : CommandObjectMultiword(interpreter, "process plugin",
637 "Commands for operating on a ProcessMinidump process.",
638 "process plugin <subcommand> [<subcommand-options>]") {
639 LoadSubCommand("dump",
640 CommandObjectSP(new CommandObjectProcessMinidumpDump(interpreter)));
641 }
Leonard Mosescu0d057902019-01-07 17:55:42 +0000642
Greg Clayton48a28c12018-12-18 00:50:11 +0000643 ~CommandObjectMultiwordProcessMinidump() {}
644};
645
646CommandObject *ProcessMinidump::GetPluginCommandObject() {
647 if (!m_command_sp)
648 m_command_sp.reset(new CommandObjectMultiwordProcessMinidump(
649 GetTarget().GetDebugger().GetCommandInterpreter()));
650 return m_command_sp.get();
651}