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