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