Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
May 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions lldb/bindings/interface/SBSaveCoreOptionsDocstrings.i
Original file line number Diff line number Diff line change
Expand Up @@ -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;
13 changes: 13 additions & 0 deletions lldb/include/lldb/API/SBSaveCoreOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
2 changes: 2 additions & 0 deletions lldb/include/lldb/Symbol/SaveCoreOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ class SaveCoreOptions {

lldb_private::ThreadCollection::collection GetThreadsToSave() const;

llvm::Expected<uint64_t> GetCurrentSizeInBytes();

void Clear();

private:
Expand Down
14 changes: 14 additions & 0 deletions lldb/source/API/SBSaveCoreOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
21 changes: 21 additions & 0 deletions lldb/source/Symbol/SaveCoreOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Original file line number Diff line number Diff line change
Expand Up @@ -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 : ''
Loading