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 minidump::Thread &thread : m_thread_list) { 330 LocationDescriptor context_location = 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.ThreadId) { 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 ModuleSpec module_spec(file_spec, uuid); 372 module_spec.GetArchitecture() = GetArchitecture(); 373 Status error; 374 // Try and find a module with a full UUID that matches. This function will 375 // add the module to the target if it finds one. 376 lldb::ModuleSP module_sp = GetTarget().GetOrCreateModule(module_spec, 377 true /* notify */, &error); 378 if (!module_sp) { 379 // Try and find a module without specifying the UUID and only looking for 380 // the file given a basename. We then will look for a partial UUID match 381 // if we find any matches. This function will add the module to the 382 // target if it finds one, so we need to remove the module from the target 383 // if the UUID doesn't match during our manual UUID verification. This 384 // allows the "target.exec-search-paths" setting to specify one or more 385 // directories that contain executables that can be searched for matches. 386 ModuleSpec basename_module_spec(module_spec); 387 basename_module_spec.GetUUID().Clear(); 388 basename_module_spec.GetFileSpec().GetDirectory().Clear(); 389 module_sp = GetTarget().GetOrCreateModule(basename_module_spec, 390 true /* notify */, &error); 391 if (module_sp) { 392 // We consider the module to be a match if the minidump UUID is a 393 // prefix of the actual UUID, or if either of the UUIDs are empty. 394 const auto dmp_bytes = uuid.GetBytes(); 395 const auto mod_bytes = module_sp->GetUUID().GetBytes(); 396 const bool match = dmp_bytes.empty() || mod_bytes.empty() || 397 mod_bytes.take_front(dmp_bytes.size()) == dmp_bytes; 398 if (!match) { 399 GetTarget().GetImages().Remove(module_sp); 400 module_sp.reset(); 401 } 402 } 403 } 404 if (!module_sp) { 405 // We failed to locate a matching local object file. Fortunately, the 406 // minidump format encodes enough information about each module's memory 407 // range to allow us to create placeholder modules. 408 // 409 // This enables most LLDB functionality involving address-to-module 410 // translations (ex. identifing the module for a stack frame PC) and 411 // modules/sections commands (ex. target modules list, ...) 412 LLDB_LOG(log, 413 "Unable to locate the matching object file, creating a " 414 "placeholder module for: {0}", 415 name); 416 417 module_sp = Module::CreateModuleFromObjectFile<PlaceholderObjectFile>( 418 module_spec, module->BaseOfImage, module->SizeOfImage); 419 GetTarget().GetImages().Append(module_sp, true /* notify */); 420 } 421 422 bool load_addr_changed = false; 423 module_sp->SetLoadAddress(GetTarget(), module->BaseOfImage, false, 424 load_addr_changed); 425 } 426 } 427 428 bool ProcessMinidump::GetProcessInfo(ProcessInstanceInfo &info) { 429 info.Clear(); 430 info.SetProcessID(GetID()); 431 info.SetArchitecture(GetArchitecture()); 432 lldb::ModuleSP module_sp = GetTarget().GetExecutableModule(); 433 if (module_sp) { 434 const bool add_exe_file_as_first_arg = false; 435 info.SetExecutableFile(GetTarget().GetExecutableModule()->GetFileSpec(), 436 add_exe_file_as_first_arg); 437 } 438 return true; 439 } 440 441 // For minidumps there's no runtime generated code so we don't need JITLoader(s) 442 // Avoiding them will also speed up minidump loading since JITLoaders normally 443 // try to set up symbolic breakpoints, which in turn may force loading more 444 // debug information than needed. 445 JITLoaderList &ProcessMinidump::GetJITLoaders() { 446 if (!m_jit_loaders_up) { 447 m_jit_loaders_up = llvm::make_unique<JITLoaderList>(); 448 } 449 return *m_jit_loaders_up; 450 } 451 452 #define INIT_BOOL(VAR, LONG, SHORT, DESC) \ 453 VAR(LLDB_OPT_SET_1, false, LONG, SHORT, DESC, false, true) 454 #define APPEND_OPT(VAR) \ 455 m_option_group.Append(&VAR, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1) 456 457 class CommandObjectProcessMinidumpDump : public CommandObjectParsed { 458 private: 459 OptionGroupOptions m_option_group; 460 OptionGroupBoolean m_dump_all; 461 OptionGroupBoolean m_dump_directory; 462 OptionGroupBoolean m_dump_linux_cpuinfo; 463 OptionGroupBoolean m_dump_linux_proc_status; 464 OptionGroupBoolean m_dump_linux_lsb_release; 465 OptionGroupBoolean m_dump_linux_cmdline; 466 OptionGroupBoolean m_dump_linux_environ; 467 OptionGroupBoolean m_dump_linux_auxv; 468 OptionGroupBoolean m_dump_linux_maps; 469 OptionGroupBoolean m_dump_linux_proc_stat; 470 OptionGroupBoolean m_dump_linux_proc_uptime; 471 OptionGroupBoolean m_dump_linux_proc_fd; 472 OptionGroupBoolean m_dump_linux_all; 473 OptionGroupBoolean m_fb_app_data; 474 OptionGroupBoolean m_fb_build_id; 475 OptionGroupBoolean m_fb_version; 476 OptionGroupBoolean m_fb_java_stack; 477 OptionGroupBoolean m_fb_dalvik; 478 OptionGroupBoolean m_fb_unwind; 479 OptionGroupBoolean m_fb_error_log; 480 OptionGroupBoolean m_fb_app_state; 481 OptionGroupBoolean m_fb_abort; 482 OptionGroupBoolean m_fb_thread; 483 OptionGroupBoolean m_fb_logcat; 484 OptionGroupBoolean m_fb_all; 485 486 void SetDefaultOptionsIfNoneAreSet() { 487 if (m_dump_all.GetOptionValue().GetCurrentValue() || 488 m_dump_linux_all.GetOptionValue().GetCurrentValue() || 489 m_fb_all.GetOptionValue().GetCurrentValue() || 490 m_dump_directory.GetOptionValue().GetCurrentValue() || 491 m_dump_linux_cpuinfo.GetOptionValue().GetCurrentValue() || 492 m_dump_linux_proc_status.GetOptionValue().GetCurrentValue() || 493 m_dump_linux_lsb_release.GetOptionValue().GetCurrentValue() || 494 m_dump_linux_cmdline.GetOptionValue().GetCurrentValue() || 495 m_dump_linux_environ.GetOptionValue().GetCurrentValue() || 496 m_dump_linux_auxv.GetOptionValue().GetCurrentValue() || 497 m_dump_linux_maps.GetOptionValue().GetCurrentValue() || 498 m_dump_linux_proc_stat.GetOptionValue().GetCurrentValue() || 499 m_dump_linux_proc_uptime.GetOptionValue().GetCurrentValue() || 500 m_dump_linux_proc_fd.GetOptionValue().GetCurrentValue() || 501 m_fb_app_data.GetOptionValue().GetCurrentValue() || 502 m_fb_build_id.GetOptionValue().GetCurrentValue() || 503 m_fb_version.GetOptionValue().GetCurrentValue() || 504 m_fb_java_stack.GetOptionValue().GetCurrentValue() || 505 m_fb_dalvik.GetOptionValue().GetCurrentValue() || 506 m_fb_unwind.GetOptionValue().GetCurrentValue() || 507 m_fb_error_log.GetOptionValue().GetCurrentValue() || 508 m_fb_app_state.GetOptionValue().GetCurrentValue() || 509 m_fb_abort.GetOptionValue().GetCurrentValue() || 510 m_fb_thread.GetOptionValue().GetCurrentValue() || 511 m_fb_logcat.GetOptionValue().GetCurrentValue()) 512 return; 513 // If no options were set, then dump everything 514 m_dump_all.GetOptionValue().SetCurrentValue(true); 515 } 516 bool DumpAll() const { 517 return m_dump_all.GetOptionValue().GetCurrentValue(); 518 } 519 bool DumpDirectory() const { 520 return DumpAll() || 521 m_dump_directory.GetOptionValue().GetCurrentValue(); 522 } 523 bool DumpLinux() const { 524 return DumpAll() || m_dump_linux_all.GetOptionValue().GetCurrentValue(); 525 } 526 bool DumpLinuxCPUInfo() const { 527 return DumpLinux() || 528 m_dump_linux_cpuinfo.GetOptionValue().GetCurrentValue(); 529 } 530 bool DumpLinuxProcStatus() const { 531 return DumpLinux() || 532 m_dump_linux_proc_status.GetOptionValue().GetCurrentValue(); 533 } 534 bool DumpLinuxProcStat() const { 535 return DumpLinux() || 536 m_dump_linux_proc_stat.GetOptionValue().GetCurrentValue(); 537 } 538 bool DumpLinuxLSBRelease() const { 539 return DumpLinux() || 540 m_dump_linux_lsb_release.GetOptionValue().GetCurrentValue(); 541 } 542 bool DumpLinuxCMDLine() const { 543 return DumpLinux() || 544 m_dump_linux_cmdline.GetOptionValue().GetCurrentValue(); 545 } 546 bool DumpLinuxEnviron() const { 547 return DumpLinux() || 548 m_dump_linux_environ.GetOptionValue().GetCurrentValue(); 549 } 550 bool DumpLinuxAuxv() const { 551 return DumpLinux() || 552 m_dump_linux_auxv.GetOptionValue().GetCurrentValue(); 553 } 554 bool DumpLinuxMaps() const { 555 return DumpLinux() || 556 m_dump_linux_maps.GetOptionValue().GetCurrentValue(); 557 } 558 bool DumpLinuxProcUptime() const { 559 return DumpLinux() || 560 m_dump_linux_proc_uptime.GetOptionValue().GetCurrentValue(); 561 } 562 bool DumpLinuxProcFD() const { 563 return DumpLinux() || 564 m_dump_linux_proc_fd.GetOptionValue().GetCurrentValue(); 565 } 566 bool DumpFacebook() const { 567 return DumpAll() || m_fb_all.GetOptionValue().GetCurrentValue(); 568 } 569 bool DumpFacebookAppData() const { 570 return DumpFacebook() || m_fb_app_data.GetOptionValue().GetCurrentValue(); 571 } 572 bool DumpFacebookBuildID() const { 573 return DumpFacebook() || m_fb_build_id.GetOptionValue().GetCurrentValue(); 574 } 575 bool DumpFacebookVersionName() const { 576 return DumpFacebook() || m_fb_version.GetOptionValue().GetCurrentValue(); 577 } 578 bool DumpFacebookJavaStack() const { 579 return DumpFacebook() || m_fb_java_stack.GetOptionValue().GetCurrentValue(); 580 } 581 bool DumpFacebookDalvikInfo() const { 582 return DumpFacebook() || m_fb_dalvik.GetOptionValue().GetCurrentValue(); 583 } 584 bool DumpFacebookUnwindSymbols() const { 585 return DumpFacebook() || m_fb_unwind.GetOptionValue().GetCurrentValue(); 586 } 587 bool DumpFacebookErrorLog() const { 588 return DumpFacebook() || m_fb_error_log.GetOptionValue().GetCurrentValue(); 589 } 590 bool DumpFacebookAppStateLog() const { 591 return DumpFacebook() || m_fb_app_state.GetOptionValue().GetCurrentValue(); 592 } 593 bool DumpFacebookAbortReason() const { 594 return DumpFacebook() || m_fb_abort.GetOptionValue().GetCurrentValue(); 595 } 596 bool DumpFacebookThreadName() const { 597 return DumpFacebook() || m_fb_thread.GetOptionValue().GetCurrentValue(); 598 } 599 bool DumpFacebookLogcat() const { 600 return DumpFacebook() || m_fb_logcat.GetOptionValue().GetCurrentValue(); 601 } 602 public: 603 CommandObjectProcessMinidumpDump(CommandInterpreter &interpreter) 604 : CommandObjectParsed(interpreter, "process plugin dump", 605 "Dump information from the minidump file.", nullptr), 606 m_option_group(), 607 INIT_BOOL(m_dump_all, "all", 'a', 608 "Dump the everything in the minidump."), 609 INIT_BOOL(m_dump_directory, "directory", 'd', 610 "Dump the minidump directory map."), 611 INIT_BOOL(m_dump_linux_cpuinfo, "cpuinfo", 'C', 612 "Dump linux /proc/cpuinfo."), 613 INIT_BOOL(m_dump_linux_proc_status, "status", 's', 614 "Dump linux /proc/<pid>/status."), 615 INIT_BOOL(m_dump_linux_lsb_release, "lsb-release", 'r', 616 "Dump linux /etc/lsb-release."), 617 INIT_BOOL(m_dump_linux_cmdline, "cmdline", 'c', 618 "Dump linux /proc/<pid>/cmdline."), 619 INIT_BOOL(m_dump_linux_environ, "environ", 'e', 620 "Dump linux /proc/<pid>/environ."), 621 INIT_BOOL(m_dump_linux_auxv, "auxv", 'x', 622 "Dump linux /proc/<pid>/auxv."), 623 INIT_BOOL(m_dump_linux_maps, "maps", 'm', 624 "Dump linux /proc/<pid>/maps."), 625 INIT_BOOL(m_dump_linux_proc_stat, "stat", 'S', 626 "Dump linux /proc/<pid>/stat."), 627 INIT_BOOL(m_dump_linux_proc_uptime, "uptime", 'u', 628 "Dump linux process uptime."), 629 INIT_BOOL(m_dump_linux_proc_fd, "fd", 'f', 630 "Dump linux /proc/<pid>/fd."), 631 INIT_BOOL(m_dump_linux_all, "linux", 'l', 632 "Dump all linux streams."), 633 INIT_BOOL(m_fb_app_data, "fb-app-data", 1, 634 "Dump Facebook application custom data."), 635 INIT_BOOL(m_fb_build_id, "fb-build-id", 2, 636 "Dump the Facebook build ID."), 637 INIT_BOOL(m_fb_version, "fb-version", 3, 638 "Dump Facebook application version string."), 639 INIT_BOOL(m_fb_java_stack, "fb-java-stack", 4, 640 "Dump Facebook java stack."), 641 INIT_BOOL(m_fb_dalvik, "fb-dalvik-info", 5, 642 "Dump Facebook Dalvik info."), 643 INIT_BOOL(m_fb_unwind, "fb-unwind-symbols", 6, 644 "Dump Facebook unwind symbols."), 645 INIT_BOOL(m_fb_error_log, "fb-error-log", 7, 646 "Dump Facebook error log."), 647 INIT_BOOL(m_fb_app_state, "fb-app-state-log", 8, 648 "Dump Facebook java stack."), 649 INIT_BOOL(m_fb_abort, "fb-abort-reason", 9, 650 "Dump Facebook abort reason."), 651 INIT_BOOL(m_fb_thread, "fb-thread-name", 10, 652 "Dump Facebook thread name."), 653 INIT_BOOL(m_fb_logcat, "fb-logcat", 11, 654 "Dump Facebook logcat."), 655 INIT_BOOL(m_fb_all, "facebook", 12, "Dump all Facebook streams.") { 656 APPEND_OPT(m_dump_all); 657 APPEND_OPT(m_dump_directory); 658 APPEND_OPT(m_dump_linux_cpuinfo); 659 APPEND_OPT(m_dump_linux_proc_status); 660 APPEND_OPT(m_dump_linux_lsb_release); 661 APPEND_OPT(m_dump_linux_cmdline); 662 APPEND_OPT(m_dump_linux_environ); 663 APPEND_OPT(m_dump_linux_auxv); 664 APPEND_OPT(m_dump_linux_maps); 665 APPEND_OPT(m_dump_linux_proc_stat); 666 APPEND_OPT(m_dump_linux_proc_uptime); 667 APPEND_OPT(m_dump_linux_proc_fd); 668 APPEND_OPT(m_dump_linux_all); 669 APPEND_OPT(m_fb_app_data); 670 APPEND_OPT(m_fb_build_id); 671 APPEND_OPT(m_fb_version); 672 APPEND_OPT(m_fb_java_stack); 673 APPEND_OPT(m_fb_dalvik); 674 APPEND_OPT(m_fb_unwind); 675 APPEND_OPT(m_fb_error_log); 676 APPEND_OPT(m_fb_app_state); 677 APPEND_OPT(m_fb_abort); 678 APPEND_OPT(m_fb_thread); 679 APPEND_OPT(m_fb_logcat); 680 APPEND_OPT(m_fb_all); 681 m_option_group.Finalize(); 682 } 683 684 ~CommandObjectProcessMinidumpDump() override {} 685 686 Options *GetOptions() override { return &m_option_group; } 687 688 bool DoExecute(Args &command, CommandReturnObject &result) override { 689 const size_t argc = command.GetArgumentCount(); 690 if (argc > 0) { 691 result.AppendErrorWithFormat("'%s' take no arguments, only options", 692 m_cmd_name.c_str()); 693 result.SetStatus(eReturnStatusFailed); 694 return false; 695 } 696 SetDefaultOptionsIfNoneAreSet(); 697 698 ProcessMinidump *process = static_cast<ProcessMinidump *>( 699 m_interpreter.GetExecutionContext().GetProcessPtr()); 700 result.SetStatus(eReturnStatusSuccessFinishResult); 701 Stream &s = result.GetOutputStream(); 702 MinidumpParser &minidump = *process->m_minidump_parser; 703 if (DumpDirectory()) { 704 s.Printf("RVA SIZE TYPE StreamType\n"); 705 s.Printf("---------- ---------- ---------- --------------------------\n"); 706 for (const auto &stream_desc : minidump.GetMinidumpFile().streams()) 707 s.Printf( 708 "0x%8.8x 0x%8.8x 0x%8.8x %s\n", (uint32_t)stream_desc.Location.RVA, 709 (uint32_t)stream_desc.Location.DataSize, 710 (unsigned)(StreamType)stream_desc.Type, 711 MinidumpParser::GetStreamTypeAsString(stream_desc.Type).data()); 712 s.Printf("\n"); 713 } 714 auto DumpTextStream = [&](StreamType stream_type, 715 llvm::StringRef label) -> void { 716 auto bytes = minidump.GetStream(stream_type); 717 if (!bytes.empty()) { 718 if (label.empty()) 719 label = MinidumpParser::GetStreamTypeAsString(stream_type); 720 s.Printf("%s:\n%s\n\n", label.data(), bytes.data()); 721 } 722 }; 723 auto DumpBinaryStream = [&](StreamType stream_type, 724 llvm::StringRef label) -> void { 725 auto bytes = minidump.GetStream(stream_type); 726 if (!bytes.empty()) { 727 if (label.empty()) 728 label = MinidumpParser::GetStreamTypeAsString(stream_type); 729 s.Printf("%s:\n", label.data()); 730 DataExtractor data(bytes.data(), bytes.size(), eByteOrderLittle, 731 process->GetAddressByteSize()); 732 DumpDataExtractor(data, &s, 0, lldb::eFormatBytesWithASCII, 1, 733 bytes.size(), 16, 0, 0, 0); 734 s.Printf("\n\n"); 735 } 736 }; 737 738 if (DumpLinuxCPUInfo()) 739 DumpTextStream(StreamType::LinuxCPUInfo, "/proc/cpuinfo"); 740 if (DumpLinuxProcStatus()) 741 DumpTextStream(StreamType::LinuxProcStatus, "/proc/PID/status"); 742 if (DumpLinuxLSBRelease()) 743 DumpTextStream(StreamType::LinuxLSBRelease, "/etc/lsb-release"); 744 if (DumpLinuxCMDLine()) 745 DumpTextStream(StreamType::LinuxCMDLine, "/proc/PID/cmdline"); 746 if (DumpLinuxEnviron()) 747 DumpTextStream(StreamType::LinuxEnviron, "/proc/PID/environ"); 748 if (DumpLinuxAuxv()) 749 DumpBinaryStream(StreamType::LinuxAuxv, "/proc/PID/auxv"); 750 if (DumpLinuxMaps()) 751 DumpTextStream(StreamType::LinuxMaps, "/proc/PID/maps"); 752 if (DumpLinuxProcStat()) 753 DumpTextStream(StreamType::LinuxProcStat, "/proc/PID/stat"); 754 if (DumpLinuxProcUptime()) 755 DumpTextStream(StreamType::LinuxProcUptime, "uptime"); 756 if (DumpLinuxProcFD()) 757 DumpTextStream(StreamType::LinuxProcFD, "/proc/PID/fd"); 758 if (DumpFacebookAppData()) 759 DumpTextStream(StreamType::FacebookAppCustomData, 760 "Facebook App Data"); 761 if (DumpFacebookBuildID()) { 762 auto bytes = minidump.GetStream(StreamType::FacebookBuildID); 763 if (bytes.size() >= 4) { 764 DataExtractor data(bytes.data(), bytes.size(), eByteOrderLittle, 765 process->GetAddressByteSize()); 766 lldb::offset_t offset = 0; 767 uint32_t build_id = data.GetU32(&offset); 768 s.Printf("Facebook Build ID:\n"); 769 s.Printf("%u\n", build_id); 770 s.Printf("\n"); 771 } 772 } 773 if (DumpFacebookVersionName()) 774 DumpTextStream(StreamType::FacebookAppVersionName, 775 "Facebook Version String"); 776 if (DumpFacebookJavaStack()) 777 DumpTextStream(StreamType::FacebookJavaStack, 778 "Facebook Java Stack"); 779 if (DumpFacebookDalvikInfo()) 780 DumpTextStream(StreamType::FacebookDalvikInfo, 781 "Facebook Dalvik Info"); 782 if (DumpFacebookUnwindSymbols()) 783 DumpBinaryStream(StreamType::FacebookUnwindSymbols, 784 "Facebook Unwind Symbols Bytes"); 785 if (DumpFacebookErrorLog()) 786 DumpTextStream(StreamType::FacebookDumpErrorLog, 787 "Facebook Error Log"); 788 if (DumpFacebookAppStateLog()) 789 DumpTextStream(StreamType::FacebookAppStateLog, 790 "Faceook Application State Log"); 791 if (DumpFacebookAbortReason()) 792 DumpTextStream(StreamType::FacebookAbortReason, 793 "Facebook Abort Reason"); 794 if (DumpFacebookThreadName()) 795 DumpTextStream(StreamType::FacebookThreadName, 796 "Facebook Thread Name"); 797 if (DumpFacebookLogcat()) 798 DumpTextStream(StreamType::FacebookLogcat, 799 "Facebook Logcat"); 800 return true; 801 } 802 }; 803 804 class CommandObjectMultiwordProcessMinidump : public CommandObjectMultiword { 805 public: 806 CommandObjectMultiwordProcessMinidump(CommandInterpreter &interpreter) 807 : CommandObjectMultiword(interpreter, "process plugin", 808 "Commands for operating on a ProcessMinidump process.", 809 "process plugin <subcommand> [<subcommand-options>]") { 810 LoadSubCommand("dump", 811 CommandObjectSP(new CommandObjectProcessMinidumpDump(interpreter))); 812 } 813 814 ~CommandObjectMultiwordProcessMinidump() override {} 815 }; 816 817 CommandObject *ProcessMinidump::GetPluginCommandObject() { 818 if (!m_command_sp) 819 m_command_sp = std::make_shared<CommandObjectMultiwordProcessMinidump>( 820 GetTarget().GetDebugger().GetCommandInterpreter()); 821 return m_command_sp.get(); 822 } 823