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: 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) 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 84 ObjectFile *GetObjectFile() override { return nullptr; } 85 86 SectionList *GetSectionList() override { 87 return Module::GetUnifiedSectionList(); 88 } 89 }; 90 91 ConstString ProcessMinidump::GetPluginNameStatic() { 92 static ConstString g_name("minidump"); 93 return g_name; 94 } 95 96 const char *ProcessMinidump::GetPluginDescriptionStatic() { 97 return "Minidump plug-in."; 98 } 99 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 136 bool ProcessMinidump::CanDebug(lldb::TargetSP target_sp, 137 bool plugin_specified_by_name) { 138 return true; 139 } 140 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 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 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 167 void ProcessMinidump::Terminate() { 168 PluginManager::UnregisterPlugin(ProcessMinidump::CreateInstance); 169 } 170 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 210 ConstString ProcessMinidump::GetPluginName() { return GetPluginNameStatic(); } 211 212 uint32_t ProcessMinidump::GetPluginVersion() { return 1; } 213 214 Status ProcessMinidump::DoDestroy() { return Status(); } 215 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 257 bool ProcessMinidump::IsAlive() { return true; } 258 259 bool ProcessMinidump::WarnBeforeDetach() const { return false; } 260 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 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 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 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 299 Status ProcessMinidump::GetMemoryRegions( 300 lldb_private::MemoryRegionInfos ®ion_list) { 301 region_list = m_minidump_parser.GetMemoryRegions(); 302 return Status(); 303 } 304 305 void ProcessMinidump::Clear() { Process::m_thread_list.Clear(); } 306 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 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 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. 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 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 } 509 public: 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 } 556 557 ~CommandObjectProcessMinidumpDump() {} 558 559 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(); 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: 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 643 ~CommandObjectMultiwordProcessMinidump() {} 644 }; 645 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