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 13import dummy_scripted_process 14 15class ScriptedProcesTestCase(TestBase): 16 17 NO_DEBUG_INFO_TESTCASE = True 18 19 @skipUnlessDarwin 20 def test_python_plugin_package(self): 21 """Test that the lldb python module has a `plugins.scripted_process` 22 package.""" 23 self.expect('script import lldb.plugins', 24 substrs=["ModuleNotFoundError"], matching=False) 25 26 self.expect('script dir(lldb.plugins)', 27 substrs=["scripted_process"]) 28 29 self.expect('script import lldb.plugins.scripted_process', 30 substrs=["ModuleNotFoundError"], matching=False) 31 32 self.expect('script dir(lldb.plugins.scripted_process)', 33 substrs=["ScriptedProcess"]) 34 35 self.expect('script from lldb.plugins.scripted_process import ScriptedProcess', 36 substrs=["ImportError"], matching=False) 37 38 self.expect('script dir(ScriptedProcess)', 39 substrs=["launch"]) 40 41 def move_blueprint_to_dsym(self, blueprint_name): 42 blueprint_origin_path = os.path.join(self.getSourceDir(), blueprint_name) 43 dsym_bundle = self.getBuildArtifact("a.out.dSYM") 44 blueprint_destination_path = os.path.join(dsym_bundle, "Contents", 45 "Resources", "Python") 46 if not os.path.exists(blueprint_destination_path): 47 os.mkdir(blueprint_destination_path) 48 49 blueprint_destination_path = os.path.join(blueprint_destination_path, "a_out.py") 50 shutil.copy(blueprint_origin_path, blueprint_destination_path) 51 52 @skipUnlessDarwin 53 def test_invalid_scripted_register_context(self): 54 """Test that we can launch an lldb scripted process with an invalid 55 Scripted Thread, with invalid register context.""" 56 self.build() 57 58 os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1' 59 def cleanup(): 60 del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"] 61 self.addTearDownHook(cleanup) 62 63 self.runCmd("settings set target.load-script-from-symbol-file true") 64 self.move_blueprint_to_dsym('invalid_scripted_process.py') 65 target = self.dbg.CreateTarget(self.getBuildArtifact("a.out")) 66 self.assertTrue(target, VALID_TARGET) 67 log_file = self.getBuildArtifact('thread.log') 68 self.runCmd("log enable lldb thread -f " + log_file) 69 self.assertTrue(os.path.isfile(log_file)) 70 71 launch_info = lldb.SBLaunchInfo(None) 72 launch_info.SetProcessPluginName("ScriptedProcess") 73 launch_info.SetScriptedProcessClassName("a_out.InvalidScriptedProcess") 74 error = lldb.SBError() 75 76 process = target.Launch(launch_info, error) 77 78 self.assertSuccess(error) 79 self.assertTrue(process, PROCESS_IS_VALID) 80 self.assertEqual(process.GetProcessID(), 666) 81 self.assertEqual(process.GetNumThreads(), 0) 82 83 addr = 0x500000000 84 buff = process.ReadMemory(addr, 4, error) 85 self.assertEqual(buff, None) 86 self.assertTrue(error.Fail()) 87 self.assertEqual(error.GetCString(), "This is an invalid scripted process!") 88 89 with open(log_file, 'r') as f: 90 log = f.read() 91 92 self.assertIn("Failed to get scripted thread registers data.", log) 93 94 @skipUnlessDarwin 95 def test_scripted_process_and_scripted_thread(self): 96 """Test that we can launch an lldb scripted process using the SBAPI, 97 check its process ID, read string from memory, check scripted thread 98 id, name stop reason and register context. 99 """ 100 self.build() 101 target_0 = self.dbg.CreateTarget(self.getBuildArtifact("a.out")) 102 self.assertTrue(target_0, VALID_TARGET) 103 104 os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1' 105 def cleanup(): 106 del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"] 107 self.addTearDownHook(cleanup) 108 109 scripted_process_example_relpath = 'dummy_scripted_process.py' 110 self.runCmd("command script import " + os.path.join(self.getSourceDir(), 111 scripted_process_example_relpath)) 112 113 launch_info = lldb.SBLaunchInfo(None) 114 launch_info.SetProcessPluginName("ScriptedProcess") 115 launch_info.SetScriptedProcessClassName("dummy_scripted_process.DummyScriptedProcess") 116 117 error = lldb.SBError() 118 process_0 = target_0.Launch(launch_info, error) 119 self.assertTrue(process_0 and process_0.IsValid(), PROCESS_IS_VALID) 120 self.assertEqual(process_0.GetProcessID(), 42) 121 self.assertEqual(process_0.GetNumThreads(), 1) 122 123 py_impl = process_0.GetScriptedImplementation() 124 self.assertTrue(py_impl) 125 self.assertTrue(isinstance(py_impl, dummy_scripted_process.DummyScriptedProcess)) 126 self.assertFalse(hasattr(py_impl, 'my_super_secret_member')) 127 py_impl.my_super_secret_member = 42 128 self.assertTrue(hasattr(py_impl, 'my_super_secret_member')) 129 self.assertEqual(py_impl.my_super_secret_method(), 42) 130 131 # Try reading from target #0 process ... 132 addr = 0x500000000 133 message = "Hello, target 0" 134 buff = process_0.ReadCStringFromMemory(addr, len(message) + 1, error) 135 self.assertSuccess(error) 136 self.assertEqual(buff, message) 137 138 target_1 = self.dbg.CreateTarget(self.getBuildArtifact("a.out")) 139 self.assertTrue(target_1, VALID_TARGET) 140 141 # We still need to specify a PID when attaching even for scripted processes 142 attach_info = lldb.SBAttachInfo(42) 143 attach_info.SetProcessPluginName("ScriptedProcess") 144 attach_info.SetScriptedProcessClassName("dummy_scripted_process.DummyScriptedProcess") 145 146 error = lldb.SBError() 147 process_1 = target_1.Attach(attach_info, error) 148 self.assertTrue(process_1 and process_1.IsValid(), PROCESS_IS_VALID) 149 self.assertEqual(process_1.GetProcessID(), 42) 150 self.assertEqual(process_1.GetNumThreads(), 1) 151 152 # ... then try reading from target #1 process ... 153 addr = 0x500000000 154 message = "Hello, target 1" 155 buff = process_1.ReadCStringFromMemory(addr, len(message) + 1, error) 156 self.assertSuccess(error) 157 self.assertEqual(buff, message) 158 159 # ... now, reading again from target #0 process to make sure the call 160 # gets dispatched to the right target. 161 addr = 0x500000000 162 message = "Hello, target 0" 163 buff = process_0.ReadCStringFromMemory(addr, len(message) + 1, error) 164 self.assertSuccess(error) 165 self.assertEqual(buff, message) 166 167 thread = process_0.GetSelectedThread() 168 self.assertTrue(thread, "Invalid thread.") 169 self.assertEqual(thread.GetThreadID(), 0x19) 170 self.assertEqual(thread.GetName(), "DummyScriptedThread.thread-1") 171 self.assertStopReason(thread.GetStopReason(), lldb.eStopReasonSignal) 172 173 self.assertGreater(thread.GetNumFrames(), 0) 174 175 frame = thread.GetFrameAtIndex(0) 176 GPRs = None 177 register_set = frame.registers # Returns an SBValueList. 178 for regs in register_set: 179 if 'general purpose' in regs.name.lower(): 180 GPRs = regs 181 break 182 183 self.assertTrue(GPRs, "Invalid General Purpose Registers Set") 184 self.assertGreater(GPRs.GetNumChildren(), 0) 185 for idx, reg in enumerate(GPRs, start=1): 186 if idx > 21: 187 break 188 self.assertEqual(idx, int(reg.value, 16)) 189 190 self.assertTrue(frame.IsArtificial(), "Frame is not artificial") 191 pc = frame.GetPCAddress().GetLoadAddress(target_0) 192 self.assertEqual(pc, 0x0100001b00) 193