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 impl = process.GetScriptedImplementation() 84 self.assertTrue(impl) 85 impl = process.GetScriptedImplementation() 86 self.assertTrue(impl) 87 impl = process.GetScriptedImplementation() 88 self.assertTrue(impl) 89 impl = process.GetScriptedImplementation() 90 self.assertTrue(impl) 91 92 addr = 0x500000000 93 buff = process.ReadMemory(addr, 4, error) 94 self.assertEqual(buff, None) 95 self.assertTrue(error.Fail()) 96 self.assertEqual(error.GetCString(), "This is an invalid scripted process!") 97 98 with open(log_file, 'r') as f: 99 log = f.read() 100 101 self.assertIn("Failed to get scripted thread registers data.", log) 102 103 @skipUnlessDarwin 104 def test_scripted_process_and_scripted_thread(self): 105 """Test that we can launch an lldb scripted process using the SBAPI, 106 check its process ID, read string from memory, check scripted thread 107 id, name stop reason and register context. 108 """ 109 self.build() 110 target_0 = self.dbg.CreateTarget(self.getBuildArtifact("a.out")) 111 self.assertTrue(target_0, VALID_TARGET) 112 113 os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1' 114 def cleanup(): 115 del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"] 116 self.addTearDownHook(cleanup) 117 118 scripted_process_example_relpath = 'dummy_scripted_process.py' 119 self.runCmd("command script import " + os.path.join(self.getSourceDir(), 120 scripted_process_example_relpath)) 121 122 launch_info = lldb.SBLaunchInfo(None) 123 launch_info.SetProcessPluginName("ScriptedProcess") 124 launch_info.SetScriptedProcessClassName("dummy_scripted_process.DummyScriptedProcess") 125 126 error = lldb.SBError() 127 process_0 = target_0.Launch(launch_info, error) 128 self.assertTrue(process_0 and process_0.IsValid(), PROCESS_IS_VALID) 129 self.assertEqual(process_0.GetProcessID(), 42) 130 self.assertEqual(process_0.GetNumThreads(), 1) 131 132 py_impl = process_0.GetScriptedImplementation() 133 self.assertTrue(py_impl) 134 self.assertTrue(isinstance(py_impl, dummy_scripted_process.DummyScriptedProcess)) 135 self.assertFalse(hasattr(py_impl, 'my_super_secret_member')) 136 py_impl.my_super_secret_member = 42 137 self.assertTrue(hasattr(py_impl, 'my_super_secret_member')) 138 self.assertEqual(py_impl.my_super_secret_method(), 42) 139 140 # Try reading from target #0 process ... 141 addr = 0x500000000 142 message = "Hello, target 0" 143 buff = process_0.ReadCStringFromMemory(addr, len(message) + 1, error) 144 self.assertSuccess(error) 145 self.assertEqual(buff, message) 146 147 target_1 = self.dbg.CreateTarget(self.getBuildArtifact("a.out")) 148 self.assertTrue(target_1, VALID_TARGET) 149 150 # We still need to specify a PID when attaching even for scripted processes 151 attach_info = lldb.SBAttachInfo(42) 152 attach_info.SetProcessPluginName("ScriptedProcess") 153 attach_info.SetScriptedProcessClassName("dummy_scripted_process.DummyScriptedProcess") 154 155 error = lldb.SBError() 156 process_1 = target_1.Attach(attach_info, error) 157 self.assertTrue(process_1 and process_1.IsValid(), PROCESS_IS_VALID) 158 self.assertEqual(process_1.GetProcessID(), 42) 159 self.assertEqual(process_1.GetNumThreads(), 1) 160 161 # ... then try reading from target #1 process ... 162 message = "Hello, target 1" 163 buff = process_1.ReadCStringFromMemory(addr, len(message) + 1, error) 164 self.assertSuccess(error) 165 self.assertEqual(buff, message) 166 167 # ... now, reading again from target #0 process to make sure the call 168 # gets dispatched to the right target. 169 message = "Hello, target 0" 170 buff = process_0.ReadCStringFromMemory(addr, len(message) + 1, error) 171 self.assertSuccess(error) 172 self.assertEqual(buff, message) 173 174 # Let's write some memory. 175 message = "Hello, world!" 176 bytes_written = process_0.WriteMemoryAsCString(addr, message, error) 177 self.assertSuccess(error) 178 self.assertEqual(bytes_written, len(message) + 1) 179 180 # ... and check if that memory was saved properly. 181 buff = process_0.ReadCStringFromMemory(addr, len(message) + 1, error) 182 self.assertSuccess(error) 183 self.assertEqual(buff, message) 184 185 thread = process_0.GetSelectedThread() 186 self.assertTrue(thread, "Invalid thread.") 187 self.assertEqual(thread.GetThreadID(), 0x19) 188 self.assertEqual(thread.GetName(), "DummyScriptedThread.thread-1") 189 self.assertStopReason(thread.GetStopReason(), lldb.eStopReasonTrace) 190 191 self.assertGreater(thread.GetNumFrames(), 0) 192 193 frame = thread.GetFrameAtIndex(0) 194 GPRs = None 195 register_set = frame.registers # Returns an SBValueList. 196 for regs in register_set: 197 if 'general purpose' in regs.name.lower(): 198 GPRs = regs 199 break 200 201 self.assertTrue(GPRs, "Invalid General Purpose Registers Set") 202 self.assertGreater(GPRs.GetNumChildren(), 0) 203 for idx, reg in enumerate(GPRs, start=1): 204 if idx > 21: 205 break 206 self.assertEqual(idx, int(reg.value, 16)) 207 208 self.assertTrue(frame.IsArtificial(), "Frame is not artificial") 209 pc = frame.GetPCAddress().GetLoadAddress(target_0) 210 self.assertEqual(pc, 0x0100001b00) 211