1 //===-- 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
10 #include "ProcessMinidump.h"
11 #include "ThreadMinidump.h"
12
13 #include "lldb/Core/DumpDataExtractor.h"
14 #include "lldb/Core/Module.h"
15 #include "lldb/Core/ModuleSpec.h"
16 #include "lldb/Core/PluginManager.h"
17 #include "lldb/Core/Section.h"
18 #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"
24 #include "lldb/Target/JITLoaderList.h"
25 #include "lldb/Target/MemoryRegionInfo.h"
26 #include "lldb/Target/SectionLoadList.h"
27 #include "lldb/Target/Target.h"
28 #include "lldb/Target/UnixSignals.h"
29 #include "lldb/Utility/LLDBAssert.h"
30 #include "lldb/Utility/Log.h"
31 #include "lldb/Utility/State.h"
32
33 #include "llvm/Support/MemoryBuffer.h"
34 #include "llvm/Support/Threading.h"
35
36 #include "Plugins/Process/Utility/StopInfoMachException.h"
37
38 // C includes
39 // C++ includes
40
41 using namespace lldb;
42 using namespace lldb_private;
43 using namespace minidump;
44
45 //------------------------------------------------------------------
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 //------------------------------------------------------------------
53 class PlaceholderModule : public Module {
54 public:
PlaceholderModule(const ModuleSpec & module_spec)55 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 }
60
61 // Creates a synthetic module section covering the whole module image (and
62 // sets the section load address as well)
CreateImageSection(const MinidumpModule * module,Target & target)63 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
GetObjectFile()84 ObjectFile *GetObjectFile() override { return nullptr; }
85
GetSectionList()86 SectionList *GetSectionList() override {
87 return Module::GetUnifiedSectionList();
88 }
89 };
90
GetPluginNameStatic()91 ConstString ProcessMinidump::GetPluginNameStatic() {
92 static ConstString g_name("minidump");
93 return g_name;
94 }
95
GetPluginDescriptionStatic()96 const char *ProcessMinidump::GetPluginDescriptionStatic() {
97 return "Minidump plug-in.";
98 }
99
CreateInstance(lldb::TargetSP target_sp,lldb::ListenerSP listener_sp,const FileSpec * crash_file)100 lldb::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
108 constexpr size_t header_size = sizeof(MinidumpHeader);
109 auto DataPtr = FileSystem::Instance().CreateDataBuffer(crash_file->GetPath(),
110 header_size, 0);
111 if (!DataPtr)
112 return nullptr;
113
114 lldbassert(DataPtr->GetByteSize() == header_size);
115
116 // first, only try to parse the header, beacuse we need to be fast
117 llvm::ArrayRef<uint8_t> HeaderBytes = DataPtr->GetData();
118 const MinidumpHeader *header = MinidumpHeader::Parse(HeaderBytes);
119 if (header == nullptr)
120 return nullptr;
121
122 auto AllData =
123 FileSystem::Instance().CreateDataBuffer(crash_file->GetPath(), -1, 0);
124 if (!AllData)
125 return nullptr;
126
127 auto minidump_parser = MinidumpParser::Create(AllData);
128 // check if the parser object is valid
129 if (!minidump_parser)
130 return nullptr;
131
132 return std::make_shared<ProcessMinidump>(target_sp, listener_sp, *crash_file,
133 minidump_parser.getValue());
134 }
135
CanDebug(lldb::TargetSP target_sp,bool plugin_specified_by_name)136 bool ProcessMinidump::CanDebug(lldb::TargetSP target_sp,
137 bool plugin_specified_by_name) {
138 return true;
139 }
140
ProcessMinidump(lldb::TargetSP target_sp,lldb::ListenerSP listener_sp,const FileSpec & core_file,MinidumpParser minidump_parser)141 ProcessMinidump::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
~ProcessMinidump()148 ProcessMinidump::~ProcessMinidump() {
149 Clear();
150 // 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.
154 Finalize();
155 }
156
Initialize()157 void ProcessMinidump::Initialize() {
158 static llvm::once_flag g_once_flag;
159
160 llvm::call_once(g_once_flag, []() {
161 PluginManager::RegisterPlugin(GetPluginNameStatic(),
162 GetPluginDescriptionStatic(),
163 ProcessMinidump::CreateInstance);
164 });
165 }
166
Terminate()167 void ProcessMinidump::Terminate() {
168 PluginManager::UnregisterPlugin(ProcessMinidump::CreateInstance);
169 }
170
DoLoadCore()171 Status ProcessMinidump::DoLoadCore() {
172 Status error;
173
174 // 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:
184 case llvm::Triple::arm:
185 case llvm::Triple::aarch64:
186 // Any supported architectures must be listed here and also supported in
187 // ThreadMinidump::CreateRegisterContextForFrame().
188 break;
189 default:
190 error.SetErrorStringWithFormat("unsupported minidump architecture: %s",
191 arch.GetArchitectureName());
192 return error;
193 }
194 GetTarget().SetArchitecture(arch, true /*set_platform*/);
195
196 m_thread_list = m_minidump_parser.GetThreads();
197 m_active_exception = m_minidump_parser.GetExceptionStream();
198 ReadModuleList();
199
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
GetPluginName()210 ConstString ProcessMinidump::GetPluginName() { return GetPluginNameStatic(); }
211
GetPluginVersion()212 uint32_t ProcessMinidump::GetPluginVersion() { return 1; }
213
DoDestroy()214 Status ProcessMinidump::DoDestroy() { return Status(); }
215
RefreshStateAfterStop()216 void 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);
235 } 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);
240 } 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
IsAlive()257 bool ProcessMinidump::IsAlive() { return true; }
258
WarnBeforeDetach() const259 bool ProcessMinidump::WarnBeforeDetach() const { return false; }
260
ReadMemory(lldb::addr_t addr,void * buf,size_t size,Status & error)261 size_t ProcessMinidump::ReadMemory(lldb::addr_t addr, void *buf, size_t size,
262 Status &error) {
263 // Don't allow the caching that lldb_private::Process::ReadMemory does since
264 // we have it all cached in our dump file anyway.
265 return DoReadMemory(addr, buf, size, error);
266 }
267
DoReadMemory(lldb::addr_t addr,void * buf,size_t size,Status & error)268 size_t ProcessMinidump::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
269 Status &error) {
270
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
GetArchitecture()281 ArchSpec 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
GetMemoryRegionInfo(lldb::addr_t load_addr,MemoryRegionInfo & range_info)293 Status ProcessMinidump::GetMemoryRegionInfo(lldb::addr_t load_addr,
294 MemoryRegionInfo &range_info) {
295 range_info = m_minidump_parser.GetMemoryRegionInfo(load_addr);
296 return Status();
297 }
298
GetMemoryRegions(lldb_private::MemoryRegionInfos & region_list)299 Status ProcessMinidump::GetMemoryRegions(
300 lldb_private::MemoryRegionInfos ®ion_list) {
301 region_list = m_minidump_parser.GetMemoryRegions();
302 return Status();
303 }
304
Clear()305 void ProcessMinidump::Clear() { Process::m_thread_list.Clear(); }
306
UpdateThreadList(ThreadList & old_thread_list,ThreadList & new_thread_list)307 bool ProcessMinidump::UpdateThreadList(ThreadList &old_thread_list,
308 ThreadList &new_thread_list) {
309 for (const MinidumpThread& thread : m_thread_list) {
310 MinidumpLocationDescriptor context_location = thread.thread_context;
311
312 // 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
318 llvm::ArrayRef<uint8_t> context;
319 if (!m_is_wow64)
320 context = m_minidump_parser.GetThreadContext(context_location);
321 else
322 context = m_minidump_parser.GetThreadContextWow64(thread);
323
324 lldb::ThreadSP thread_sp(new ThreadMinidump(*this, thread, context));
325 new_thread_list.AddThread(thread_sp);
326 }
327 return new_thread_list.GetSize(false) > 0;
328 }
329
ReadModuleList()330 void 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) {
343 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));
349 }
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
357 const auto uuid = m_minidump_parser.GetModuleUUID(module);
358 auto file_spec = FileSpec(name.getValue(), GetArchitecture().GetTriple());
359 FileSystem::Instance().Resolve(file_spec);
360 ModuleSpec module_spec(file_spec, uuid);
361 Status error;
362 lldb::ModuleSP module_sp = GetTarget().GetSharedModule(module_spec, &error);
363 if (!module_sp || error.Fail()) {
364 // 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.
367 //
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, ...)
371 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
377 auto placeholder_module =
378 std::make_shared<PlaceholderModule>(module_spec);
379 placeholder_module->CreateImageSection(module, GetTarget());
380 module_sp = placeholder_module;
381 GetTarget().GetImages().Append(module_sp);
382 }
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 }
394
GetProcessInfo(ProcessInstanceInfo & info)395 bool 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 }
407
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.
GetJITLoaders()412 JITLoaderList &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 }
418
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
424 class CommandObjectProcessMinidumpDump : public CommandObjectParsed {
425 private:
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
SetDefaultOptionsIfNoneAreSet()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 }
DumpAll() const459 bool DumpAll() const {
460 return m_dump_all.GetOptionValue().GetCurrentValue();
461 }
DumpDirectory() const462 bool DumpDirectory() const {
463 return DumpAll() ||
464 m_dump_directory.GetOptionValue().GetCurrentValue();
465 }
DumpLinux() const466 bool DumpLinux() const {
467 return DumpAll() || m_dump_linux_all.GetOptionValue().GetCurrentValue();
468 }
DumpLinuxCPUInfo() const469 bool DumpLinuxCPUInfo() const {
470 return DumpLinux() ||
471 m_dump_linux_cpuinfo.GetOptionValue().GetCurrentValue();
472 }
DumpLinuxProcStatus() const473 bool DumpLinuxProcStatus() const {
474 return DumpLinux() ||
475 m_dump_linux_proc_status.GetOptionValue().GetCurrentValue();
476 }
DumpLinuxProcStat() const477 bool DumpLinuxProcStat() const {
478 return DumpLinux() ||
479 m_dump_linux_proc_stat.GetOptionValue().GetCurrentValue();
480 }
DumpLinuxLSBRelease() const481 bool DumpLinuxLSBRelease() const {
482 return DumpLinux() ||
483 m_dump_linux_lsb_release.GetOptionValue().GetCurrentValue();
484 }
DumpLinuxCMDLine() const485 bool DumpLinuxCMDLine() const {
486 return DumpLinux() ||
487 m_dump_linux_cmdline.GetOptionValue().GetCurrentValue();
488 }
DumpLinuxEnviron() const489 bool DumpLinuxEnviron() const {
490 return DumpLinux() ||
491 m_dump_linux_environ.GetOptionValue().GetCurrentValue();
492 }
DumpLinuxAuxv() const493 bool DumpLinuxAuxv() const {
494 return DumpLinux() ||
495 m_dump_linux_auxv.GetOptionValue().GetCurrentValue();
496 }
DumpLinuxMaps() const497 bool DumpLinuxMaps() const {
498 return DumpLinux() ||
499 m_dump_linux_maps.GetOptionValue().GetCurrentValue();
500 }
DumpLinuxProcUptime() const501 bool DumpLinuxProcUptime() const {
502 return DumpLinux() ||
503 m_dump_linux_proc_uptime.GetOptionValue().GetCurrentValue();
504 }
DumpLinuxProcFD() const505 bool DumpLinuxProcFD() const {
506 return DumpLinux() ||
507 m_dump_linux_proc_fd.GetOptionValue().GetCurrentValue();
508 }
509 public:
510
CommandObjectProcessMinidumpDump(CommandInterpreter & interpreter)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 }
556
~CommandObjectProcessMinidumpDump()557 ~CommandObjectProcessMinidumpDump() {}
558
GetOptions()559 Options *GetOptions() override { return &m_option_group; }
560
DoExecute(Args & command,CommandReturnObject & result)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();
570
571 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,
586 llvm::StringRef label) -> void {
587 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,
595 llvm::StringRef label) -> void {
596 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
633 class CommandObjectMultiwordProcessMinidump : public CommandObjectMultiword {
634 public:
CommandObjectMultiwordProcessMinidump(CommandInterpreter & interpreter)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 }
642
~CommandObjectMultiwordProcessMinidump()643 ~CommandObjectMultiwordProcessMinidump() {}
644 };
645
GetPluginCommandObject()646 CommandObject *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 }
652