1 //===-- ProcessMinidump.cpp -------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "ProcessMinidump.h" 10 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 #include "llvm/BinaryFormat/Magic.h" 33 #include "llvm/Support/MemoryBuffer.h" 34 #include "llvm/Support/Threading.h" 35 36 #include "Plugins/Process/Utility/StopInfoMachException.h" 37 38 #include <memory> 39 40 using namespace lldb; 41 using namespace lldb_private; 42 using namespace minidump; 43 44 namespace { 45 46 /// A minimal ObjectFile implementation providing a dummy object file for the 47 /// cases when the real module binary is not available. This allows the module 48 /// to show up in "image list" and symbols to be added to it. 49 class PlaceholderObjectFile : public ObjectFile { 50 public: 51 PlaceholderObjectFile(const lldb::ModuleSP &module_sp, 52 const ModuleSpec &module_spec, lldb::offset_t base, 53 lldb::offset_t size) 54 : ObjectFile(module_sp, &module_spec.GetFileSpec(), /*file_offset*/ 0, 55 /*length*/ 0, /*data_sp*/ nullptr, /*data_offset*/ 0), 56 m_arch(module_spec.GetArchitecture()), m_uuid(module_spec.GetUUID()), 57 m_base(base), m_size(size) { 58 m_symtab_up = llvm::make_unique<Symtab>(this); 59 } 60 61 ConstString GetPluginName() override { return ConstString("placeholder"); } 62 uint32_t GetPluginVersion() override { return 1; } 63 bool ParseHeader() override { return true; } 64 Type CalculateType() override { return eTypeUnknown; } 65 Strata CalculateStrata() override { return eStrataUnknown; } 66 uint32_t GetDependentModules(FileSpecList &file_list) override { return 0; } 67 bool IsExecutable() const override { return false; } 68 ArchSpec GetArchitecture() override { return m_arch; } 69 UUID GetUUID() override { return m_uuid; } 70 Symtab *GetSymtab() override { return m_symtab_up.get(); } 71 bool IsStripped() override { return true; } 72 ByteOrder GetByteOrder() const override { return m_arch.GetByteOrder(); } 73 74 uint32_t GetAddressByteSize() const override { 75 return m_arch.GetAddressByteSize(); 76 } 77 78 Address GetBaseAddress() override { 79 return Address(m_sections_up->GetSectionAtIndex(0), 0); 80 } 81 82 void CreateSections(SectionList &unified_section_list) override { 83 m_sections_up = llvm::make_unique<SectionList>(); 84 auto section_sp = std::make_shared<Section>( 85 GetModule(), this, /*sect_id*/ 0, ConstString(".module_image"), 86 eSectionTypeOther, m_base, m_size, /*file_offset*/ 0, /*file_size*/ 0, 87 /*log2align*/ 0, /*flags*/ 0); 88 section_sp->SetPermissions(ePermissionsReadable | ePermissionsExecutable); 89 m_sections_up->AddSection(section_sp); 90 unified_section_list.AddSection(std::move(section_sp)); 91 } 92 93 bool SetLoadAddress(Target &target, addr_t value, 94 bool value_is_offset) override { 95 assert(!value_is_offset); 96 assert(value == m_base); 97 98 // Create sections if they haven't been created already. 99 GetModule()->GetSectionList(); 100 assert(m_sections_up->GetNumSections(0) == 1); 101 102 target.GetSectionLoadList().SetSectionLoadAddress( 103 m_sections_up->GetSectionAtIndex(0), m_base); 104 return true; 105 } 106 107 void Dump(Stream *s) override { 108 s->Format("Placeholder object file for {0} loaded at [{1:x}-{2:x})\n", 109 GetFileSpec(), m_base, m_base + m_size); 110 } 111 112 private: 113 ArchSpec m_arch; 114 UUID m_uuid; 115 lldb::offset_t m_base; 116 lldb::offset_t m_size; 117 }; 118 } // namespace 119 120 ConstString ProcessMinidump::GetPluginNameStatic() { 121 static ConstString g_name("minidump"); 122 return g_name; 123 } 124 125 const char *ProcessMinidump::GetPluginDescriptionStatic() { 126 return "Minidump plug-in."; 127 } 128 129 lldb::ProcessSP ProcessMinidump::CreateInstance(lldb::TargetSP target_sp, 130 lldb::ListenerSP listener_sp, 131 const FileSpec *crash_file) { 132 if (!crash_file) 133 return nullptr; 134 135 lldb::ProcessSP process_sp; 136 // Read enough data for the Minidump header 137 constexpr size_t header_size = sizeof(Header); 138 auto DataPtr = FileSystem::Instance().CreateDataBuffer(crash_file->GetPath(), 139 header_size, 0); 140 if (!DataPtr) 141 return nullptr; 142 143 lldbassert(DataPtr->GetByteSize() == header_size); 144 if (identify_magic(toStringRef(DataPtr->GetData())) != llvm::file_magic::minidump) 145 return nullptr; 146 147 auto AllData = 148 FileSystem::Instance().CreateDataBuffer(crash_file->GetPath(), -1, 0); 149 if (!AllData) 150 return nullptr; 151 152 return std::make_shared<ProcessMinidump>(target_sp, listener_sp, *crash_file, 153 std::move(AllData)); 154 } 155 156 bool ProcessMinidump::CanDebug(lldb::TargetSP target_sp, 157 bool plugin_specified_by_name) { 158 return true; 159 } 160 161 ProcessMinidump::ProcessMinidump(lldb::TargetSP target_sp, 162 lldb::ListenerSP listener_sp, 163 const FileSpec &core_file, 164 DataBufferSP core_data) 165 : Process(target_sp, listener_sp), m_core_file(core_file), 166 m_core_data(std::move(core_data)), m_is_wow64(false) {} 167 168 ProcessMinidump::~ProcessMinidump() { 169 Clear(); 170 // We need to call finalize on the process before destroying ourselves to 171 // make sure all of the broadcaster cleanup goes as planned. If we destruct 172 // this class, then Process::~Process() might have problems trying to fully 173 // destroy the broadcaster. 174 Finalize(); 175 } 176 177 void ProcessMinidump::Initialize() { 178 static llvm::once_flag g_once_flag; 179 180 llvm::call_once(g_once_flag, []() { 181 PluginManager::RegisterPlugin(GetPluginNameStatic(), 182 GetPluginDescriptionStatic(), 183 ProcessMinidump::CreateInstance); 184 }); 185 } 186 187 void ProcessMinidump::Terminate() { 188 PluginManager::UnregisterPlugin(ProcessMinidump::CreateInstance); 189 } 190 191 Status ProcessMinidump::DoLoadCore() { 192 auto expected_parser = MinidumpParser::Create(m_core_data); 193 if (!expected_parser) 194 return Status(expected_parser.takeError()); 195 m_minidump_parser = std::move(*expected_parser); 196 197 Status error; 198 199 // Do we support the minidump's architecture? 200 ArchSpec arch = GetArchitecture(); 201 switch (arch.GetMachine()) { 202 case llvm::Triple::x86: 203 case llvm::Triple::x86_64: 204 case llvm::Triple::arm: 205 case llvm::Triple::aarch64: 206 // Any supported architectures must be listed here and also supported in 207 // ThreadMinidump::CreateRegisterContextForFrame(). 208 break; 209 default: 210 error.SetErrorStringWithFormat("unsupported minidump architecture: %s", 211 arch.GetArchitectureName()); 212 return error; 213 } 214 GetTarget().SetArchitecture(arch, true /*set_platform*/); 215 216 m_thread_list = m_minidump_parser->GetThreads(); 217 m_active_exception = m_minidump_parser->GetExceptionStream(); 218 ReadModuleList(); 219 220 llvm::Optional<lldb::pid_t> pid = m_minidump_parser->GetPid(); 221 if (!pid) { 222 error.SetErrorString("failed to parse PID"); 223 return error; 224 } 225 SetID(pid.getValue()); 226 227 return error; 228 } 229 230 ConstString ProcessMinidump::GetPluginName() { return GetPluginNameStatic(); } 231 232 uint32_t ProcessMinidump::GetPluginVersion() { return 1; } 233 234 Status ProcessMinidump::DoDestroy() { return Status(); } 235 236 void ProcessMinidump::RefreshStateAfterStop() { 237 if (!m_active_exception) 238 return; 239 240 if (m_active_exception->exception_record.exception_code == 241 MinidumpException::DumpRequested) { 242 return; 243 } 244 245 lldb::StopInfoSP stop_info; 246 lldb::ThreadSP stop_thread; 247 248 Process::m_thread_list.SetSelectedThreadByID(m_active_exception->thread_id); 249 stop_thread = Process::m_thread_list.GetSelectedThread(); 250 ArchSpec arch = GetArchitecture(); 251 252 if (arch.GetTriple().getOS() == llvm::Triple::Linux) { 253 stop_info = StopInfo::CreateStopReasonWithSignal( 254 *stop_thread, m_active_exception->exception_record.exception_code); 255 } else if (arch.GetTriple().getVendor() == llvm::Triple::Apple) { 256 stop_info = StopInfoMachException::CreateStopReasonWithMachException( 257 *stop_thread, m_active_exception->exception_record.exception_code, 2, 258 m_active_exception->exception_record.exception_flags, 259 m_active_exception->exception_record.exception_address, 0); 260 } else { 261 std::string desc; 262 llvm::raw_string_ostream desc_stream(desc); 263 desc_stream << "Exception " 264 << llvm::format_hex( 265 m_active_exception->exception_record.exception_code, 8) 266 << " encountered at address " 267 << llvm::format_hex( 268 m_active_exception->exception_record.exception_address, 269 8); 270 stop_info = StopInfo::CreateStopReasonWithException( 271 *stop_thread, desc_stream.str().c_str()); 272 } 273 274 stop_thread->SetStopInfo(stop_info); 275 } 276 277 bool ProcessMinidump::IsAlive() { return true; } 278 279 bool ProcessMinidump::WarnBeforeDetach() const { return false; } 280 281 size_t ProcessMinidump::ReadMemory(lldb::addr_t addr, void *buf, size_t size, 282 Status &error) { 283 // Don't allow the caching that lldb_private::Process::ReadMemory does since 284 // we have it all cached in our dump file anyway. 285 return DoReadMemory(addr, buf, size, error); 286 } 287 288 size_t ProcessMinidump::DoReadMemory(lldb::addr_t addr, void *buf, size_t size, 289 Status &error) { 290 291 llvm::ArrayRef<uint8_t> mem = m_minidump_parser->GetMemory(addr, size); 292 if (mem.empty()) { 293 error.SetErrorString("could not parse memory info"); 294 return 0; 295 } 296 297 std::memcpy(buf, mem.data(), mem.size()); 298 return mem.size(); 299 } 300 301 ArchSpec ProcessMinidump::GetArchitecture() { 302 if (!m_is_wow64) { 303 return m_minidump_parser->GetArchitecture(); 304 } 305 306 llvm::Triple triple; 307 triple.setVendor(llvm::Triple::VendorType::UnknownVendor); 308 triple.setArch(llvm::Triple::ArchType::x86); 309 triple.setOS(llvm::Triple::OSType::Win32); 310 return ArchSpec(triple); 311 } 312 313 Status ProcessMinidump::GetMemoryRegionInfo(lldb::addr_t load_addr, 314 MemoryRegionInfo &range_info) { 315 range_info = m_minidump_parser->GetMemoryRegionInfo(load_addr); 316 return Status(); 317 } 318 319 Status ProcessMinidump::GetMemoryRegions( 320 lldb_private::MemoryRegionInfos ®ion_list) { 321 region_list = m_minidump_parser->GetMemoryRegions(); 322 return Status(); 323 } 324 325 void ProcessMinidump::Clear() { Process::m_thread_list.Clear(); } 326 327 bool ProcessMinidump::UpdateThreadList(ThreadList &old_thread_list, 328 ThreadList &new_thread_list) { 329 for (const MinidumpThread& thread : m_thread_list) { 330 LocationDescriptor context_location = thread.thread_context; 331 332 // If the minidump contains an exception context, use it 333 if (m_active_exception != nullptr && 334 m_active_exception->thread_id == thread.thread_id) { 335 context_location = m_active_exception->thread_context; 336 } 337 338 llvm::ArrayRef<uint8_t> context; 339 if (!m_is_wow64) 340 context = m_minidump_parser->GetThreadContext(context_location); 341 else 342 context = m_minidump_parser->GetThreadContextWow64(thread); 343 344 lldb::ThreadSP thread_sp(new ThreadMinidump(*this, thread, context)); 345 new_thread_list.AddThread(thread_sp); 346 } 347 return new_thread_list.GetSize(false) > 0; 348 } 349 350 void ProcessMinidump::ReadModuleList() { 351 std::vector<const minidump::Module *> filtered_modules = 352 m_minidump_parser->GetFilteredModuleList(); 353 354 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES)); 355 356 for (auto module : filtered_modules) { 357 std::string name = cantFail(m_minidump_parser->GetMinidumpFile().getString( 358 module->ModuleNameRVA)); 359 LLDB_LOG(log, "found module: name: {0} {1:x10}-{2:x10} size: {3}", name, 360 module->BaseOfImage, module->BaseOfImage + module->SizeOfImage, 361 module->SizeOfImage); 362 363 // check if the process is wow64 - a 32 bit windows process running on a 364 // 64 bit windows 365 if (llvm::StringRef(name).endswith_lower("wow64.dll")) { 366 m_is_wow64 = true; 367 } 368 369 const auto uuid = m_minidump_parser->GetModuleUUID(module); 370 auto file_spec = FileSpec(name, GetArchitecture().GetTriple()); 371 FileSystem::Instance().Resolve(file_spec); 372 ModuleSpec module_spec(file_spec, uuid); 373 module_spec.GetArchitecture() = GetArchitecture(); 374 Status error; 375 // Try and find a module with a full UUID that matches. This function will 376 // add the module to the target if it finds one. 377 lldb::ModuleSP module_sp = GetTarget().GetOrCreateModule(module_spec, 378 true /* notify */, &error); 379 if (!module_sp) { 380 // Try and find a module without specifying the UUID and only looking for 381 // the file given a basename. We then will look for a partial UUID match 382 // if we find any matches. This function will add the module to the 383 // target if it finds one, so we need to remove the module from the target 384 // if the UUID doesn't match during our manual UUID verification. This 385 // allows the "target.exec-search-paths" setting to specify one or more 386 // directories that contain executables that can be searched for matches. 387 ModuleSpec basename_module_spec(module_spec); 388 basename_module_spec.GetUUID().Clear(); 389 basename_module_spec.GetFileSpec().GetDirectory().Clear(); 390 module_sp = GetTarget().GetOrCreateModule(basename_module_spec, 391 true /* notify */, &error); 392 if (module_sp) { 393 // We consider the module to be a match if the minidump UUID is a 394 // prefix of the actual UUID, or if either of the UUIDs are empty. 395 const auto dmp_bytes = uuid.GetBytes(); 396 const auto mod_bytes = module_sp->GetUUID().GetBytes(); 397 const bool match = dmp_bytes.empty() || mod_bytes.empty() || 398 mod_bytes.take_front(dmp_bytes.size()) == dmp_bytes; 399 if (!match) { 400 GetTarget().GetImages().Remove(module_sp); 401 module_sp.reset(); 402 } 403 } 404 } 405 if (!module_sp) { 406 // We failed to locate a matching local object file. Fortunately, the 407 // minidump format encodes enough information about each module's memory 408 // range to allow us to create placeholder modules. 409 // 410 // This enables most LLDB functionality involving address-to-module 411 // translations (ex. identifing the module for a stack frame PC) and 412 // modules/sections commands (ex. target modules list, ...) 413 LLDB_LOG(log, 414 "Unable to locate the matching object file, creating a " 415 "placeholder module for: {0}", 416 name); 417 418 module_sp = Module::CreateModuleFromObjectFile<PlaceholderObjectFile>( 419 module_spec, module->BaseOfImage, module->SizeOfImage); 420 GetTarget().GetImages().Append(module_sp, true /* notify */); 421 } 422 423 bool load_addr_changed = false; 424 module_sp->SetLoadAddress(GetTarget(), module->BaseOfImage, false, 425 load_addr_changed); 426 } 427 } 428 429 bool ProcessMinidump::GetProcessInfo(ProcessInstanceInfo &info) { 430 info.Clear(); 431 info.SetProcessID(GetID()); 432 info.SetArchitecture(GetArchitecture()); 433 lldb::ModuleSP module_sp = GetTarget().GetExecutableModule(); 434 if (module_sp) { 435 const bool add_exe_file_as_first_arg = false; 436 info.SetExecutableFile(GetTarget().GetExecutableModule()->GetFileSpec(), 437 add_exe_file_as_first_arg); 438 } 439 return true; 440 } 441 442 // For minidumps there's no runtime generated code so we don't need JITLoader(s) 443 // Avoiding them will also speed up minidump loading since JITLoaders normally 444 // try to set up symbolic breakpoints, which in turn may force loading more 445 // debug information than needed. 446 JITLoaderList &ProcessMinidump::GetJITLoaders() { 447 if (!m_jit_loaders_up) { 448 m_jit_loaders_up = llvm::make_unique<JITLoaderList>(); 449 } 450 return *m_jit_loaders_up; 451 } 452 453 #define INIT_BOOL(VAR, LONG, SHORT, DESC) \ 454 VAR(LLDB_OPT_SET_1, false, LONG, SHORT, DESC, false, true) 455 #define APPEND_OPT(VAR) \ 456 m_option_group.Append(&VAR, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1) 457 458 class CommandObjectProcessMinidumpDump : public CommandObjectParsed { 459 private: 460 OptionGroupOptions m_option_group; 461 OptionGroupBoolean m_dump_all; 462 OptionGroupBoolean m_dump_directory; 463 OptionGroupBoolean m_dump_linux_cpuinfo; 464 OptionGroupBoolean m_dump_linux_proc_status; 465 OptionGroupBoolean m_dump_linux_lsb_release; 466 OptionGroupBoolean m_dump_linux_cmdline; 467 OptionGroupBoolean m_dump_linux_environ; 468 OptionGroupBoolean m_dump_linux_auxv; 469 OptionGroupBoolean m_dump_linux_maps; 470 OptionGroupBoolean m_dump_linux_proc_stat; 471 OptionGroupBoolean m_dump_linux_proc_uptime; 472 OptionGroupBoolean m_dump_linux_proc_fd; 473 OptionGroupBoolean m_dump_linux_all; 474 OptionGroupBoolean m_fb_app_data; 475 OptionGroupBoolean m_fb_build_id; 476 OptionGroupBoolean m_fb_version; 477 OptionGroupBoolean m_fb_java_stack; 478 OptionGroupBoolean m_fb_dalvik; 479 OptionGroupBoolean m_fb_unwind; 480 OptionGroupBoolean m_fb_error_log; 481 OptionGroupBoolean m_fb_app_state; 482 OptionGroupBoolean m_fb_abort; 483 OptionGroupBoolean m_fb_thread; 484 OptionGroupBoolean m_fb_logcat; 485 OptionGroupBoolean m_fb_all; 486 487 void SetDefaultOptionsIfNoneAreSet() { 488 if (m_dump_all.GetOptionValue().GetCurrentValue() || 489 m_dump_linux_all.GetOptionValue().GetCurrentValue() || 490 m_fb_all.GetOptionValue().GetCurrentValue() || 491 m_dump_directory.GetOptionValue().GetCurrentValue() || 492 m_dump_linux_cpuinfo.GetOptionValue().GetCurrentValue() || 493 m_dump_linux_proc_status.GetOptionValue().GetCurrentValue() || 494 m_dump_linux_lsb_release.GetOptionValue().GetCurrentValue() || 495 m_dump_linux_cmdline.GetOptionValue().GetCurrentValue() || 496 m_dump_linux_environ.GetOptionValue().GetCurrentValue() || 497 m_dump_linux_auxv.GetOptionValue().GetCurrentValue() || 498 m_dump_linux_maps.GetOptionValue().GetCurrentValue() || 499 m_dump_linux_proc_stat.GetOptionValue().GetCurrentValue() || 500 m_dump_linux_proc_uptime.GetOptionValue().GetCurrentValue() || 501 m_dump_linux_proc_fd.GetOptionValue().GetCurrentValue() || 502 m_fb_app_data.GetOptionValue().GetCurrentValue() || 503 m_fb_build_id.GetOptionValue().GetCurrentValue() || 504 m_fb_version.GetOptionValue().GetCurrentValue() || 505 m_fb_java_stack.GetOptionValue().GetCurrentValue() || 506 m_fb_dalvik.GetOptionValue().GetCurrentValue() || 507 m_fb_unwind.GetOptionValue().GetCurrentValue() || 508 m_fb_error_log.GetOptionValue().GetCurrentValue() || 509 m_fb_app_state.GetOptionValue().GetCurrentValue() || 510 m_fb_abort.GetOptionValue().GetCurrentValue() || 511 m_fb_thread.GetOptionValue().GetCurrentValue() || 512 m_fb_logcat.GetOptionValue().GetCurrentValue()) 513 return; 514 // If no options were set, then dump everything 515 m_dump_all.GetOptionValue().SetCurrentValue(true); 516 } 517 bool DumpAll() const { 518 return m_dump_all.GetOptionValue().GetCurrentValue(); 519 } 520 bool DumpDirectory() const { 521 return DumpAll() || 522 m_dump_directory.GetOptionValue().GetCurrentValue(); 523 } 524 bool DumpLinux() const { 525 return DumpAll() || m_dump_linux_all.GetOptionValue().GetCurrentValue(); 526 } 527 bool DumpLinuxCPUInfo() const { 528 return DumpLinux() || 529 m_dump_linux_cpuinfo.GetOptionValue().GetCurrentValue(); 530 } 531 bool DumpLinuxProcStatus() const { 532 return DumpLinux() || 533 m_dump_linux_proc_status.GetOptionValue().GetCurrentValue(); 534 } 535 bool DumpLinuxProcStat() const { 536 return DumpLinux() || 537 m_dump_linux_proc_stat.GetOptionValue().GetCurrentValue(); 538 } 539 bool DumpLinuxLSBRelease() const { 540 return DumpLinux() || 541 m_dump_linux_lsb_release.GetOptionValue().GetCurrentValue(); 542 } 543 bool DumpLinuxCMDLine() const { 544 return DumpLinux() || 545 m_dump_linux_cmdline.GetOptionValue().GetCurrentValue(); 546 } 547 bool DumpLinuxEnviron() const { 548 return DumpLinux() || 549 m_dump_linux_environ.GetOptionValue().GetCurrentValue(); 550 } 551 bool DumpLinuxAuxv() const { 552 return DumpLinux() || 553 m_dump_linux_auxv.GetOptionValue().GetCurrentValue(); 554 } 555 bool DumpLinuxMaps() const { 556 return DumpLinux() || 557 m_dump_linux_maps.GetOptionValue().GetCurrentValue(); 558 } 559 bool DumpLinuxProcUptime() const { 560 return DumpLinux() || 561 m_dump_linux_proc_uptime.GetOptionValue().GetCurrentValue(); 562 } 563 bool DumpLinuxProcFD() const { 564 return DumpLinux() || 565 m_dump_linux_proc_fd.GetOptionValue().GetCurrentValue(); 566 } 567 bool DumpFacebook() const { 568 return DumpAll() || m_fb_all.GetOptionValue().GetCurrentValue(); 569 } 570 bool DumpFacebookAppData() const { 571 return DumpFacebook() || m_fb_app_data.GetOptionValue().GetCurrentValue(); 572 } 573 bool DumpFacebookBuildID() const { 574 return DumpFacebook() || m_fb_build_id.GetOptionValue().GetCurrentValue(); 575 } 576 bool DumpFacebookVersionName() const { 577 return DumpFacebook() || m_fb_version.GetOptionValue().GetCurrentValue(); 578 } 579 bool DumpFacebookJavaStack() const { 580 return DumpFacebook() || m_fb_java_stack.GetOptionValue().GetCurrentValue(); 581 } 582 bool DumpFacebookDalvikInfo() const { 583 return DumpFacebook() || m_fb_dalvik.GetOptionValue().GetCurrentValue(); 584 } 585 bool DumpFacebookUnwindSymbols() const { 586 return DumpFacebook() || m_fb_unwind.GetOptionValue().GetCurrentValue(); 587 } 588 bool DumpFacebookErrorLog() const { 589 return DumpFacebook() || m_fb_error_log.GetOptionValue().GetCurrentValue(); 590 } 591 bool DumpFacebookAppStateLog() const { 592 return DumpFacebook() || m_fb_app_state.GetOptionValue().GetCurrentValue(); 593 } 594 bool DumpFacebookAbortReason() const { 595 return DumpFacebook() || m_fb_abort.GetOptionValue().GetCurrentValue(); 596 } 597 bool DumpFacebookThreadName() const { 598 return DumpFacebook() || m_fb_thread.GetOptionValue().GetCurrentValue(); 599 } 600 bool DumpFacebookLogcat() const { 601 return DumpFacebook() || m_fb_logcat.GetOptionValue().GetCurrentValue(); 602 } 603 public: 604 605 CommandObjectProcessMinidumpDump(CommandInterpreter &interpreter) 606 : CommandObjectParsed(interpreter, "process plugin dump", 607 "Dump information from the minidump file.", NULL), 608 m_option_group(), 609 INIT_BOOL(m_dump_all, "all", 'a', 610 "Dump the everything in the minidump."), 611 INIT_BOOL(m_dump_directory, "directory", 'd', 612 "Dump the minidump directory map."), 613 INIT_BOOL(m_dump_linux_cpuinfo, "cpuinfo", 'C', 614 "Dump linux /proc/cpuinfo."), 615 INIT_BOOL(m_dump_linux_proc_status, "status", 's', 616 "Dump linux /proc/<pid>/status."), 617 INIT_BOOL(m_dump_linux_lsb_release, "lsb-release", 'r', 618 "Dump linux /etc/lsb-release."), 619 INIT_BOOL(m_dump_linux_cmdline, "cmdline", 'c', 620 "Dump linux /proc/<pid>/cmdline."), 621 INIT_BOOL(m_dump_linux_environ, "environ", 'e', 622 "Dump linux /proc/<pid>/environ."), 623 INIT_BOOL(m_dump_linux_auxv, "auxv", 'x', 624 "Dump linux /proc/<pid>/auxv."), 625 INIT_BOOL(m_dump_linux_maps, "maps", 'm', 626 "Dump linux /proc/<pid>/maps."), 627 INIT_BOOL(m_dump_linux_proc_stat, "stat", 'S', 628 "Dump linux /proc/<pid>/stat."), 629 INIT_BOOL(m_dump_linux_proc_uptime, "uptime", 'u', 630 "Dump linux process uptime."), 631 INIT_BOOL(m_dump_linux_proc_fd, "fd", 'f', 632 "Dump linux /proc/<pid>/fd."), 633 INIT_BOOL(m_dump_linux_all, "linux", 'l', 634 "Dump all linux streams."), 635 INIT_BOOL(m_fb_app_data, "fb-app-data", 1, 636 "Dump Facebook application custom data."), 637 INIT_BOOL(m_fb_build_id, "fb-build-id", 2, 638 "Dump the Facebook build ID."), 639 INIT_BOOL(m_fb_version, "fb-version", 3, 640 "Dump Facebook application version string."), 641 INIT_BOOL(m_fb_java_stack, "fb-java-stack", 4, 642 "Dump Facebook java stack."), 643 INIT_BOOL(m_fb_dalvik, "fb-dalvik-info", 5, 644 "Dump Facebook Dalvik info."), 645 INIT_BOOL(m_fb_unwind, "fb-unwind-symbols", 6, 646 "Dump Facebook unwind symbols."), 647 INIT_BOOL(m_fb_error_log, "fb-error-log", 7, 648 "Dump Facebook error log."), 649 INIT_BOOL(m_fb_app_state, "fb-app-state-log", 8, 650 "Dump Facebook java stack."), 651 INIT_BOOL(m_fb_abort, "fb-abort-reason", 9, 652 "Dump Facebook abort reason."), 653 INIT_BOOL(m_fb_thread, "fb-thread-name", 10, 654 "Dump Facebook thread name."), 655 INIT_BOOL(m_fb_logcat, "fb-logcat", 11, 656 "Dump Facebook logcat."), 657 INIT_BOOL(m_fb_all, "facebook", 12, "Dump all Facebook streams.") { 658 APPEND_OPT(m_dump_all); 659 APPEND_OPT(m_dump_directory); 660 APPEND_OPT(m_dump_linux_cpuinfo); 661 APPEND_OPT(m_dump_linux_proc_status); 662 APPEND_OPT(m_dump_linux_lsb_release); 663 APPEND_OPT(m_dump_linux_cmdline); 664 APPEND_OPT(m_dump_linux_environ); 665 APPEND_OPT(m_dump_linux_auxv); 666 APPEND_OPT(m_dump_linux_maps); 667 APPEND_OPT(m_dump_linux_proc_stat); 668 APPEND_OPT(m_dump_linux_proc_uptime); 669 APPEND_OPT(m_dump_linux_proc_fd); 670 APPEND_OPT(m_dump_linux_all); 671 APPEND_OPT(m_fb_app_data); 672 APPEND_OPT(m_fb_build_id); 673 APPEND_OPT(m_fb_version); 674 APPEND_OPT(m_fb_java_stack); 675 APPEND_OPT(m_fb_dalvik); 676 APPEND_OPT(m_fb_unwind); 677 APPEND_OPT(m_fb_error_log); 678 APPEND_OPT(m_fb_app_state); 679 APPEND_OPT(m_fb_abort); 680 APPEND_OPT(m_fb_thread); 681 APPEND_OPT(m_fb_logcat); 682 APPEND_OPT(m_fb_all); 683 m_option_group.Finalize(); 684 } 685 686 ~CommandObjectProcessMinidumpDump() {} 687 688 Options *GetOptions() override { return &m_option_group; } 689 690 bool DoExecute(Args &command, CommandReturnObject &result) override { 691 const size_t argc = command.GetArgumentCount(); 692 if (argc > 0) { 693 result.AppendErrorWithFormat("'%s' take no arguments, only options", 694 m_cmd_name.c_str()); 695 result.SetStatus(eReturnStatusFailed); 696 return false; 697 } 698 SetDefaultOptionsIfNoneAreSet(); 699 700 ProcessMinidump *process = static_cast<ProcessMinidump *>( 701 m_interpreter.GetExecutionContext().GetProcessPtr()); 702 result.SetStatus(eReturnStatusSuccessFinishResult); 703 Stream &s = result.GetOutputStream(); 704 MinidumpParser &minidump = *process->m_minidump_parser; 705 if (DumpDirectory()) { 706 s.Printf("RVA SIZE TYPE StreamType\n"); 707 s.Printf("---------- ---------- ---------- --------------------------\n"); 708 for (const auto &stream_desc : minidump.GetMinidumpFile().streams()) 709 s.Printf( 710 "0x%8.8x 0x%8.8x 0x%8.8x %s\n", (uint32_t)stream_desc.Location.RVA, 711 (uint32_t)stream_desc.Location.DataSize, 712 (unsigned)(StreamType)stream_desc.Type, 713 MinidumpParser::GetStreamTypeAsString(stream_desc.Type).data()); 714 s.Printf("\n"); 715 } 716 auto DumpTextStream = [&](StreamType stream_type, 717 llvm::StringRef label) -> void { 718 auto bytes = minidump.GetStream(stream_type); 719 if (!bytes.empty()) { 720 if (label.empty()) 721 label = MinidumpParser::GetStreamTypeAsString(stream_type); 722 s.Printf("%s:\n%s\n\n", label.data(), bytes.data()); 723 } 724 }; 725 auto DumpBinaryStream = [&](StreamType stream_type, 726 llvm::StringRef label) -> void { 727 auto bytes = minidump.GetStream(stream_type); 728 if (!bytes.empty()) { 729 if (label.empty()) 730 label = MinidumpParser::GetStreamTypeAsString(stream_type); 731 s.Printf("%s:\n", label.data()); 732 DataExtractor data(bytes.data(), bytes.size(), eByteOrderLittle, 733 process->GetAddressByteSize()); 734 DumpDataExtractor(data, &s, 0, lldb::eFormatBytesWithASCII, 1, 735 bytes.size(), 16, 0, 0, 0); 736 s.Printf("\n\n"); 737 } 738 }; 739 740 if (DumpLinuxCPUInfo()) 741 DumpTextStream(StreamType::LinuxCPUInfo, "/proc/cpuinfo"); 742 if (DumpLinuxProcStatus()) 743 DumpTextStream(StreamType::LinuxProcStatus, "/proc/PID/status"); 744 if (DumpLinuxLSBRelease()) 745 DumpTextStream(StreamType::LinuxLSBRelease, "/etc/lsb-release"); 746 if (DumpLinuxCMDLine()) 747 DumpTextStream(StreamType::LinuxCMDLine, "/proc/PID/cmdline"); 748 if (DumpLinuxEnviron()) 749 DumpTextStream(StreamType::LinuxEnviron, "/proc/PID/environ"); 750 if (DumpLinuxAuxv()) 751 DumpBinaryStream(StreamType::LinuxAuxv, "/proc/PID/auxv"); 752 if (DumpLinuxMaps()) 753 DumpTextStream(StreamType::LinuxMaps, "/proc/PID/maps"); 754 if (DumpLinuxProcStat()) 755 DumpTextStream(StreamType::LinuxProcStat, "/proc/PID/stat"); 756 if (DumpLinuxProcUptime()) 757 DumpTextStream(StreamType::LinuxProcUptime, "uptime"); 758 if (DumpLinuxProcFD()) 759 DumpTextStream(StreamType::LinuxProcFD, "/proc/PID/fd"); 760 if (DumpFacebookAppData()) 761 DumpTextStream(StreamType::FacebookAppCustomData, 762 "Facebook App Data"); 763 if (DumpFacebookBuildID()) { 764 auto bytes = minidump.GetStream(StreamType::FacebookBuildID); 765 if (bytes.size() >= 4) { 766 DataExtractor data(bytes.data(), bytes.size(), eByteOrderLittle, 767 process->GetAddressByteSize()); 768 lldb::offset_t offset = 0; 769 uint32_t build_id = data.GetU32(&offset); 770 s.Printf("Facebook Build ID:\n"); 771 s.Printf("%u\n", build_id); 772 s.Printf("\n"); 773 } 774 } 775 if (DumpFacebookVersionName()) 776 DumpTextStream(StreamType::FacebookAppVersionName, 777 "Facebook Version String"); 778 if (DumpFacebookJavaStack()) 779 DumpTextStream(StreamType::FacebookJavaStack, 780 "Facebook Java Stack"); 781 if (DumpFacebookDalvikInfo()) 782 DumpTextStream(StreamType::FacebookDalvikInfo, 783 "Facebook Dalvik Info"); 784 if (DumpFacebookUnwindSymbols()) 785 DumpBinaryStream(StreamType::FacebookUnwindSymbols, 786 "Facebook Unwind Symbols Bytes"); 787 if (DumpFacebookErrorLog()) 788 DumpTextStream(StreamType::FacebookDumpErrorLog, 789 "Facebook Error Log"); 790 if (DumpFacebookAppStateLog()) 791 DumpTextStream(StreamType::FacebookAppStateLog, 792 "Faceook Application State Log"); 793 if (DumpFacebookAbortReason()) 794 DumpTextStream(StreamType::FacebookAbortReason, 795 "Facebook Abort Reason"); 796 if (DumpFacebookThreadName()) 797 DumpTextStream(StreamType::FacebookThreadName, 798 "Facebook Thread Name"); 799 if (DumpFacebookLogcat()) 800 DumpTextStream(StreamType::FacebookLogcat, 801 "Facebook Logcat"); 802 return true; 803 } 804 }; 805 806 class CommandObjectMultiwordProcessMinidump : public CommandObjectMultiword { 807 public: 808 CommandObjectMultiwordProcessMinidump(CommandInterpreter &interpreter) 809 : CommandObjectMultiword(interpreter, "process plugin", 810 "Commands for operating on a ProcessMinidump process.", 811 "process plugin <subcommand> [<subcommand-options>]") { 812 LoadSubCommand("dump", 813 CommandObjectSP(new CommandObjectProcessMinidumpDump(interpreter))); 814 } 815 816 ~CommandObjectMultiwordProcessMinidump() {} 817 }; 818 819 CommandObject *ProcessMinidump::GetPluginCommandObject() { 820 if (!m_command_sp) 821 m_command_sp = std::make_shared<CommandObjectMultiwordProcessMinidump>( 822 GetTarget().GetDebugger().GetCommandInterpreter()); 823 return m_command_sp.get(); 824 } 825