Skip to content

Commit 7517a1b

Browse files
authored
[LLDB][SBSaveCoreOptions] Add new API to expose the expected core size in bytes (llvm#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.
1 parent 0eae457 commit 7517a1b

File tree

7 files changed

+123
-0
lines changed

7 files changed

+123
-0
lines changed

lldb/bindings/interface/SBSaveCoreOptionsDocstrings.i

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ Note that currently ELF Core files are not supported."
6363
Get an SBThreadCollection of all threads marked to be saved. This collection is not sorted according to insertion order."
6464
) lldb::SBSaveCoreOptions::GetThreadsToSave;
6565

66+
%feature("docstring", "
67+
Get the current total number of bytes the core is expected to have, excluding the overhead of the core file format.
68+
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."
69+
) lldb::SBSaveCoreOptions::GetCurrentSizeInBytes;
70+
6671
%feature("docstring", "
6772
Unset all options."
6873
) lldb::SBSaveCoreOptions::Clear;

lldb/include/lldb/API/SBSaveCoreOptions.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,19 @@ class LLDB_API SBSaveCoreOptions {
119119
/// an empty collection will be returned.
120120
SBThreadCollection GetThreadsToSave() const;
121121

122+
/// Get the current total number of bytes the core is expected to have
123+
/// excluding the overhead of the core file format. Requires a Process and
124+
/// Style to be specified.
125+
///
126+
/// \note
127+
/// This can cause some modification of the underlying data store
128+
/// as regions with no permissions, or invalid permissions will be removed
129+
/// and stacks will be minified up to their stack pointer + the redzone.
130+
///
131+
/// \returns
132+
/// The expected size of the data contained in the core in bytes.
133+
uint64_t GetCurrentSizeInBytes(SBError &error);
134+
122135
/// Reset all options.
123136
void Clear();
124137

lldb/include/lldb/Symbol/SaveCoreOptions.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ class SaveCoreOptions {
4949

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

52+
llvm::Expected<uint64_t> GetCurrentSizeInBytes();
53+
5254
void Clear();
5355

5456
private:

lldb/source/API/SBSaveCoreOptions.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,20 @@ void SBSaveCoreOptions::Clear() {
114114
m_opaque_up->Clear();
115115
}
116116

117+
uint64_t SBSaveCoreOptions::GetCurrentSizeInBytes(SBError &error) {
118+
LLDB_INSTRUMENT_VA(this, error);
119+
llvm::Expected<uint64_t> expected_bytes =
120+
m_opaque_up->GetCurrentSizeInBytes();
121+
if (!expected_bytes) {
122+
error =
123+
SBError(lldb_private::Status::FromError(expected_bytes.takeError()));
124+
return 0;
125+
}
126+
// Clear the error, so if the clearer uses it we set it to success.
127+
error.Clear();
128+
return *expected_bytes;
129+
}
130+
117131
lldb_private::SaveCoreOptions &SBSaveCoreOptions::ref() const {
118132
return *m_opaque_up.get();
119133
}

lldb/source/Symbol/SaveCoreOptions.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,27 @@ SaveCoreOptions::GetThreadsToSave() const {
145145
return thread_collection;
146146
}
147147

148+
llvm::Expected<uint64_t> SaveCoreOptions::GetCurrentSizeInBytes() {
149+
Status error;
150+
if (!m_process_sp)
151+
return Status::FromErrorString("Requires a process to be set.").takeError();
152+
153+
error = EnsureValidConfiguration(m_process_sp);
154+
if (error.Fail())
155+
return error.takeError();
156+
157+
CoreFileMemoryRanges ranges;
158+
error = m_process_sp->CalculateCoreFileSaveRanges(*this, ranges);
159+
if (error.Fail())
160+
return error.takeError();
161+
162+
uint64_t total_in_bytes = 0;
163+
for (auto &core_range : ranges)
164+
total_in_bytes += core_range.data.range.size();
165+
166+
return total_in_bytes;
167+
}
168+
148169
void SaveCoreOptions::ClearProcessSpecificData() {
149170
// Deliberately not following the formatter style here to indicate that
150171
// this method will be expanded in the future.

lldb/test/API/python_api/sbsavecoreoptions/TestSBSaveCoreOptions.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,63 @@ def test_removing_and_adding_insertion_order(self):
104104
thread_collection = options.GetThreadsToSave()
105105
self.assertEqual(thread_collection.GetSize(), 3)
106106
self.assertIn(middle_thread, thread_collection)
107+
108+
def test_get_current_size_in_bytes(self):
109+
"""
110+
Tests that ensures GetCurrentSizeInBytes properly returns an error without a process,
111+
and the readable regions with a process.
112+
"""
113+
114+
options = lldb.SBSaveCoreOptions()
115+
options.SetStyle(lldb.eSaveCoreCustomOnly)
116+
process = self.get_basic_process()
117+
memory_range = lldb.SBMemoryRegionInfo()
118+
119+
# Add the memory range of 0x1000-0x1100
120+
process.GetMemoryRegionInfo(0x1000, memory_range)
121+
options.AddMemoryRegionToSave(memory_range)
122+
123+
# Check that we fail when we have no process set
124+
# even though we added a memory region.
125+
error = lldb.SBError()
126+
total = options.GetCurrentSizeInBytes(error)
127+
self.assertTrue(error.Fail(), error.GetCString())
128+
129+
# Check that we don't get an error now that we've added a process
130+
options.SetProcess(process)
131+
total = options.GetCurrentSizeInBytes(error)
132+
self.assertTrue(error.Success(), error.GetCString())
133+
134+
# Validate the size returned is the same size as the single region we added.
135+
expected_size = memory_range.GetRegionEnd() - memory_range.GetRegionBase()
136+
self.assertEqual(total, expected_size)
137+
138+
def test_get_total_in_bytes_missing_requirements(self):
139+
"""
140+
Tests the matrix of error responses that GetCurrentSizeInBytes
141+
"""
142+
143+
options = lldb.SBSaveCoreOptions()
144+
145+
# No process, no style returns an error.
146+
error = lldb.SBError()
147+
total = options.GetCurrentSizeInBytes(error)
148+
self.assertTrue(error.Fail(), error.GetCString())
149+
150+
# No process returns an error
151+
options.SetStyle(lldb.eSaveCoreCustomOnly)
152+
total = options.GetCurrentSizeInBytes(error)
153+
self.assertTrue(error.Fail(), error.GetCString())
154+
155+
options.Clear()
156+
157+
# No style returns an error
158+
process = self.get_basic_process()
159+
options.SetProcess(process)
160+
total = options.GetCurrentSizeInBytes(error)
161+
self.assertTrue(error.Fail(), error.GetCString())
162+
163+
# Options that result in no valid data returns an error.
164+
options.SetStyle(lldb.eSaveCoreCustomOnly)
165+
total = options.GetCurrentSizeInBytes(error)
166+
self.assertTrue(error.Fail(), error.GetCString())

lldb/test/API/python_api/sbsavecoreoptions/basic_minidump.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,11 @@ Streams:
3434
Stack:
3535
Start of Memory Range: 0x00007FFFC8DFF000
3636
Content: 'BAADBEEF'
37+
- Type: Memory64List
38+
Memory Ranges:
39+
- Start of Memory Range: 0x1000
40+
Data Size: 0x100
41+
Content : ''
42+
- Start of Memory Range: 0x2000
43+
Data Size: 0x200
44+
Content : ''

0 commit comments

Comments
 (0)