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