[Lldb-commits] [lldb] 976867b - [lldb/test] Update TestScriptedProcess to use skinny corefiles

Med Ismail Bennani via lldb-commits lldb-commits at lists.llvm.org
Wed Nov 10 08:43:52 PST 2021


Author: Med Ismail Bennani
Date: 2021-11-10T17:43:29+01:00
New Revision: 976867b513abbf72e505506686219efaa7f3520f

URL: https://github.com/llvm/llvm-project/commit/976867b513abbf72e505506686219efaa7f3520f
DIFF: https://github.com/llvm/llvm-project/commit/976867b513abbf72e505506686219efaa7f3520f.diff

LOG: [lldb/test] Update TestScriptedProcess to use skinny corefiles

This patch changes the ScriptedProcess test to use a stack-only skinny
corefile as a backing store.

The corefile is saved as a temporary file at the beginning of the test,
and a second target is created for the ScriptedProcess. To do so, we use
the SBAPI from the ScriptedProcess' python script to interact with the
corefile process.

This patch also makes some small adjustments to the other ScriptedProcess
scripts to resolve some inconsistencies and removes the raw memory dump
that was previously checked in.

Differential Revision: https://reviews.llvm.org/D112047

Signed-off-by: Med Ismail Bennani <medismail.bennani at gmail.com>

Added: 
    lldb/test/API/functionalities/scripted_process/stack_core_scripted_process.py

Modified: 
    lldb/examples/python/scripted_process/my_scripted_process.py
    lldb/examples/python/scripted_process/scripted_process.py
    lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py

Removed: 
    lldb/examples/python/scripted_process/main.stack-dump


################################################################################
diff  --git a/lldb/examples/python/scripted_process/main.stack-dump b/lldb/examples/python/scripted_process/main.stack-dump
deleted file mode 100644
index 3df66384f4431..0000000000000
Binary files a/lldb/examples/python/scripted_process/main.stack-dump and /dev/null 
diff er

diff  --git a/lldb/examples/python/scripted_process/my_scripted_process.py b/lldb/examples/python/scripted_process/my_scripted_process.py
index 5e7c10b91533d..202ad097d4987 100644
--- a/lldb/examples/python/scripted_process/my_scripted_process.py
+++ b/lldb/examples/python/scripted_process/my_scripted_process.py
@@ -69,7 +69,7 @@ def get_scripted_thread_plugin(self):
 
 
 class MyScriptedThread(ScriptedThread):
-    registers = {
+    register_ctx = {
         "rax":0x00000000000006e4,
         "rbx":0x00000001040b6060,
         "rcx":0x00000001040b2e00,
@@ -123,7 +123,7 @@ def __init__(idx, cfa, pc, symbol_ctx):
         return self.frame_zero[0:0]
 
     def get_register_context(self) -> str:
-        return struct.pack("{}Q".format(len(self.registers)), *self.registers.values())
+        return struct.pack("{}Q".format(len(self.register_ctx)), *self.register_ctx.values())
 
 
 def __lldb_init_module(debugger, dict):

diff  --git a/lldb/examples/python/scripted_process/scripted_process.py b/lldb/examples/python/scripted_process/scripted_process.py
index 43ee2d6fffb27..ebb48523805d9 100644
--- a/lldb/examples/python/scripted_process/scripted_process.py
+++ b/lldb/examples/python/scripted_process/scripted_process.py
@@ -37,7 +37,7 @@ def __init__(self, target, args):
             self.args = args
 
     @abstractmethod
-    def get_memory_region_containing_address(addr):
+    def get_memory_region_containing_address(self, addr):
         """ Get the memory region for the scripted process, containing a
             specific address.
 
@@ -52,7 +52,7 @@ def get_memory_region_containing_address(addr):
         pass
 
     @abstractmethod
-    def get_thread_with_id(tid):
+    def get_thread_with_id(self, tid):
         """ Get the scripted process thread with a specific ID.
 
         Args:
@@ -66,7 +66,7 @@ def get_thread_with_id(tid):
         pass
 
     @abstractmethod
-    def get_registers_for_thread(tid):
+    def get_registers_for_thread(self, tid):
         """ Get the register context dictionary for a certain thread of
             the scripted process.
 
@@ -81,7 +81,7 @@ def get_registers_for_thread(tid):
         pass
 
     @abstractmethod
-    def read_memory_at_address(addr, size):
+    def read_memory_at_address(self, addr, size):
         """ Get a memory buffer from the scripted process at a certain address,
             of a certain size.
 
@@ -211,7 +211,7 @@ def __init__(self, process, args):
         self.state = None
         self.stop_reason = None
         self.register_info = None
-        self.register_ctx = []
+        self.register_ctx = {}
         self.frames = []
 
     @abstractmethod
@@ -294,7 +294,7 @@ def get_register_info(self):
             if triple:
                 arch = triple.split('-')[0]
                 if arch == 'x86_64':
-                    self.register_info['sets'] = ['GPR', 'FPU', 'EXC']
+                    self.register_info['sets'] = ['General Purpose Registers']
                     self.register_info['registers'] = [
                         {'name': 'rax', 'bitsize': 64, 'offset': 0, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 0, 'dwarf': 0},
                         {'name': 'rbx', 'bitsize': 64, 'offset': 8, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 3, 'dwarf': 3},

diff  --git a/lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py b/lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py
index 9f5b804d91a30..b8319d722e345 100644
--- a/lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py
+++ b/lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py
@@ -2,7 +2,7 @@
 Test python scripted process in lldb
 """
 
-import os
+import os, json, tempfile
 
 import lldb
 from lldbsuite.test.decorators import *
@@ -10,14 +10,12 @@
 from lldbsuite.test import lldbutil
 from lldbsuite.test import lldbtest
 
-
 class ScriptedProcesTestCase(TestBase):
 
     mydir = TestBase.compute_mydir(__file__)
 
     def setUp(self):
         TestBase.setUp(self)
-        self.source = "main.c"
 
     def tearDown(self):
         TestBase.tearDown(self)
@@ -43,7 +41,7 @@ def test_python_plugin_package(self):
         self.expect('script dir(ScriptedProcess)',
                     substrs=["launch"])
 
-    @skipIf(oslist=["linux"], archs=["arm", "aarch64"])
+    @skipIf(archs=no_match(['x86_64']))
     def test_scripted_process_and_scripted_thread(self):
         """Test that we can launch an lldb scripted process using the SBAPI,
         check its process ID, read string from memory, check scripted thread
@@ -78,19 +76,29 @@ def test_scripted_process_and_scripted_thread(self):
         self.assertGreater(thread.GetNumFrames(), 0)
 
         frame = thread.GetFrameAtIndex(0)
+        GPRs = None
         register_set = frame.registers # Returns an SBValueList.
         for regs in register_set:
-            if 'GPR' in regs.name:
-                registers  = regs
+            if 'general purpose' in regs.name.lower():
+                GPRs = regs
                 break
 
-        self.assertTrue(registers, "Invalid General Purpose Registers Set")
-        self.assertEqual(registers.GetNumChildren(), 21)
-        for idx, reg in enumerate(registers, start=1):
+        self.assertTrue(GPRs, "Invalid General Purpose Registers Set")
+        self.assertEqual(GPRs.GetNumChildren(), 21)
+        for idx, reg in enumerate(GPRs, start=1):
             self.assertEqual(idx, int(reg.value, 16))
 
-    @skipIfDarwin
+    def create_stack_skinny_corefile(self, file):
+        self.build()
+        target, process, thread, _ = lldbutil.run_to_source_breakpoint(self, "// break here", lldb.SBFileSpec("main.c"))
+        self.assertTrue(process.IsValid(), "Process is invalid.")
+        # FIXME: Use SBAPI to save the process corefile.
+        self.runCmd("process save-core -s stack  " + file)
+        self.assertTrue(os.path.exists(file), "No stack-only corefile found.")
+        self.assertTrue(self.dbg.DeleteTarget(target), "Couldn't delete target")
+
     @skipUnlessDarwin
+    @skipIf(archs=no_match(['x86_64']))
     def test_launch_scripted_process_stack_frames(self):
         """Test that we can launch an lldb scripted process from the command
         line, check its process ID and read string from memory."""
@@ -101,26 +109,45 @@ def test_launch_scripted_process_stack_frames(self):
         for module in target.modules:
             if 'a.out' in module.GetFileSpec().GetFilename():
                 main_module = module
+                break
 
         self.assertTrue(main_module, "Invalid main module.")
         error = target.SetModuleLoadAddress(main_module, 0)
         self.assertTrue(error.Success(), "Reloading main module at offset 0 failed.")
 
-        scripted_process_example_relpath = ['..','..','..','..','examples','python','scripted_process','my_scripted_process.py']
+        scripted_process_example_relpath = 'stack_core_scripted_process.py'
+        os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1'
         self.runCmd("command script import " + os.path.join(self.getSourceDir(),
-                                                            *scripted_process_example_relpath))
+                                                            scripted_process_example_relpath))
+
+        corefile_process = None
+        with tempfile.NamedTemporaryFile() as file:
+            self.create_stack_skinny_corefile(file.name)
+            corefile_target = self.dbg.CreateTarget(None)
+            corefile_process = corefile_target.LoadCore(self.getBuildArtifact(file.name))
+        self.assertTrue(corefile_process, PROCESS_IS_VALID)
+
+        structured_data = lldb.SBStructuredData()
+        structured_data.SetFromJSON(json.dumps({
+            "backing_target_idx" : self.dbg.GetIndexOfTarget(corefile_process.GetTarget())
+        }))
+        launch_info = lldb.SBLaunchInfo(None)
+        launch_info.SetProcessPluginName("ScriptedProcess")
+        launch_info.SetScriptedProcessClassName("stack_core_scripted_process.StackCoreScriptedProcess")
+        launch_info.SetScriptedProcessDictionary(structured_data)
 
-        process = target.GetProcess()
+        error = lldb.SBError()
+        process = target.Launch(launch_info, error)
+        self.assertTrue(error.Success(), error.GetCString())
         self.assertTrue(process, PROCESS_IS_VALID)
         self.assertEqual(process.GetProcessID(), 42)
-        self.assertEqual(process.GetNumThreads(), 1)
 
+        self.assertEqual(process.GetNumThreads(), 1)
         thread = process.GetSelectedThread()
         self.assertTrue(thread, "Invalid thread.")
-        self.assertEqual(thread.GetThreadID(), 0x19)
-        self.assertEqual(thread.GetName(), "MyScriptedThread.thread-1")
+        self.assertEqual(thread.GetName(), "StackCoreScriptedThread.thread-1")
 
-        self.assertEqual(thread.GetNumFrames(), 4)
+        self.assertEqual(thread.GetNumFrames(), 3)
         frame = thread.GetSelectedFrame()
         self.assertTrue(frame, "Invalid frame.")
         self.assertEqual(frame.GetFunctionName(), "bar")

diff  --git a/lldb/test/API/functionalities/scripted_process/stack_core_scripted_process.py b/lldb/test/API/functionalities/scripted_process/stack_core_scripted_process.py
new file mode 100644
index 0000000000000..7c3e069d22505
--- /dev/null
+++ b/lldb/test/API/functionalities/scripted_process/stack_core_scripted_process.py
@@ -0,0 +1,139 @@
+import os,struct,signal
+
+from typing import Any, Dict
+
+import lldb
+from lldb.plugins.scripted_process import ScriptedProcess
+from lldb.plugins.scripted_process import ScriptedThread
+
+class StackCoreScriptedProcess(ScriptedProcess):
+    def __init__(self, target: lldb.SBTarget, args : lldb.SBStructuredData):
+        super().__init__(target, args)
+
+        self.backing_target_idx = args.GetValueForKey("backing_target_idx")
+
+        self.corefile_target = None
+        self.corefile_process = None
+        if (self.backing_target_idx and self.backing_target_idx.IsValid()):
+            if self.backing_target_idx.GetType() == lldb.eStructuredDataTypeInteger:
+                idx = self.backing_target_idx.GetIntegerValue(42)
+            if self.backing_target_idx.GetType() == lldb.eStructuredDataTypeString:
+                idx = int(self.backing_target_idx.GetStringValue(100))
+            self.corefile_target = target.GetDebugger().GetTargetAtIndex(idx)
+            self.corefile_process = self.corefile_target.GetProcess()
+
+    def get_memory_region_containing_address(self, addr: int) -> lldb.SBMemoryRegionInfo:
+        mem_region = lldb.SBMemoryRegionInfo()
+        error = self.corefile_process.GetMemoryRegionInfo(addr, mem_region)
+        if error.Fail():
+            return None
+        return mem_region
+
+    def get_thread_with_id(self, tid: int):
+        return {}
+
+    def get_registers_for_thread(self, tid: int):
+        return {}
+
+    def read_memory_at_address(self, addr: int, size: int) -> lldb.SBData:
+        data = lldb.SBData()
+        error = lldb.SBError()
+        bytes_read = self.corefile_process.ReadMemory(addr, size, error)
+
+        if error.Fail():
+            return data
+
+        data.SetData(error, bytes_read, self.corefile_target.GetByteOrder(),
+                        self.corefile_target.GetAddressByteSize())
+
+        return data
+
+    def get_loaded_images(self):
+        # TODO: Iterate over corefile_target modules and build a data structure
+        # from it.
+        return self.loaded_images
+
+    def get_process_id(self) -> int:
+        return 42
+
+    def should_stop(self) -> bool:
+        return True
+
+    def is_alive(self) -> bool:
+        return True
+
+    def get_scripted_thread_plugin(self):
+        return StackCoreScriptedThread.__module__ + "." + StackCoreScriptedThread.__name__
+
+
+class StackCoreScriptedThread(ScriptedThread):
+    def __init__(self, process, args):
+        super().__init__(process, args)
+        self.backing_target_idx = args.GetValueForKey("backing_target_idx")
+
+        self.corefile_target = None
+        self.corefile_process = None
+        if (self.backing_target_idx and self.backing_target_idx.IsValid()):
+            if self.backing_target_idx.GetType() == lldb.eStructuredDataTypeInteger:
+                idx = self.backing_target_idx.GetIntegerValue(42)
+            if self.backing_target_idx.GetType() == lldb.eStructuredDataTypeString:
+                idx = int(self.backing_target_idx.GetStringValue(100))
+            self.corefile_target = self.target.GetDebugger().GetTargetAtIndex(idx)
+            self.corefile_process = self.corefile_target.GetProcess()
+
+    def get_thread_id(self) -> int:
+        return 0x19
+
+    def get_name(self) -> str:
+        return StackCoreScriptedThread.__name__ + ".thread-1"
+
+    def get_stop_reason(self) -> Dict[str, Any]:
+        return { "type": lldb.eStopReasonSignal, "data": {
+            "signal": signal.SIGINT
+        } }
+
+    def get_stackframes(self):
+        class ScriptedStackFrame:
+            def __init__(idx, cfa, pc, symbol_ctx):
+                self.idx = idx
+                self.cfa = cfa
+                self.pc = pc
+                self.symbol_ctx = symbol_ctx
+
+
+        symbol_ctx = lldb.SBSymbolContext()
+        frame_zero = ScriptedStackFrame(0, 0x42424242, 0x5000000, symbol_ctx)
+        self.frames.append(frame_zero)
+
+        return self.frame_zero[0:0]
+
+    def get_register_context(self) -> str:
+        thread = self.corefile_process.GetSelectedThread()
+        if not thread or thread.GetNumFrames() == 0:
+            return None
+        frame = thread.GetFrameAtIndex(0)
+
+        GPRs = None
+        registerSet = frame.registers # Returns an SBValueList.
+        for regs in registerSet:
+            if 'general purpose' in regs.name.lower():
+                GPRs = regs
+                break
+
+        if not GPRs:
+            return None
+
+        for reg in GPRs:
+            self.register_ctx[reg.name] = int(reg.value, base=16)
+
+        return struct.pack("{}Q".format(len(self.register_ctx)), *self.register_ctx.values())
+
+
+def __lldb_init_module(debugger, dict):
+    if not 'SKIP_SCRIPTED_PROCESS_LAUNCH' in os.environ:
+        debugger.HandleCommand(
+            "process launch -C %s.%s" % (__name__,
+                                     StackCoreScriptedProcess.__name__))
+    else:
+        print("Name of the class that will manage the scripted process: '%s.%s'"
+                % (__name__, StackCoreScriptedProcess.__name__))


        


More information about the lldb-commits mailing list