xref: /llvm-project/lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py (revision fcd2d85cc9438ffe8e4a4948898077dfc253fe9d)
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    @skipIfAsan # rdar://85954489
108    def test_launch_scripted_process_stack_frames(self):
109        """Test that we can launch an lldb scripted process from the command
110        line, check its process ID and read string from memory."""
111        self.build()
112        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
113        self.assertTrue(target, VALID_TARGET)
114
115        for module in target.modules:
116            if 'a.out' in module.GetFileSpec().GetFilename():
117                main_module = module
118                break
119
120        self.assertTrue(main_module, "Invalid main module.")
121        error = target.SetModuleLoadAddress(main_module, 0)
122        self.assertTrue(error.Success(), "Reloading main module at offset 0 failed.")
123
124        os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1'
125        def cleanup():
126          del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"]
127        self.addTearDownHook(cleanup)
128
129        scripted_process_example_relpath = 'stack_core_scripted_process.py'
130        self.runCmd("command script import " + os.path.join(self.getSourceDir(),
131                                                            scripted_process_example_relpath))
132
133        corefile_process = None
134        with tempfile.NamedTemporaryFile() as file:
135            self.create_stack_skinny_corefile(file.name)
136            corefile_target = self.dbg.CreateTarget(None)
137            corefile_process = corefile_target.LoadCore(self.getBuildArtifact(file.name))
138        self.assertTrue(corefile_process, PROCESS_IS_VALID)
139
140        structured_data = lldb.SBStructuredData()
141        structured_data.SetFromJSON(json.dumps({
142            "backing_target_idx" : self.dbg.GetIndexOfTarget(corefile_process.GetTarget())
143        }))
144        launch_info = lldb.SBLaunchInfo(None)
145        launch_info.SetProcessPluginName("ScriptedProcess")
146        launch_info.SetScriptedProcessClassName("stack_core_scripted_process.StackCoreScriptedProcess")
147        launch_info.SetScriptedProcessDictionary(structured_data)
148
149        error = lldb.SBError()
150        process = target.Launch(launch_info, error)
151        self.assertTrue(error.Success(), error.GetCString())
152        self.assertTrue(process, PROCESS_IS_VALID)
153        self.assertEqual(process.GetProcessID(), 42)
154
155        self.assertEqual(process.GetNumThreads(), 1)
156        thread = process.GetSelectedThread()
157        self.assertTrue(thread, "Invalid thread.")
158        self.assertEqual(thread.GetName(), "StackCoreScriptedThread.thread-1")
159
160        self.assertEqual(thread.GetNumFrames(), 3)
161        frame = thread.GetSelectedFrame()
162        self.assertTrue(frame, "Invalid frame.")
163        self.assertEqual(frame.GetFunctionName(), "bar")
164        self.assertEqual(int(frame.FindValue("i", lldb.eValueTypeVariableArgument).GetValue()), 42)
165        self.assertEqual(int(frame.FindValue("j", lldb.eValueTypeVariableLocal).GetValue()), 42 * 42)
166