Author: Jacob Lalonde
Date: 2025-05-09T15:49:54-07:00
New Revision: 7517a1bb486f397d45a776e127445596e00c55eb

URL: 
https://github.com/llvm/llvm-project/commit/7517a1bb486f397d45a776e127445596e00c55eb
DIFF: 
https://github.com/llvm/llvm-project/commit/7517a1bb486f397d45a776e127445596e00c55eb.diff

LOG: [LLDB][SBSaveCoreOptions] Add new API to expose the expected core size in 
bytes (#138169)

My current internal work requires some sensitivity to IO usage. I had a
work around to calculate the expected size of a Minidump, but I've added
this PR so an automated system could look at the expected size of an
LLDB generated Minidump and then choose if it has the space or wants to
generate it.

There are some prerequisites to calculating the correct size, so I have
the API take a reference for an SBError, I originally tried to return an
SBError and instead take a uint64_t reference, but this made the API
very difficult to use in python.

Added a test case as well.

Added: 
    

Modified: 
    lldb/bindings/interface/SBSaveCoreOptionsDocstrings.i
    lldb/include/lldb/API/SBSaveCoreOptions.h
    lldb/include/lldb/Symbol/SaveCoreOptions.h
    lldb/source/API/SBSaveCoreOptions.cpp
    lldb/source/Symbol/SaveCoreOptions.cpp
    lldb/test/API/python_api/sbsavecoreoptions/TestSBSaveCoreOptions.py
    lldb/test/API/python_api/sbsavecoreoptions/basic_minidump.yaml

Removed: 
    


################################################################################
diff  --git a/lldb/bindings/interface/SBSaveCoreOptionsDocstrings.i 
b/lldb/bindings/interface/SBSaveCoreOptionsDocstrings.i
index 6efbe45d2d3ab..6907164a1b95c 100644
--- a/lldb/bindings/interface/SBSaveCoreOptionsDocstrings.i
+++ b/lldb/bindings/interface/SBSaveCoreOptionsDocstrings.i
@@ -63,6 +63,11 @@ Note that currently ELF Core files are not supported."
     Get an SBThreadCollection of all threads marked to be saved. This 
collection is not sorted according to insertion order."
 ) lldb::SBSaveCoreOptions::GetThreadsToSave;
 
+%feature("docstring", "
+    Get the current total number of bytes the core is expected to have, 
excluding the overhead of the core file format.
+    Requires both a Process and a Style to be specified. An error will be 
returned if the provided options would result in no data being saved."
+) lldb::SBSaveCoreOptions::GetCurrentSizeInBytes;
+
 %feature("docstring", "
     Unset all options."
 ) lldb::SBSaveCoreOptions::Clear;

diff  --git a/lldb/include/lldb/API/SBSaveCoreOptions.h 
b/lldb/include/lldb/API/SBSaveCoreOptions.h
index c6d2ab6099b3c..37552c13d0f36 100644
--- a/lldb/include/lldb/API/SBSaveCoreOptions.h
+++ b/lldb/include/lldb/API/SBSaveCoreOptions.h
@@ -119,6 +119,19 @@ class LLDB_API SBSaveCoreOptions {
   ///   an empty collection will be returned.
   SBThreadCollection GetThreadsToSave() const;
 
+  /// Get the current total number of bytes the core is expected to have
+  /// excluding the overhead of the core file format. Requires a Process and
+  /// Style to be specified.
+  ///
+  /// \note
+  ///   This can cause some modification of the underlying data store
+  ///   as regions with no permissions, or invalid permissions will be removed
+  ///   and stacks will be minified up to their stack pointer + the redzone.
+  ///
+  /// \returns
+  ///   The expected size of the data contained in the core in bytes.
+  uint64_t GetCurrentSizeInBytes(SBError &error);
+
   /// Reset all options.
   void Clear();
 

diff  --git a/lldb/include/lldb/Symbol/SaveCoreOptions.h 
b/lldb/include/lldb/Symbol/SaveCoreOptions.h
index bcf0087fbea5c..da66b184745db 100644
--- a/lldb/include/lldb/Symbol/SaveCoreOptions.h
+++ b/lldb/include/lldb/Symbol/SaveCoreOptions.h
@@ -49,6 +49,8 @@ class SaveCoreOptions {
 
   lldb_private::ThreadCollection::collection GetThreadsToSave() const;
 
+  llvm::Expected<uint64_t> GetCurrentSizeInBytes();
+
   void Clear();
 
 private:

diff  --git a/lldb/source/API/SBSaveCoreOptions.cpp 
b/lldb/source/API/SBSaveCoreOptions.cpp
index 35b9da569dfa1..e101f6a25783c 100644
--- a/lldb/source/API/SBSaveCoreOptions.cpp
+++ b/lldb/source/API/SBSaveCoreOptions.cpp
@@ -114,6 +114,20 @@ void SBSaveCoreOptions::Clear() {
   m_opaque_up->Clear();
 }
 
+uint64_t SBSaveCoreOptions::GetCurrentSizeInBytes(SBError &error) {
+  LLDB_INSTRUMENT_VA(this, error);
+  llvm::Expected<uint64_t> expected_bytes =
+      m_opaque_up->GetCurrentSizeInBytes();
+  if (!expected_bytes) {
+    error =
+        SBError(lldb_private::Status::FromError(expected_bytes.takeError()));
+    return 0;
+  }
+  // Clear the error, so if the clearer uses it we set it to success.
+  error.Clear();
+  return *expected_bytes;
+}
+
 lldb_private::SaveCoreOptions &SBSaveCoreOptions::ref() const {
   return *m_opaque_up.get();
 }

diff  --git a/lldb/source/Symbol/SaveCoreOptions.cpp 
b/lldb/source/Symbol/SaveCoreOptions.cpp
index c9f6efeb25d22..e51ae27954934 100644
--- a/lldb/source/Symbol/SaveCoreOptions.cpp
+++ b/lldb/source/Symbol/SaveCoreOptions.cpp
@@ -145,6 +145,27 @@ SaveCoreOptions::GetThreadsToSave() const {
   return thread_collection;
 }
 
+llvm::Expected<uint64_t> SaveCoreOptions::GetCurrentSizeInBytes() {
+  Status error;
+  if (!m_process_sp)
+    return Status::FromErrorString("Requires a process to be 
set.").takeError();
+
+  error = EnsureValidConfiguration(m_process_sp);
+  if (error.Fail())
+    return error.takeError();
+
+  CoreFileMemoryRanges ranges;
+  error = m_process_sp->CalculateCoreFileSaveRanges(*this, ranges);
+  if (error.Fail())
+    return error.takeError();
+
+  uint64_t total_in_bytes = 0;
+  for (auto &core_range : ranges)
+    total_in_bytes += core_range.data.range.size();
+
+  return total_in_bytes;
+}
+
 void SaveCoreOptions::ClearProcessSpecificData() {
   // Deliberately not following the formatter style here to indicate that
   // this method will be expanded in the future.

diff  --git 
a/lldb/test/API/python_api/sbsavecoreoptions/TestSBSaveCoreOptions.py 
b/lldb/test/API/python_api/sbsavecoreoptions/TestSBSaveCoreOptions.py
index ace84e8497a59..31e35e0285f17 100644
--- a/lldb/test/API/python_api/sbsavecoreoptions/TestSBSaveCoreOptions.py
+++ b/lldb/test/API/python_api/sbsavecoreoptions/TestSBSaveCoreOptions.py
@@ -104,3 +104,63 @@ def test_removing_and_adding_insertion_order(self):
         thread_collection = options.GetThreadsToSave()
         self.assertEqual(thread_collection.GetSize(), 3)
         self.assertIn(middle_thread, thread_collection)
+
+    def test_get_current_size_in_bytes(self):
+        """
+        Tests that ensures GetCurrentSizeInBytes properly returns an error 
without a process,
+        and the readable regions with a process.
+        """
+
+        options = lldb.SBSaveCoreOptions()
+        options.SetStyle(lldb.eSaveCoreCustomOnly)
+        process = self.get_basic_process()
+        memory_range = lldb.SBMemoryRegionInfo()
+
+        # Add the memory range of 0x1000-0x1100
+        process.GetMemoryRegionInfo(0x1000, memory_range)
+        options.AddMemoryRegionToSave(memory_range)
+
+        # Check that we fail when we have no process set
+        # even though we added a memory region.
+        error = lldb.SBError()
+        total = options.GetCurrentSizeInBytes(error)
+        self.assertTrue(error.Fail(), error.GetCString())
+
+        # Check that we don't get an error now that we've added a process
+        options.SetProcess(process)
+        total = options.GetCurrentSizeInBytes(error)
+        self.assertTrue(error.Success(), error.GetCString())
+
+        # Validate the size returned is the same size as the single region we 
added.
+        expected_size = memory_range.GetRegionEnd() - 
memory_range.GetRegionBase()
+        self.assertEqual(total, expected_size)
+
+    def test_get_total_in_bytes_missing_requirements(self):
+        """
+        Tests the matrix of error responses that GetCurrentSizeInBytes
+        """
+
+        options = lldb.SBSaveCoreOptions()
+
+        # No process, no style returns an error.
+        error = lldb.SBError()
+        total = options.GetCurrentSizeInBytes(error)
+        self.assertTrue(error.Fail(), error.GetCString())
+
+        # No process returns an error
+        options.SetStyle(lldb.eSaveCoreCustomOnly)
+        total = options.GetCurrentSizeInBytes(error)
+        self.assertTrue(error.Fail(), error.GetCString())
+
+        options.Clear()
+
+        # No style returns an error
+        process = self.get_basic_process()
+        options.SetProcess(process)
+        total = options.GetCurrentSizeInBytes(error)
+        self.assertTrue(error.Fail(), error.GetCString())
+
+        # Options that result in no valid data returns an error.
+        options.SetStyle(lldb.eSaveCoreCustomOnly)
+        total = options.GetCurrentSizeInBytes(error)
+        self.assertTrue(error.Fail(), error.GetCString())

diff  --git a/lldb/test/API/python_api/sbsavecoreoptions/basic_minidump.yaml 
b/lldb/test/API/python_api/sbsavecoreoptions/basic_minidump.yaml
index 96302fbfb6b5c..e79262b3a85ce 100644
--- a/lldb/test/API/python_api/sbsavecoreoptions/basic_minidump.yaml
+++ b/lldb/test/API/python_api/sbsavecoreoptions/basic_minidump.yaml
@@ -34,3 +34,11 @@ Streams:
         Stack:
           Start of Memory Range: 0x00007FFFC8DFF000
           Content:               'BAADBEEF'
+  - Type:            Memory64List
+    Memory Ranges:
+      - Start of Memory Range: 0x1000
+        Data Size:       0x100
+        Content :        ''
+      - Start of Memory Range: 0x2000
+        Data Size:       0x200
+        Content :        ''


        
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to