xref: /llvm-project/lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py (revision 419b4711961216b9c09d06735bb4d442a213fe57)
1"""
2Test python scripted process in lldb
3"""
4
5import os, json, tempfile
6
7import lldb
8from lldbsuite.test.decorators import *
9from lldbsuite.test.lldbtest import *
10from lldbsuite.test import lldbutil
11from lldbsuite.test import lldbtest
12
13class ScriptedProcesTestCase(TestBase):
14
15    mydir = TestBase.compute_mydir(__file__)
16
17    def setUp(self):
18        TestBase.setUp(self)
19
20    def tearDown(self):
21        TestBase.tearDown(self)
22
23    def test_python_plugin_package(self):
24        """Test that the lldb python module has a `plugins.scripted_process`
25        package."""
26        self.expect('script import lldb.plugins',
27                    substrs=["ModuleNotFoundError"], matching=False)
28
29        self.expect('script dir(lldb.plugins)',
30                    substrs=["scripted_process"])
31
32        self.expect('script import lldb.plugins.scripted_process',
33                    substrs=["ModuleNotFoundError"], matching=False)
34
35        self.expect('script dir(lldb.plugins.scripted_process)',
36                    substrs=["ScriptedProcess"])
37
38        self.expect('script from lldb.plugins.scripted_process import ScriptedProcess',
39                    substrs=["ImportError"], matching=False)
40
41        self.expect('script dir(ScriptedProcess)',
42                    substrs=["launch"])
43
44    @skipIf(archs=no_match(['x86_64']))
45    def test_scripted_process_and_scripted_thread(self):
46        """Test that we can launch an lldb scripted process using the SBAPI,
47        check its process ID, read string from memory, check scripted thread
48        id, name stop reason and register context.
49        """
50        self.build()
51        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
52        self.assertTrue(target, VALID_TARGET)
53
54        os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1'
55        def cleanup():
56          del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"]
57        self.addTearDownHook(cleanup)
58
59        scripted_process_example_relpath = 'dummy_scripted_process.py'
60        self.runCmd("command script import " + os.path.join(self.getSourceDir(),
61                                                            scripted_process_example_relpath))
62
63        launch_info = lldb.SBLaunchInfo(None)
64        launch_info.SetProcessPluginName("ScriptedProcess")
65        launch_info.SetScriptedProcessClassName("dummy_scripted_process.DummyScriptedProcess")
66
67        error = lldb.SBError()
68        process = target.Launch(launch_info, error)
69        self.assertTrue(process and process.IsValid(), PROCESS_IS_VALID)
70        self.assertEqual(process.GetProcessID(), 42)
71
72        self.assertEqual(process.GetNumThreads(), 1)
73
74        thread = process.GetSelectedThread()
75        self.assertTrue(thread, "Invalid thread.")
76        self.assertEqual(thread.GetThreadID(), 0x19)
77        self.assertEqual(thread.GetName(), "DummyScriptedThread.thread-1")
78        self.assertEqual(thread.GetStopReason(), lldb.eStopReasonSignal)
79
80        self.assertGreater(thread.GetNumFrames(), 0)
81
82        frame = thread.GetFrameAtIndex(0)
83        GPRs = None
84        register_set = frame.registers # Returns an SBValueList.
85        for regs in register_set:
86            if 'general purpose' in regs.name.lower():
87                GPRs = regs
88                break
89
90        self.assertTrue(GPRs, "Invalid General Purpose Registers Set")
91        self.assertEqual(GPRs.GetNumChildren(), 21)
92        for idx, reg in enumerate(GPRs, start=1):
93            self.assertEqual(idx, int(reg.value, 16))
94
95    def create_stack_skinny_corefile(self, file):
96        self.build()
97        target, process, thread, _ = lldbutil.run_to_source_breakpoint(self, "// break here", lldb.SBFileSpec("main.c"))
98        self.assertTrue(process.IsValid(), "Process is invalid.")
99        # FIXME: Use SBAPI to save the process corefile.
100        self.runCmd("process save-core -s stack  " + file)
101        self.assertTrue(os.path.exists(file), "No stack-only corefile found.")
102        self.assertTrue(self.dbg.DeleteTarget(target), "Couldn't delete target")
103
104    @skipUnlessDarwin
105    @skipIfOutOfTreeDebugserver
106    @skipIf(archs=no_match(['x86_64']))
107    def test_launch_scripted_process_stack_frames(self):
108        """Test that we can launch an lldb scripted process from the command
109        line, check its process ID and read string from memory."""
110        self.build()
111        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
112        self.assertTrue(target, VALID_TARGET)
113
114        for module in target.modules:
115            if 'a.out' in module.GetFileSpec().GetFilename():
116                main_module = module
117                break
118
119        self.assertTrue(main_module, "Invalid main module.")
120        error = target.SetModuleLoadAddress(main_module, 0)
121        self.assertTrue(error.Success(), "Reloading main module at offset 0 failed.")
122
123        os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1'
124        def cleanup():
125          del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"]
126        self.addTearDownHook(cleanup)
127
128        scripted_process_example_relpath = 'stack_core_scripted_process.py'
129        self.runCmd("command script import " + os.path.join(self.getSourceDir(),
130                                                            scripted_process_example_relpath))
131
132        corefile_process = None
133        with tempfile.NamedTemporaryFile() as file:
134            self.create_stack_skinny_corefile(file.name)
135            corefile_target = self.dbg.CreateTarget(None)
136            corefile_process = corefile_target.LoadCore(self.getBuildArtifact(file.name))
137        self.assertTrue(corefile_process, PROCESS_IS_VALID)
138
139        structured_data = lldb.SBStructuredData()
140        structured_data.SetFromJSON(json.dumps({
141            "backing_target_idx" : self.dbg.GetIndexOfTarget(corefile_process.GetTarget())
142        }))
143        launch_info = lldb.SBLaunchInfo(None)
144        launch_info.SetProcessPluginName("ScriptedProcess")
145        launch_info.SetScriptedProcessClassName("stack_core_scripted_process.StackCoreScriptedProcess")
146        launch_info.SetScriptedProcessDictionary(structured_data)
147
148        error = lldb.SBError()
149        process = target.Launch(launch_info, error)
150        self.assertTrue(error.Success(), error.GetCString())
151        self.assertTrue(process, PROCESS_IS_VALID)
152        self.assertEqual(process.GetProcessID(), 42)
153
154        self.assertEqual(process.GetNumThreads(), 1)
155        thread = process.GetSelectedThread()
156        self.assertTrue(thread, "Invalid thread.")
157        self.assertEqual(thread.GetName(), "StackCoreScriptedThread.thread-1")
158
159        self.assertEqual(thread.GetNumFrames(), 3)
160        frame = thread.GetSelectedFrame()
161        self.assertTrue(frame, "Invalid frame.")
162        self.assertEqual(frame.GetFunctionName(), "bar")
163        self.assertEqual(int(frame.FindValue("i", lldb.eValueTypeVariableArgument).GetValue()), 42)
164        self.assertEqual(int(frame.FindValue("j", lldb.eValueTypeVariableLocal).GetValue()), 42 * 42)
165