xref: /llvm-project/lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py (revision 995d556f427d2ac7d3d9f80041adc7c51e80308b)
1"""
2Test python scripted process in lldb
3"""
4
5import os, shutil
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    NO_DEBUG_INFO_TESTCASE = True
16
17    def test_python_plugin_package(self):
18        """Test that the lldb python module has a `plugins.scripted_process`
19        package."""
20        self.expect('script import lldb.plugins',
21                    substrs=["ModuleNotFoundError"], matching=False)
22
23        self.expect('script dir(lldb.plugins)',
24                    substrs=["scripted_process"])
25
26        self.expect('script import lldb.plugins.scripted_process',
27                    substrs=["ModuleNotFoundError"], matching=False)
28
29        self.expect('script dir(lldb.plugins.scripted_process)',
30                    substrs=["ScriptedProcess"])
31
32        self.expect('script from lldb.plugins.scripted_process import ScriptedProcess',
33                    substrs=["ImportError"], matching=False)
34
35        self.expect('script dir(ScriptedProcess)',
36                    substrs=["launch"])
37
38    def move_blueprint_to_dsym(self, blueprint_name):
39        blueprint_origin_path = os.path.join(self.getSourceDir(), blueprint_name)
40        dsym_bundle = self.getBuildArtifact("a.out.dSYM")
41        blueprint_destination_path = os.path.join(dsym_bundle, "Contents",
42                                                  "Resources", "Python")
43        if not os.path.exists(blueprint_destination_path):
44            os.mkdir(blueprint_destination_path)
45
46        blueprint_destination_path = os.path.join(blueprint_destination_path, "a_out.py")
47        shutil.copy(blueprint_origin_path, blueprint_destination_path)
48
49    @skipUnlessDarwin
50    def test_invalid_scripted_register_context(self):
51        """Test that we can launch an lldb scripted process with an invalid
52        Scripted Thread, with invalid register context."""
53        self.build()
54
55        os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1'
56        def cleanup():
57          del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"]
58        self.addTearDownHook(cleanup)
59
60        self.runCmd("settings set target.load-script-from-symbol-file true")
61        self.move_blueprint_to_dsym('invalid_scripted_process.py')
62        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
63        self.assertTrue(target, VALID_TARGET)
64        log_file = self.getBuildArtifact('thread.log')
65        self.runCmd("log enable lldb thread -f " + log_file)
66        self.assertTrue(os.path.isfile(log_file))
67
68        launch_info = lldb.SBLaunchInfo(None)
69        launch_info.SetProcessPluginName("ScriptedProcess")
70        launch_info.SetScriptedProcessClassName("a_out.InvalidScriptedProcess")
71        error = lldb.SBError()
72
73        process = target.Launch(launch_info, error)
74
75        self.assertSuccess(error)
76        self.assertTrue(process, PROCESS_IS_VALID)
77        self.assertEqual(process.GetProcessID(), 666)
78        self.assertEqual(process.GetNumThreads(), 0)
79
80        with open(log_file, 'r') as f:
81            log = f.read()
82
83        self.assertIn("Failed to get scripted thread registers data.", log)
84
85    @skipUnlessDarwin
86    def test_scripted_process_and_scripted_thread(self):
87        """Test that we can launch an lldb scripted process using the SBAPI,
88        check its process ID, read string from memory, check scripted thread
89        id, name stop reason and register context.
90        """
91        self.build()
92        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
93        self.assertTrue(target, VALID_TARGET)
94
95        os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1'
96        def cleanup():
97          del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"]
98        self.addTearDownHook(cleanup)
99
100        scripted_process_example_relpath = 'dummy_scripted_process.py'
101        self.runCmd("command script import " + os.path.join(self.getSourceDir(),
102                                                            scripted_process_example_relpath))
103
104        launch_info = lldb.SBLaunchInfo(None)
105        launch_info.SetProcessPluginName("ScriptedProcess")
106        launch_info.SetScriptedProcessClassName("dummy_scripted_process.DummyScriptedProcess")
107
108        error = lldb.SBError()
109        process = target.Launch(launch_info, error)
110        self.assertTrue(process and process.IsValid(), PROCESS_IS_VALID)
111        self.assertEqual(process.GetProcessID(), 42)
112
113        self.assertEqual(process.GetNumThreads(), 1)
114
115        thread = process.GetSelectedThread()
116        self.assertTrue(thread, "Invalid thread.")
117        self.assertEqual(thread.GetThreadID(), 0x19)
118        self.assertEqual(thread.GetName(), "DummyScriptedThread.thread-1")
119        self.assertStopReason(thread.GetStopReason(), lldb.eStopReasonSignal)
120
121        self.assertGreater(thread.GetNumFrames(), 0)
122
123        frame = thread.GetFrameAtIndex(0)
124        GPRs = None
125        register_set = frame.registers # Returns an SBValueList.
126        for regs in register_set:
127            if 'general purpose' in regs.name.lower():
128                GPRs = regs
129                break
130
131        self.assertTrue(GPRs, "Invalid General Purpose Registers Set")
132        self.assertGreater(GPRs.GetNumChildren(), 0)
133        for idx, reg in enumerate(GPRs, start=1):
134            if idx > 21:
135                break
136            self.assertEqual(idx, int(reg.value, 16))
137
138        self.assertTrue(frame.IsArtificial(), "Frame is not artificial")
139        pc = frame.GetPCAddress().GetLoadAddress(target)
140        self.assertEqual(pc, 0x0100001b00)
141