From 8c31efeed6007bade1e4ddda2ceccab311661cbc Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Wed, 11 Aug 2021 13:37:31 -0700 Subject: Add the ability to process save-core stack-memory-only corefiles Add a field to the qMemoryRegionInfo packet where the remote stub can describe the type of memory -- heap, stack. Keep track of memory regions that are stack memory in lldb. Add a new "--style stack" to process save-core to request that only stack memory be included in the corefile. Differential Revision: https://reviews.llvm.org/D107625 --- lldb/source/Commands/CommandObjectProcess.cpp | 13 +++--- .../Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp | 52 +++++++++++++++------- .../gdb-remote/GDBRemoteCommunicationClient.cpp | 13 ++++++ 3 files changed, 57 insertions(+), 21 deletions(-) (limited to 'lldb/source') diff --git a/lldb/source/Commands/CommandObjectProcess.cpp b/lldb/source/Commands/CommandObjectProcess.cpp index 1a8ed021b9f0..c65b661f9cfc 100644 --- a/lldb/source/Commands/CommandObjectProcess.cpp +++ b/lldb/source/Commands/CommandObjectProcess.cpp @@ -1166,7 +1166,9 @@ protected: static constexpr OptionEnumValueElement g_corefile_save_style[] = { {eSaveCoreFull, "full", "Create a core file with all memory saved"}, {eSaveCoreDirtyOnly, "modified-memory", - "Create a corefile with only modified memory saved"}}; + "Create a corefile with only modified memory saved"}, + {eSaveCoreStackOnly, "stack", + "Create a corefile with only stack memory saved"}}; static constexpr OptionEnumValues SaveCoreStyles() { return OptionEnumValues(g_corefile_save_style); @@ -1237,11 +1239,12 @@ protected: Status error = PluginManager::SaveCore(process_sp, output_file, corefile_style); if (error.Success()) { - if (corefile_style == SaveCoreStyle::eSaveCoreDirtyOnly) { + if (corefile_style == SaveCoreStyle::eSaveCoreDirtyOnly || + corefile_style == SaveCoreStyle::eSaveCoreStackOnly) { result.AppendMessageWithFormat( - "\nModified-memory only corefile " - "created. This corefile may not show \n" - "library/framework/app binaries " + "\nModified-memory or stack-memory only corefile " + "created. This corefile may \n" + "not show library/framework/app binaries " "on a different system, or when \n" "those binaries have " "been updated/modified. Copies are not included\n" diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp index ce5324943171..decccc494bc0 100644 --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -6342,13 +6342,17 @@ struct segment_vmaddr { // are some multiple passes over the image list while calculating // everything. -static offset_t -CreateAllImageInfosPayload(const lldb::ProcessSP &process_sp, - offset_t initial_file_offset, - StreamString &all_image_infos_payload) { +static offset_t CreateAllImageInfosPayload( + const lldb::ProcessSP &process_sp, offset_t initial_file_offset, + StreamString &all_image_infos_payload, SaveCoreStyle core_style) { Target &target = process_sp->GetTarget(); - const ModuleList &modules = target.GetImages(); - size_t modules_count = modules.GetSize(); + ModuleList modules = target.GetImages(); + + // stack-only corefiles have no reason to include binaries that + // are not executing; we're trying to make the smallest corefile + // we can, so leave the rest out. + if (core_style == SaveCoreStyle::eSaveCoreStackOnly) + modules.Clear(); std::set executing_uuids; ThreadList &thread_list(process_sp->GetThreadList()); @@ -6363,10 +6367,12 @@ CreateAllImageInfosPayload(const lldb::ProcessSP &process_sp, UUID uuid = module_sp->GetUUID(); if (uuid.IsValid()) { executing_uuids.insert(uuid.GetAsString()); + modules.AppendIfNeeded(module_sp); } } } } + size_t modules_count = modules.GetSize(); struct all_image_infos_header infos; infos.version = 1; @@ -6508,12 +6514,9 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp, if (!process_sp) return false; - // For Mach-O, we can only create full corefiles or dirty-page-only - // corefiles. The default is dirty-page-only. - if (core_style != SaveCoreStyle::eSaveCoreFull) { + // Default on macOS is to create a dirty-memory-only corefile. + if (core_style == SaveCoreStyle::eSaveCoreUnspecified) { core_style = SaveCoreStyle::eSaveCoreDirtyOnly; - } else { - core_style = SaveCoreStyle::eSaveCoreFull; } Target &target = process_sp->GetTarget(); @@ -6568,13 +6571,23 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp, if (size == 0) break; - if (prot != 0) { + bool include_this_region = true; + bool dirty_pages_only = false; + if (core_style == SaveCoreStyle::eSaveCoreStackOnly) { + dirty_pages_only = true; + if (range_info.IsStackMemory() != MemoryRegionInfo::eYes) { + include_this_region = false; + } + } + if (core_style == SaveCoreStyle::eSaveCoreDirtyOnly) { + dirty_pages_only = true; + } + + if (prot != 0 && include_this_region) { addr_t pagesize = range_info.GetPageSize(); const llvm::Optional> &dirty_page_list = range_info.GetDirtyPageList(); - if (core_style == SaveCoreStyle::eSaveCoreDirtyOnly && - dirty_page_list.hasValue()) { - core_style = SaveCoreStyle::eSaveCoreDirtyOnly; + if (dirty_pages_only && dirty_page_list.hasValue()) { for (addr_t dirtypage : dirty_page_list.getValue()) { page_object obj; obj.addr = dirtypage; @@ -6617,6 +6630,12 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp, last_obj = obj; } + // If we only ended up with one contiguous memory segment + if (combined_page_objects.size() == 0 && + last_obj.addr != LLDB_INVALID_ADDRESS) { + combined_page_objects.push_back(last_obj); + } + for (page_object obj : combined_page_objects) { uint32_t cmd_type = LC_SEGMENT_64; uint32_t segment_size = sizeof(llvm::MachO::segment_command_64); @@ -6767,7 +6786,8 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp, all_image_infos_lcnote_up->name = "all image infos"; all_image_infos_lcnote_up->payload_file_offset = file_offset; file_offset = CreateAllImageInfosPayload( - process_sp, file_offset, all_image_infos_lcnote_up->payload); + process_sp, file_offset, all_image_infos_lcnote_up->payload, + core_style); lc_notes.push_back(std::move(all_image_infos_lcnote_up)); // Add LC_NOTE load commands diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index ee8c7c66573d..e898a08641dc 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -1572,6 +1572,19 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo( } } } + } else if (name.equals("type")) { + std::string comma_sep_str = value.str(); + size_t comma_pos; + while ((comma_pos = comma_sep_str.find(',')) != std::string::npos) { + comma_sep_str[comma_pos] = '\0'; + if (comma_sep_str == "stack") { + region_info.SetIsStackMemory(MemoryRegionInfo::eYes); + } + } + // handle final (or only) type of "stack" + if (comma_sep_str == "stack") { + region_info.SetIsStackMemory(MemoryRegionInfo::eYes); + } } else if (name.equals("error")) { StringExtractorGDBRemote error_extractor(value); std::string error_string; -- cgit v1.2.3