blob: 7c030811843de967b36d84745d8064cb7a483a24 [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"
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +000037// C includes
38// C++ includes
39
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
Leonard Mosescu47196a22018-04-18 23:10:46 +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 {
53public:
Leonard Mosescu9fecd372018-05-02 20:06:17 +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());
58 }
Leonard Mosescu47196a22018-04-18 23:10:46 +000059
Adrian Prantl05097242018-04-30 16:49:04 +000060 // Creates a synthetic module section covering the whole module image (and
61 // sets the section load address as well)
Leonard Mosescu47196a22018-04-18 23:10:46 +000062 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);
79 target.GetSectionLoadList().SetSectionLoadAddress(
80 section_sp, module->base_of_image);
81 }
82
83 ObjectFile *GetObjectFile() override { return nullptr; }
84
85 SectionList *GetSectionList() override {
86 return Module::GetUnifiedSectionList();
87 }
88};
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) {
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000308 uint32_t num_threads = 0;
309 if (m_thread_list.size() > 0)
310 num_threads = m_thread_list.size();
311
312 for (lldb::tid_t tid = 0; tid < num_threads; ++tid) {
313 llvm::ArrayRef<uint8_t> context;
314 if (!m_is_wow64)
315 context = m_minidump_parser.GetThreadContext(m_thread_list[tid]);
316 else
317 context = m_minidump_parser.GetThreadContextWow64(m_thread_list[tid]);
318
319 lldb::ThreadSP thread_sp(
320 new ThreadMinidump(*this, m_thread_list[tid], context));
321 new_thread_list.AddThread(thread_sp);
322 }
323 return new_thread_list.GetSize(false) > 0;
324}
325
326void ProcessMinidump::ReadModuleList() {
327 std::vector<const MinidumpModule *> filtered_modules =
328 m_minidump_parser.GetFilteredModuleList();
329
330 for (auto module : filtered_modules) {
331 llvm::Optional<std::string> name =
332 m_minidump_parser.GetMinidumpString(module->module_name_rva);
333
334 if (!name)
335 continue;
336
337 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES));
338 if (log) {
Pavel Labatheaa419c2016-11-02 10:29:47 +0000339 log->Printf("ProcessMinidump::%s found module: name: %s %#010" PRIx64
340 "-%#010" PRIx64 " size: %" PRIu32,
341 __FUNCTION__, name.getValue().c_str(),
342 uint64_t(module->base_of_image),
343 module->base_of_image + module->size_of_image,
344 uint32_t(module->size_of_image));
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000345 }
346
347 // check if the process is wow64 - a 32 bit windows process running on a
348 // 64 bit windows
349 if (llvm::StringRef(name.getValue()).endswith_lower("wow64.dll")) {
350 m_is_wow64 = true;
351 }
352
Leonard Mosescu9fecd372018-05-02 20:06:17 +0000353 const auto uuid = m_minidump_parser.GetModuleUUID(module);
Jonas Devlieghere8f3be7a2018-11-01 21:05:36 +0000354 auto file_spec = FileSpec(name.getValue(), GetArchitecture().GetTriple());
355 FileSystem::Instance().Resolve(file_spec);
Leonard Mosescu9fecd372018-05-02 20:06:17 +0000356 ModuleSpec module_spec(file_spec, uuid);
Zachary Turner97206d52017-05-12 04:51:55 +0000357 Status error;
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000358 lldb::ModuleSP module_sp = GetTarget().GetSharedModule(module_spec, &error);
359 if (!module_sp || error.Fail()) {
Adrian Prantl05097242018-04-30 16:49:04 +0000360 // We failed to locate a matching local object file. Fortunately, the
361 // minidump format encodes enough information about each module's memory
362 // range to allow us to create placeholder modules.
Leonard Mosescu47196a22018-04-18 23:10:46 +0000363 //
364 // This enables most LLDB functionality involving address-to-module
365 // translations (ex. identifing the module for a stack frame PC) and
366 // modules/sections commands (ex. target modules list, ...)
Leonard Mosescu9ba51572018-08-07 18:00:30 +0000367 if (log) {
368 log->Printf("Unable to locate the matching object file, creating a "
369 "placeholder module for: %s",
370 name.getValue().c_str());
371 }
372
Leonard Mosescu47196a22018-04-18 23:10:46 +0000373 auto placeholder_module =
Leonard Mosescu9fecd372018-05-02 20:06:17 +0000374 std::make_shared<PlaceholderModule>(module_spec);
Leonard Mosescu47196a22018-04-18 23:10:46 +0000375 placeholder_module->CreateImageSection(module, GetTarget());
376 module_sp = placeholder_module;
377 GetTarget().GetImages().Append(module_sp);
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000378 }
379
380 if (log) {
381 log->Printf("ProcessMinidump::%s load module: name: %s", __FUNCTION__,
382 name.getValue().c_str());
383 }
384
385 bool load_addr_changed = false;
386 module_sp->SetLoadAddress(GetTarget(), module->base_of_image, false,
387 load_addr_changed);
388 }
389}
Dimitar Vlahovski5a19c0c2016-11-01 15:48:24 +0000390
391bool ProcessMinidump::GetProcessInfo(ProcessInstanceInfo &info) {
392 info.Clear();
393 info.SetProcessID(GetID());
394 info.SetArchitecture(GetArchitecture());
395 lldb::ModuleSP module_sp = GetTarget().GetExecutableModule();
396 if (module_sp) {
397 const bool add_exe_file_as_first_arg = false;
398 info.SetExecutableFile(GetTarget().GetExecutableModule()->GetFileSpec(),
399 add_exe_file_as_first_arg);
400 }
401 return true;
402}
Leonard Mosescu40b832e2018-08-23 21:34:33 +0000403
404// For minidumps there's no runtime generated code so we don't need JITLoader(s)
405// Avoiding them will also speed up minidump loading since JITLoaders normally
406// try to set up symbolic breakpoints, which in turn may force loading more
407// debug information than needed.
408JITLoaderList &ProcessMinidump::GetJITLoaders() {
409 if (!m_jit_loaders_ap) {
410 m_jit_loaders_ap = llvm::make_unique<JITLoaderList>();
411 }
412 return *m_jit_loaders_ap;
413}
Greg Clayton48a28c12018-12-18 00:50:11 +0000414
415#define INIT_BOOL(VAR, LONG, SHORT, DESC) \
416 VAR(LLDB_OPT_SET_1, false, LONG, SHORT, DESC, false, true)
417#define APPEND_OPT(VAR) \
418 m_option_group.Append(&VAR, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1)
419
420class CommandObjectProcessMinidumpDump : public CommandObjectParsed {
421private:
422 OptionGroupOptions m_option_group;
423 OptionGroupBoolean m_dump_all;
424 OptionGroupBoolean m_dump_directory;
425 OptionGroupBoolean m_dump_linux_cpuinfo;
426 OptionGroupBoolean m_dump_linux_proc_status;
427 OptionGroupBoolean m_dump_linux_lsb_release;
428 OptionGroupBoolean m_dump_linux_cmdline;
429 OptionGroupBoolean m_dump_linux_environ;
430 OptionGroupBoolean m_dump_linux_auxv;
431 OptionGroupBoolean m_dump_linux_maps;
432 OptionGroupBoolean m_dump_linux_proc_stat;
433 OptionGroupBoolean m_dump_linux_proc_uptime;
434 OptionGroupBoolean m_dump_linux_proc_fd;
435 OptionGroupBoolean m_dump_linux_all;
436
437 void SetDefaultOptionsIfNoneAreSet() {
438 if (m_dump_all.GetOptionValue().GetCurrentValue() ||
439 m_dump_linux_all.GetOptionValue().GetCurrentValue() ||
440 m_dump_directory.GetOptionValue().GetCurrentValue() ||
441 m_dump_linux_cpuinfo.GetOptionValue().GetCurrentValue() ||
442 m_dump_linux_proc_status.GetOptionValue().GetCurrentValue() ||
443 m_dump_linux_lsb_release.GetOptionValue().GetCurrentValue() ||
444 m_dump_linux_cmdline.GetOptionValue().GetCurrentValue() ||
445 m_dump_linux_environ.GetOptionValue().GetCurrentValue() ||
446 m_dump_linux_auxv.GetOptionValue().GetCurrentValue() ||
447 m_dump_linux_maps.GetOptionValue().GetCurrentValue() ||
448 m_dump_linux_proc_stat.GetOptionValue().GetCurrentValue() ||
449 m_dump_linux_proc_uptime.GetOptionValue().GetCurrentValue() ||
450 m_dump_linux_proc_fd.GetOptionValue().GetCurrentValue())
451 return;
452 // If no options were set, then dump everything
453 m_dump_all.GetOptionValue().SetCurrentValue(true);
454 }
455 bool DumpAll() const {
456 return m_dump_all.GetOptionValue().GetCurrentValue();
457 }
458 bool DumpDirectory() const {
459 return DumpAll() ||
460 m_dump_directory.GetOptionValue().GetCurrentValue();
461 }
462 bool DumpLinux() const {
463 return DumpAll() || m_dump_linux_all.GetOptionValue().GetCurrentValue();
464 }
465 bool DumpLinuxCPUInfo() const {
466 return DumpLinux() ||
467 m_dump_linux_cpuinfo.GetOptionValue().GetCurrentValue();
468 }
469 bool DumpLinuxProcStatus() const {
470 return DumpLinux() ||
471 m_dump_linux_proc_status.GetOptionValue().GetCurrentValue();
472 }
473 bool DumpLinuxProcStat() const {
474 return DumpLinux() ||
475 m_dump_linux_proc_stat.GetOptionValue().GetCurrentValue();
476 }
477 bool DumpLinuxLSBRelease() const {
478 return DumpLinux() ||
479 m_dump_linux_lsb_release.GetOptionValue().GetCurrentValue();
480 }
481 bool DumpLinuxCMDLine() const {
482 return DumpLinux() ||
483 m_dump_linux_cmdline.GetOptionValue().GetCurrentValue();
484 }
485 bool DumpLinuxEnviron() const {
486 return DumpLinux() ||
487 m_dump_linux_environ.GetOptionValue().GetCurrentValue();
488 }
489 bool DumpLinuxAuxv() const {
490 return DumpLinux() ||
491 m_dump_linux_auxv.GetOptionValue().GetCurrentValue();
492 }
493 bool DumpLinuxMaps() const {
494 return DumpLinux() ||
495 m_dump_linux_maps.GetOptionValue().GetCurrentValue();
496 }
497 bool DumpLinuxProcUptime() const {
498 return DumpLinux() ||
499 m_dump_linux_proc_uptime.GetOptionValue().GetCurrentValue();
500 }
501 bool DumpLinuxProcFD() const {
502 return DumpLinux() ||
503 m_dump_linux_proc_fd.GetOptionValue().GetCurrentValue();
504 }
505public:
506
507 CommandObjectProcessMinidumpDump(CommandInterpreter &interpreter)
508 : CommandObjectParsed(interpreter, "process plugin dump",
509 "Dump information from the minidump file.", NULL),
510 m_option_group(),
511 INIT_BOOL(m_dump_all, "all", 'a',
512 "Dump the everything in the minidump."),
513 INIT_BOOL(m_dump_directory, "directory", 'd',
514 "Dump the minidump directory map."),
515 INIT_BOOL(m_dump_linux_cpuinfo, "cpuinfo", 'C',
516 "Dump linux /proc/cpuinfo."),
517 INIT_BOOL(m_dump_linux_proc_status, "status", 's',
518 "Dump linux /proc/<pid>/status."),
519 INIT_BOOL(m_dump_linux_lsb_release, "lsb-release", 'r',
520 "Dump linux /etc/lsb-release."),
521 INIT_BOOL(m_dump_linux_cmdline, "cmdline", 'c',
522 "Dump linux /proc/<pid>/cmdline."),
523 INIT_BOOL(m_dump_linux_environ, "environ", 'e',
524 "Dump linux /proc/<pid>/environ."),
525 INIT_BOOL(m_dump_linux_auxv, "auxv", 'x',
526 "Dump linux /proc/<pid>/auxv."),
527 INIT_BOOL(m_dump_linux_maps, "maps", 'm',
528 "Dump linux /proc/<pid>/maps."),
529 INIT_BOOL(m_dump_linux_proc_stat, "stat", 'S',
530 "Dump linux /proc/<pid>/stat."),
531 INIT_BOOL(m_dump_linux_proc_uptime, "uptime", 'u',
532 "Dump linux process uptime."),
533 INIT_BOOL(m_dump_linux_proc_fd, "fd", 'f',
534 "Dump linux /proc/<pid>/fd."),
535 INIT_BOOL(m_dump_linux_all, "linux", 'l',
536 "Dump all linux streams.") {
537 APPEND_OPT(m_dump_all);
538 APPEND_OPT(m_dump_directory);
539 APPEND_OPT(m_dump_linux_cpuinfo);
540 APPEND_OPT(m_dump_linux_proc_status);
541 APPEND_OPT(m_dump_linux_lsb_release);
542 APPEND_OPT(m_dump_linux_cmdline);
543 APPEND_OPT(m_dump_linux_environ);
544 APPEND_OPT(m_dump_linux_auxv);
545 APPEND_OPT(m_dump_linux_maps);
546 APPEND_OPT(m_dump_linux_proc_stat);
547 APPEND_OPT(m_dump_linux_proc_uptime);
548 APPEND_OPT(m_dump_linux_proc_fd);
549 APPEND_OPT(m_dump_linux_all);
550 m_option_group.Finalize();
551 }
552
553 ~CommandObjectProcessMinidumpDump() {}
554
555 Options *GetOptions() override { return &m_option_group; }
556
557 bool DoExecute(Args &command, CommandReturnObject &result) override {
558 const size_t argc = command.GetArgumentCount();
559 if (argc > 0) {
560 result.AppendErrorWithFormat("'%s' take no arguments, only options",
561 m_cmd_name.c_str());
562 result.SetStatus(eReturnStatusFailed);
563 return false;
564 }
565 SetDefaultOptionsIfNoneAreSet();
566
567 ProcessMinidump *process = static_cast<ProcessMinidump *>(
568 m_interpreter.GetExecutionContext().GetProcessPtr());
569 result.SetStatus(eReturnStatusSuccessFinishResult);
570 Stream &s = result.GetOutputStream();
571 MinidumpParser &minidump = process->m_minidump_parser;
572 if (DumpDirectory()) {
573 s.Printf("RVA SIZE TYPE MinidumpStreamType\n");
574 s.Printf("---------- ---------- ---------- --------------------------\n");
575 for (const auto &pair: minidump.GetDirectoryMap())
576 s.Printf("0x%8.8x 0x%8.8x 0x%8.8x %s\n", (uint32_t)pair.second.rva,
577 (uint32_t)pair.second.data_size, pair.first,
578 MinidumpParser::GetStreamTypeAsString(pair.first).data());
579 s.Printf("\n");
580 }
581 auto DumpTextStream = [&](MinidumpStreamType stream_type,
Pavel Labath796984d2018-12-27 09:44:32 +0000582 llvm::StringRef label) -> void {
Greg Clayton48a28c12018-12-18 00:50:11 +0000583 auto bytes = minidump.GetStream(stream_type);
584 if (!bytes.empty()) {
585 if (label.empty())
586 label = MinidumpParser::GetStreamTypeAsString((uint32_t)stream_type);
587 s.Printf("%s:\n%s\n\n", label.data(), bytes.data());
588 }
589 };
590 auto DumpBinaryStream = [&](MinidumpStreamType stream_type,
Pavel Labath796984d2018-12-27 09:44:32 +0000591 llvm::StringRef label) -> void {
Greg Clayton48a28c12018-12-18 00:50:11 +0000592 auto bytes = minidump.GetStream(stream_type);
593 if (!bytes.empty()) {
594 if (label.empty())
595 label = MinidumpParser::GetStreamTypeAsString((uint32_t)stream_type);
596 s.Printf("%s:\n", label.data());
597 DataExtractor data(bytes.data(), bytes.size(), eByteOrderLittle,
598 process->GetAddressByteSize());
599 DumpDataExtractor(data, &s, 0, lldb::eFormatBytesWithASCII, 1,
600 bytes.size(), 16, 0, 0, 0);
601 s.Printf("\n\n");
602 }
603 };
604
605 if (DumpLinuxCPUInfo())
606 DumpTextStream(MinidumpStreamType::LinuxCPUInfo, "/proc/cpuinfo");
607 if (DumpLinuxProcStatus())
608 DumpTextStream(MinidumpStreamType::LinuxProcStatus, "/proc/PID/status");
609 if (DumpLinuxLSBRelease())
610 DumpTextStream(MinidumpStreamType::LinuxLSBRelease, "/etc/lsb-release");
611 if (DumpLinuxCMDLine())
612 DumpTextStream(MinidumpStreamType::LinuxCMDLine, "/proc/PID/cmdline");
613 if (DumpLinuxEnviron())
614 DumpTextStream(MinidumpStreamType::LinuxEnviron, "/proc/PID/environ");
615 if (DumpLinuxAuxv())
616 DumpBinaryStream(MinidumpStreamType::LinuxAuxv, "/proc/PID/auxv");
617 if (DumpLinuxMaps())
618 DumpTextStream(MinidumpStreamType::LinuxMaps, "/proc/PID/maps");
619 if (DumpLinuxProcStat())
620 DumpTextStream(MinidumpStreamType::LinuxProcStat, "/proc/PID/stat");
621 if (DumpLinuxProcUptime())
622 DumpTextStream(MinidumpStreamType::LinuxProcUptime, "uptime");
623 if (DumpLinuxProcFD())
624 DumpTextStream(MinidumpStreamType::LinuxProcFD, "/proc/PID/fd");
625 return true;
626 }
627};
628
629class CommandObjectMultiwordProcessMinidump : public CommandObjectMultiword {
630public:
631 CommandObjectMultiwordProcessMinidump(CommandInterpreter &interpreter)
632 : CommandObjectMultiword(interpreter, "process plugin",
633 "Commands for operating on a ProcessMinidump process.",
634 "process plugin <subcommand> [<subcommand-options>]") {
635 LoadSubCommand("dump",
636 CommandObjectSP(new CommandObjectProcessMinidumpDump(interpreter)));
637 }
638
639 ~CommandObjectMultiwordProcessMinidump() {}
640};
641
642CommandObject *ProcessMinidump::GetPluginCommandObject() {
643 if (!m_command_sp)
644 m_command_sp.reset(new CommandObjectMultiwordProcessMinidump(
645 GetTarget().GetDebugger().GetCommandInterpreter()));
646 return m_command_sp.get();
647}