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 def test_invalid_scripted_register_context(self): 45 """Test that we can launch an lldb scripted process with an invalid 46 Scripted Thread, with invalid register context.""" 47 self.build() 48 target = self.dbg.CreateTarget(self.getBuildArtifact("a.out")) 49 self.assertTrue(target, VALID_TARGET) 50 log_file = self.getBuildArtifact('thread.log') 51 self.runCmd("log enable lldb thread -f " + log_file) 52 self.assertTrue(os.path.isfile(log_file)) 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 = 'invalid_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("invalid_scripted_process.InvalidScriptedProcess") 66 error = lldb.SBError() 67 68 process = target.Launch(launch_info, error) 69 70 self.assertTrue(error.Success(), error.GetCString()) 71 self.assertTrue(process, PROCESS_IS_VALID) 72 self.assertEqual(process.GetProcessID(), 666) 73 self.assertEqual(process.GetNumThreads(), 0) 74 75 with open(log_file, 'r') as f: 76 log = f.read() 77 78 self.assertIn("Failed to get scripted thread registers data.", log) 79 80 @skipIf(archs=no_match(['x86_64'])) 81 def test_scripted_process_and_scripted_thread(self): 82 """Test that we can launch an lldb scripted process using the SBAPI, 83 check its process ID, read string from memory, check scripted thread 84 id, name stop reason and register context. 85 """ 86 self.build() 87 target = self.dbg.CreateTarget(self.getBuildArtifact("a.out")) 88 self.assertTrue(target, VALID_TARGET) 89 90 os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1' 91 def cleanup(): 92 del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"] 93 self.addTearDownHook(cleanup) 94 95 scripted_process_example_relpath = 'dummy_scripted_process.py' 96 self.runCmd("command script import " + os.path.join(self.getSourceDir(), 97 scripted_process_example_relpath)) 98 99 launch_info = lldb.SBLaunchInfo(None) 100 launch_info.SetProcessPluginName("ScriptedProcess") 101 launch_info.SetScriptedProcessClassName("dummy_scripted_process.DummyScriptedProcess") 102 103 error = lldb.SBError() 104 process = target.Launch(launch_info, error) 105 self.assertTrue(process and process.IsValid(), PROCESS_IS_VALID) 106 self.assertEqual(process.GetProcessID(), 42) 107 108 self.assertEqual(process.GetNumThreads(), 1) 109 110 thread = process.GetSelectedThread() 111 self.assertTrue(thread, "Invalid thread.") 112 self.assertEqual(thread.GetThreadID(), 0x19) 113 self.assertEqual(thread.GetName(), "DummyScriptedThread.thread-1") 114 self.assertEqual(thread.GetStopReason(), lldb.eStopReasonSignal) 115 116 self.assertGreater(thread.GetNumFrames(), 0) 117 118 frame = thread.GetFrameAtIndex(0) 119 GPRs = None 120 register_set = frame.registers # Returns an SBValueList. 121 for regs in register_set: 122 if 'general purpose' in regs.name.lower(): 123 GPRs = regs 124 break 125 126 self.assertTrue(GPRs, "Invalid General Purpose Registers Set") 127 self.assertEqual(GPRs.GetNumChildren(), 21) 128 for idx, reg in enumerate(GPRs, start=1): 129 self.assertEqual(idx, int(reg.value, 16)) 130 131 def create_stack_skinny_corefile(self, file): 132 self.build() 133 target, process, thread, _ = lldbutil.run_to_source_breakpoint(self, "// break here", lldb.SBFileSpec("main.c")) 134 self.assertTrue(process.IsValid(), "Process is invalid.") 135 # FIXME: Use SBAPI to save the process corefile. 136 self.runCmd("process save-core -s stack " + file) 137 self.assertTrue(os.path.exists(file), "No stack-only corefile found.") 138 self.assertTrue(self.dbg.DeleteTarget(target), "Couldn't delete target") 139 140 @skipUnlessDarwin 141 @skipIfOutOfTreeDebugserver 142 @skipIfAsan # rdar://85954489 143 def test_launch_scripted_process_stack_frames(self): 144 """Test that we can launch an lldb scripted process from the command 145 line, check its process ID and read string from memory.""" 146 self.build() 147 target = self.dbg.CreateTarget(self.getBuildArtifact("a.out")) 148 self.assertTrue(target, VALID_TARGET) 149 150 for module in target.modules: 151 if 'a.out' in module.GetFileSpec().GetFilename(): 152 main_module = module 153 break 154 155 self.assertTrue(main_module, "Invalid main module.") 156 error = target.SetModuleLoadAddress(main_module, 0) 157 self.assertTrue(error.Success(), "Reloading main module at offset 0 failed.") 158 159 os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1' 160 def cleanup(): 161 del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"] 162 self.addTearDownHook(cleanup) 163 164 scripted_process_example_relpath = 'stack_core_scripted_process.py' 165 self.runCmd("command script import " + os.path.join(self.getSourceDir(), 166 scripted_process_example_relpath)) 167 168 corefile_process = None 169 with tempfile.NamedTemporaryFile() as file: 170 self.create_stack_skinny_corefile(file.name) 171 corefile_target = self.dbg.CreateTarget(None) 172 corefile_process = corefile_target.LoadCore(self.getBuildArtifact(file.name)) 173 self.assertTrue(corefile_process, PROCESS_IS_VALID) 174 175 structured_data = lldb.SBStructuredData() 176 structured_data.SetFromJSON(json.dumps({ 177 "backing_target_idx" : self.dbg.GetIndexOfTarget(corefile_process.GetTarget()) 178 })) 179 launch_info = lldb.SBLaunchInfo(None) 180 launch_info.SetProcessPluginName("ScriptedProcess") 181 launch_info.SetScriptedProcessClassName("stack_core_scripted_process.StackCoreScriptedProcess") 182 launch_info.SetScriptedProcessDictionary(structured_data) 183 184 error = lldb.SBError() 185 process = target.Launch(launch_info, error) 186 self.assertTrue(error.Success(), error.GetCString()) 187 self.assertTrue(process, PROCESS_IS_VALID) 188 self.assertEqual(process.GetProcessID(), 42) 189 190 self.assertEqual(process.GetNumThreads(), 1) 191 thread = process.GetSelectedThread() 192 self.assertTrue(thread, "Invalid thread.") 193 self.assertEqual(thread.GetName(), "StackCoreScriptedThread.thread-1") 194 195 self.assertEqual(thread.GetNumFrames(), 3) 196 frame = thread.GetSelectedFrame() 197 self.assertTrue(frame, "Invalid frame.") 198 self.assertEqual(frame.GetFunctionName(), "bar") 199 self.assertEqual(int(frame.FindValue("i", lldb.eValueTypeVariableArgument).GetValue()), 42) 200 self.assertEqual(int(frame.FindValue("j", lldb.eValueTypeVariableLocal).GetValue()), 42 * 42) 201