This revision was not accepted when it landed; it landed in state "Needs 
Review".
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG8c31efeed600: Add the ability to process save-core 
stack-memory-only corefiles (authored by jasonmolenda).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D107625/new/

https://reviews.llvm.org/D107625

Files:
  lldb/docs/lldb-gdb-remote.txt
  lldb/include/lldb/Target/MemoryRegionInfo.h
  lldb/include/lldb/lldb-enumerations.h
  lldb/source/Commands/CommandObjectProcess.cpp
  lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
  lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
  lldb/test/API/macosx/skinny-corefile/TestSkinnyCorefile.py
  lldb/test/API/macosx/stack-corefile/Makefile
  lldb/test/API/macosx/stack-corefile/TestStackCorefile.py
  lldb/test/API/macosx/stack-corefile/main.c
  lldb/tools/debugserver/source/DNBDefs.h
  lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp
  lldb/tools/debugserver/source/MacOSX/MachVMRegion.cpp
  lldb/tools/debugserver/source/MacOSX/MachVMRegion.h
  lldb/tools/debugserver/source/RNBRemote.cpp

Index: lldb/tools/debugserver/source/RNBRemote.cpp
===================================================================
--- lldb/tools/debugserver/source/RNBRemote.cpp
+++ lldb/tools/debugserver/source/RNBRemote.cpp
@@ -4310,6 +4310,14 @@
       }
     }
     ostrm << ";";
+    if (!region_info.vm_types.empty()) {
+      for (size_t i = 0; i < region_info.vm_types.size(); i++) {
+        if (i)
+          ostrm << ",";
+        ostrm << region_info.vm_types[i];
+      }
+      ostrm << ";";
+    }
   }
   return SendPacket(ostrm.str());
 }
Index: lldb/tools/debugserver/source/MacOSX/MachVMRegion.h
===================================================================
--- lldb/tools/debugserver/source/MacOSX/MachVMRegion.h
+++ lldb/tools/debugserver/source/MacOSX/MachVMRegion.h
@@ -40,6 +40,7 @@
                       vm_prot_t prot);
   bool RestoreProtections();
   bool GetRegionForAddress(nub_addr_t addr);
+  std::vector<std::string> GetMemoryTypes() const;
 
   uint32_t GetDNBPermissions() const;
 
Index: lldb/tools/debugserver/source/MacOSX/MachVMRegion.cpp
===================================================================
--- lldb/tools/debugserver/source/MacOSX/MachVMRegion.cpp
+++ lldb/tools/debugserver/source/MacOSX/MachVMRegion.cpp
@@ -182,3 +182,43 @@
     dnb_permissions |= eMemoryPermissionsExecutable;
   return dnb_permissions;
 }
+
+std::vector<std::string> MachVMRegion::GetMemoryTypes() const {
+  std::vector<std::string> types;
+  if (m_data.user_tag == VM_MEMORY_STACK) {
+    if (m_data.protection == VM_PROT_NONE) {
+      types.push_back("stack-guard");
+    } else {
+      types.push_back("stack");
+    }
+  }
+  if (m_data.user_tag == VM_MEMORY_MALLOC) {
+    if (m_data.protection == VM_PROT_NONE)
+      types.push_back("malloc-guard");
+    else if (m_data.share_mode == SM_EMPTY)
+      types.push_back("malloc-reserved");
+    else
+      types.push_back("malloc-metadata");
+  }
+  if (m_data.user_tag == VM_MEMORY_MALLOC_NANO ||
+      m_data.user_tag == VM_MEMORY_MALLOC_TINY ||
+      m_data.user_tag == VM_MEMORY_MALLOC_SMALL ||
+      m_data.user_tag == VM_MEMORY_MALLOC_LARGE ||
+      m_data.user_tag == VM_MEMORY_MALLOC_LARGE_REUSED ||
+      m_data.user_tag == VM_MEMORY_MALLOC_LARGE_REUSABLE ||
+      m_data.user_tag == VM_MEMORY_MALLOC_HUGE ||
+      m_data.user_tag == VM_MEMORY_REALLOC ||
+      m_data.user_tag == VM_MEMORY_SBRK) {
+    types.push_back("heap");
+    if (m_data.user_tag == VM_MEMORY_MALLOC_TINY) {
+      types.push_back("malloc-tiny");
+    }
+    if (m_data.user_tag == VM_MEMORY_MALLOC_LARGE) {
+      types.push_back("malloc-large");
+    }
+    if (m_data.user_tag == VM_MEMORY_MALLOC_SMALL) {
+      types.push_back("malloc-small");
+    }
+  }
+  return types;
+}
Index: lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp
===================================================================
--- lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp
+++ lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp
@@ -125,6 +125,7 @@
     region_info->permissions = vmRegion.GetDNBPermissions();
     region_info->dirty_pages =
         get_dirty_pages(task, vmRegion.StartAddress(), vmRegion.GetByteSize());
+    region_info->vm_types = vmRegion.GetMemoryTypes();
   } else {
     region_info->addr = address;
     region_info->size = 0;
Index: lldb/tools/debugserver/source/DNBDefs.h
===================================================================
--- lldb/tools/debugserver/source/DNBDefs.h
+++ lldb/tools/debugserver/source/DNBDefs.h
@@ -16,6 +16,7 @@
 #include <csignal>
 #include <cstdint>
 #include <cstdio>
+#include <string>
 #include <sys/syslimits.h>
 #include <unistd.h>
 #include <vector>
@@ -318,11 +319,13 @@
 
 struct DNBRegionInfo {
 public:
-  DNBRegionInfo() : addr(0), size(0), permissions(0), dirty_pages() {}
+  DNBRegionInfo()
+      : addr(0), size(0), permissions(0), dirty_pages(), vm_types() {}
   nub_addr_t addr;
   nub_addr_t size;
   uint32_t permissions;
   std::vector<nub_addr_t> dirty_pages;
+  std::vector<std::string> vm_types;
 };
 
 enum DNBProfileDataScanType {
Index: lldb/test/API/macosx/stack-corefile/main.c
===================================================================
--- /dev/null
+++ lldb/test/API/macosx/stack-corefile/main.c
@@ -0,0 +1,15 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+int main() {
+  int stack_int = 5;
+  int *heap_int = (int*) malloc(sizeof (int));
+  *heap_int = 10;
+
+  char stack_str[80];
+  strcpy (stack_str, "stack string");
+  char *heap_str = (char*) malloc(80);
+  strcpy (heap_str, "heap string");
+
+  return stack_int; // break here;
+}
Index: lldb/test/API/macosx/stack-corefile/TestStackCorefile.py
===================================================================
--- /dev/null
+++ lldb/test/API/macosx/stack-corefile/TestStackCorefile.py
@@ -0,0 +1,69 @@
+"""Test that lldb can create a stack-only corefile, and load the main binary."""
+
+import os
+import re
+import subprocess
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+class TestStackCorefile(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    @no_debug_info_test
+    @skipUnlessDarwin
+    def test(self):
+
+        corefile = self.getBuildArtifact("process.core")
+        self.build()
+        (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
+            self, "// break here", lldb.SBFileSpec("main.c"))
+
+        frame = thread.GetFrameAtIndex(0)
+        stack_int = frame.GetValueForVariablePath("stack_int")
+        heap_int = frame.GetValueForVariablePath("*heap_int")
+        stack_str = frame.GetValueForVariablePath("stack_str")
+        heap_str = frame.GetValueForVariablePath("heap_str")
+        self.assertEqual(stack_int.GetValueAsUnsigned(), 5)
+        self.assertEqual(heap_int.GetValueAsUnsigned(), 10)
+        self.assertEqual(stack_str.summary, '"stack string"')
+        self.assertEqual(heap_str.summary, '"heap string"')
+
+        self.runCmd("process save-core -s stack " + corefile)
+        process.Kill()
+        self.dbg.DeleteTarget(target)
+
+        # Now load the corefile
+        target = self.dbg.CreateTarget('')
+        process = target.LoadCore(corefile)
+        thread = process.GetSelectedThread()
+        self.assertTrue(process.IsValid())
+        self.assertTrue(process.GetSelectedThread().IsValid())
+        if self.TraceOn():
+            self.runCmd("image list")
+            self.runCmd("bt")
+            self.runCmd("fr v")
+        num_modules = target.GetNumModules()
+        #  We should only have the a.out binary and possibly
+        # the libdyld.dylib.  Extra libraries loaded means 
+        # extra LC_NOTE and unnecessarily large corefile.
+        self.assertTrue(num_modules == 1 or num_modules == 2)
+
+        # The heap variables should be unavailable now.
+        frame = thread.GetFrameAtIndex(0)
+        stack_int = frame.GetValueForVariablePath("stack_int")
+        heap_int = frame.GetValueForVariablePath("*heap_int")
+        stack_str = frame.GetValueForVariablePath("stack_str")
+        heap_str = frame.GetValueForVariablePath("heap_str")
+
+        ## The heap SBValues both come back as IsValid()==true,
+        ## which I'm not so sure is a great/correct thing --
+        ## it hides the memory read error that actually happened,
+        ## and we don't have a real value.
+        self.assertEqual(stack_int.GetValueAsUnsigned(), 5)
+        self.assertEqual(heap_int.GetValueAsUnsigned(), 0)
+        self.assertEqual(stack_str.summary, '"stack string"')
+        self.assertEqual(heap_str.summary, '""')
Index: lldb/test/API/macosx/stack-corefile/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/macosx/stack-corefile/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES = main.c
+
+include Makefile.rules
Index: lldb/test/API/macosx/skinny-corefile/TestSkinnyCorefile.py
===================================================================
--- lldb/test/API/macosx/skinny-corefile/TestSkinnyCorefile.py
+++ lldb/test/API/macosx/skinny-corefile/TestSkinnyCorefile.py
@@ -12,7 +12,7 @@
 from lldbsuite.test import lldbutil
 
 
-class TestFirmwareCorefiles(TestBase):
+class TestSkinnyCorefile(TestBase):
 
     mydir = TestBase.compute_mydir(__file__)
 
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -1572,6 +1572,19 @@
               }
             }
           }
+        } 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;
Index: lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
===================================================================
--- lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
+++ lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
@@ -6342,13 +6342,17 @@
 // 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<std::string> executing_uuids;
   ThreadList &thread_list(process_sp->GetThreadList());
@@ -6363,10 +6367,12 @@
         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 @@
   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 @@
           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<std::vector<addr_t>> &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 @@
           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 @@
         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
Index: lldb/source/Commands/CommandObjectProcess.cpp
===================================================================
--- lldb/source/Commands/CommandObjectProcess.cpp
+++ lldb/source/Commands/CommandObjectProcess.cpp
@@ -1166,7 +1166,9 @@
 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 @@
         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"
Index: lldb/include/lldb/lldb-enumerations.h
===================================================================
--- lldb/include/lldb/lldb-enumerations.h
+++ lldb/include/lldb/lldb-enumerations.h
@@ -1137,6 +1137,7 @@
   eSaveCoreUnspecified = 0,
   eSaveCoreFull = 1,
   eSaveCoreDirtyOnly = 2,
+  eSaveCoreStackOnly = 3,
 };
 
 } // namespace lldb
Index: lldb/include/lldb/Target/MemoryRegionInfo.h
===================================================================
--- lldb/include/lldb/Target/MemoryRegionInfo.h
+++ lldb/include/lldb/Target/MemoryRegionInfo.h
@@ -28,10 +28,10 @@
   MemoryRegionInfo(RangeType range, OptionalBool read, OptionalBool write,
                    OptionalBool execute, OptionalBool mapped, ConstString name,
                    OptionalBool flash, lldb::offset_t blocksize,
-                   OptionalBool memory_tagged)
+                   OptionalBool memory_tagged, OptionalBool stack_memory)
       : m_range(range), m_read(read), m_write(write), m_execute(execute),
         m_mapped(mapped), m_name(name), m_flash(flash), m_blocksize(blocksize),
-        m_memory_tagged(memory_tagged) {}
+        m_memory_tagged(memory_tagged), m_is_stack_memory(stack_memory) {}
 
   RangeType &GetRange() { return m_range; }
 
@@ -98,7 +98,8 @@
            m_mapped == rhs.m_mapped && m_name == rhs.m_name &&
            m_flash == rhs.m_flash && m_blocksize == rhs.m_blocksize &&
            m_memory_tagged == rhs.m_memory_tagged &&
-           m_pagesize == rhs.m_pagesize;
+           m_pagesize == rhs.m_pagesize &&
+           m_is_stack_memory == rhs.m_is_stack_memory;
   }
 
   bool operator!=(const MemoryRegionInfo &rhs) const { return !(*this == rhs); }
@@ -116,6 +117,10 @@
     return m_dirty_pages;
   }
 
+  OptionalBool IsStackMemory() const { return m_is_stack_memory; }
+
+  void SetIsStackMemory(OptionalBool val) { m_is_stack_memory = val; }
+
   void SetPageSize(int pagesize) { m_pagesize = pagesize; }
 
   void SetDirtyPageList(std::vector<lldb::addr_t> pagelist) {
@@ -134,6 +139,7 @@
   OptionalBool m_flash = eDontKnow;
   lldb::offset_t m_blocksize = 0;
   OptionalBool m_memory_tagged = eDontKnow;
+  OptionalBool m_is_stack_memory = eDontKnow;
   int m_pagesize = 0;
   llvm::Optional<std::vector<lldb::addr_t>> m_dirty_pages;
 };
Index: lldb/docs/lldb-gdb-remote.txt
===================================================================
--- lldb/docs/lldb-gdb-remote.txt
+++ lldb/docs/lldb-gdb-remote.txt
@@ -1206,6 +1206,9 @@
                           // is "mt" for AArch64 memory tagging. lldb will
                           // ignore any other flags in this field.
 
+    type:[<type>][,<type>]; // memory types that apply to this region, e.g.
+                 // "stack" for stack memory.
+
     error:<ascii-byte-error-string>; // where <ascii-byte-error-string> is
                                      // a hex encoded string value that
                                      // contains an error string
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to