diff --git a/lldb/bindings/interface/SBSaveCoreOptionsExtensions.i b/lldb/bindings/interface/SBSaveCoreOptionsExtensions.i new file mode 100644 index 0000000000000..fb0dd5621c06d --- /dev/null +++ b/lldb/bindings/interface/SBSaveCoreOptionsExtensions.i @@ -0,0 +1,39 @@ + +%extend lldb::SBSaveCoreOptions { +#ifdef SWIGPYTHON + %pythoncode%{ + '''Add a thread to the SaveCoreOptions thread list, and follow its children N pointers deep, adding each memory region to the SaveCoreOptions Memory region list.''' + def save_thread_with_heaps(self, thread, num_pointers_deep = 3): + import lldb + self.AddThread(thread) + frame = thread.GetFrameAtIndex(0) + process = thread.GetProcess() + queue = [] + for var in frame.locals: + type = var.GetType() + if type.IsPointerType() or type.IsReferenceType(): + queue.append(var.Dereference()) + + while (num_pointers_deep > 0 and len(queue) > 0): + queue_size = len(queue) + for i in range(0, queue_size): + var = queue.pop(0) + var_type = var.GetType() + addr = var.GetAddress().GetOffset() + if addr == 0 or addr == None: + continue + memory_region = lldb.SBMemoryRegionInfo() + err = process.GetMemoryRegionInfo(addr, memory_region) + if err.Fail(): + continue + self.AddMemoryRegionToSave(memory_region) + # We only check for direct pointer children T*, should probably xscan + # internal to the children themselves. + for x in var.children: + if x.TypeIsPointerType(): + queue.append(x.Dereference()) + + num_pointers_deep -= 1 + %} +#endif +} diff --git a/lldb/bindings/interfaces.swig b/lldb/bindings/interfaces.swig index 8a6fed95f0b72..d8fbe522b610d 100644 --- a/lldb/bindings/interfaces.swig +++ b/lldb/bindings/interfaces.swig @@ -200,6 +200,7 @@ %include "./interface/SBProcessExtensions.i" %include "./interface/SBProcessInfoListExtensions.i" %include "./interface/SBQueueItemExtensions.i" +%include "./interface/SBSaveCoreOptionsExtensions.i" %include "./interface/SBScriptObjectExtensions.i" %include "./interface/SBSectionExtensions.i" %include "./interface/SBStreamExtensions.i" diff --git a/lldb/test/API/functionalities/process_save_core_minidump/Makefile b/lldb/test/API/functionalities/process_save_core_minidump/Makefile index 2d177981fdde1..84694117e0e3f 100644 --- a/lldb/test/API/functionalities/process_save_core_minidump/Makefile +++ b/lldb/test/API/functionalities/process_save_core_minidump/Makefile @@ -3,4 +3,3 @@ CXX_SOURCES := main.cpp CFLAGS_EXTRAS := -lpthread include Makefile.rules - diff --git a/lldb/test/API/functionalities/process_save_core_minidump/TestProcessSaveCoreMinidump.py b/lldb/test/API/functionalities/process_save_core_minidump/TestProcessSaveCoreMinidump.py index 03cc415924e0b..0ef845987ffe8 100644 --- a/lldb/test/API/functionalities/process_save_core_minidump/TestProcessSaveCoreMinidump.py +++ b/lldb/test/API/functionalities/process_save_core_minidump/TestProcessSaveCoreMinidump.py @@ -3,6 +3,7 @@ """ import os + import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * diff --git a/lldb/test/API/python_api/sbsavecoreoptions/Makefile b/lldb/test/API/python_api/sbsavecoreoptions/Makefile new file mode 100644 index 0000000000000..99998b20bcb05 --- /dev/null +++ b/lldb/test/API/python_api/sbsavecoreoptions/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/python_api/sbsavecoreoptions/TestSBSaveCoreOptions.py b/lldb/test/API/python_api/sbsavecoreoptions/TestSBSaveCoreOptions.py index 40d0cc7e96ff4..ed412f6cd9d0e 100644 --- a/lldb/test/API/python_api/sbsavecoreoptions/TestSBSaveCoreOptions.py +++ b/lldb/test/API/python_api/sbsavecoreoptions/TestSBSaveCoreOptions.py @@ -4,15 +4,18 @@ from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * + class SBSaveCoreOptionsAPICase(TestBase): basic_minidump = "basic_minidump.yaml" basic_minidump_different_pid = "basic_minidump_different_pid.yaml" def get_process_from_yaml(self, yaml_file): minidump_path = self.getBuildArtifact(os.path.basename(yaml_file) + ".dmp") - print ("minidump_path: " + minidump_path) + print("minidump_path: " + minidump_path) self.yaml2obj(yaml_file, minidump_path) - self.assertTrue(os.path.exists(minidump_path), "yaml2obj did not emit a minidump file") + self.assertTrue( + os.path.exists(minidump_path), "yaml2obj did not emit a minidump file" + ) target = self.dbg.CreateTarget(None) process = target.LoadCore(minidump_path) self.assertTrue(process.IsValid(), "Process is not valid") @@ -59,7 +62,6 @@ def test_adding_and_removing_thread(self): removed_success = options.RemoveThread(thread) self.assertFalse(removed_success) - def test_adding_thread_different_process(self): """Test adding and removing a thread from save core options.""" options = lldb.SBSaveCoreOptions() @@ -79,3 +81,43 @@ def test_adding_thread_different_process(self): self.assertTrue(error.Fail()) error = options.AddThread(thread) self.assertTrue(error.Success()) + + def verify_linked_list(self, node, depth, max_depth): + if depth > max_depth: + return + + x_val = node.GetChildMemberWithName("x").GetValueAsUnsigned(0) + self.assertEqual(x_val, depth) + next_node = node.GetChildMemberWithName("next").Dereference() + self.verify_linked_list(next_node, depth + 1, max_depth) + + @skipIfWindows + def test_thread_and_heaps_extension(self): + """Test the thread and heap extension for save core options.""" + options = lldb.SBSaveCoreOptions() + self.build() + (target, process, t, bp) = lldbutil.run_to_source_breakpoint( + self, "break here", lldb.SBFileSpec("a.out") + ) + main_thread = None + for thread_idx in range(process.GetNumThreads()): + thread = process.GetThreadAtIndex(thread_idx) + frame = thread.GetFrameAtIndex(0) + if "main" in frame.name: + main_thread = thread + break + self.assertTrue(main_thread != None) + options.save_thread_with_heaps(main_thread, 3) + core_file = self.getBuildArtifact("core.one_thread_and_heap.dmp") + spec = lldb.SBFileSpec(core_file) + options.SetOutputFile(spec) + options.SetPluginName("minidump") + options.SetStyle(lldb.eSaveCoreCustomOnly) + error = process.SaveCore(options) + self.assertTrue(error.Success()) + core_proc = target.LoadCore(core_file) + self.assertTrue(core_proc.IsValid()) + self.assertEqual(core_proc.GetNumThreads(), 1) + frame = core_proc.GetThreadAtIndex(0).GetFrameAtIndex(0) + head = frame.FindVariable("head") + self.verify_linked_list(head.Dereference(), 0, 3) diff --git a/lldb/test/API/python_api/sbsavecoreoptions/main.cpp b/lldb/test/API/python_api/sbsavecoreoptions/main.cpp new file mode 100644 index 0000000000000..12ccfd9600eac --- /dev/null +++ b/lldb/test/API/python_api/sbsavecoreoptions/main.cpp @@ -0,0 +1,20 @@ +#include + +struct Node { + Node *next; + int x; +}; + +int main() { + Node *head = new Node(); + Node *current = head; + head->x = 0; + for (size_t i = 0; i < 10; i++) { + Node *next = new Node(); + next->x = current->x + 1; + current->next = next; + current = next; + } + + return 0; // break here +}