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 @skipIf(archs=no_match(['arm64', 'arm64e'])) 146 @skipIfOutOfTreeDebugserver 147 def test_launch_scripted_process_stack_frames(self): 148 """Test that we can launch an lldb scripted process from the command 149 line, check its process ID and read string from memory.""" 150 self.build() 151 target = self.dbg.CreateTarget(self.getBuildArtifact("a.out")) 152 self.assertTrue(target, VALID_TARGET) 153 154 for module in target.modules: 155 if 'a.out' in module.GetFileSpec().GetFilename(): 156 main_module = module 157 break 158 159 self.assertTrue(main_module, "Invalid main module.") 160 error = target.SetModuleLoadAddress(main_module, 0) 161 self.assertTrue(error.Success(), "Reloading main module at offset 0 failed.") 162 163 os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1' 164 def cleanup(): 165 del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"] 166 self.addTearDownHook(cleanup) 167 168 scripted_process_example_relpath = 'stack_core_scripted_process.py' 169 self.runCmd("command script import " + os.path.join(self.getSourceDir(), 170 scripted_process_example_relpath)) 171 172 corefile_process = None 173 with tempfile.NamedTemporaryFile() as file: 174 self.create_stack_skinny_corefile(file.name) 175 corefile_target = self.dbg.CreateTarget(None) 176 corefile_process = corefile_target.LoadCore(self.getBuildArtifact(file.name)) 177 self.assertTrue(corefile_process, PROCESS_IS_VALID) 178 179 structured_data = lldb.SBStructuredData() 180 structured_data.SetFromJSON(json.dumps({ 181 "backing_target_idx" : self.dbg.GetIndexOfTarget(corefile_process.GetTarget()) 182 })) 183 launch_info = lldb.SBLaunchInfo(None) 184 launch_info.SetProcessPluginName("ScriptedProcess") 185 launch_info.SetScriptedProcessClassName("stack_core_scripted_process.StackCoreScriptedProcess") 186 launch_info.SetScriptedProcessDictionary(structured_data) 187 188 error = lldb.SBError() 189 process = target.Launch(launch_info, error) 190 self.assertTrue(error.Success(), error.GetCString()) 191 self.assertTrue(process, PROCESS_IS_VALID) 192 self.assertEqual(process.GetProcessID(), 42) 193 194 self.assertEqual(process.GetNumThreads(), 3) 195 thread = process.GetThreadAtIndex(2) 196 self.assertTrue(thread, "Invalid thread.") 197 self.assertEqual(thread.GetName(), "StackCoreScriptedThread.thread-2") 198 199 self.assertEqual(thread.GetNumFrames(), 6) 200 frame = thread.GetSelectedFrame() 201 self.assertTrue(frame, "Invalid frame.") 202 self.assertIn("bar", frame.GetFunctionName()) 203 self.assertEqual(int(frame.FindValue("i", lldb.eValueTypeVariableArgument).GetValue()), 42) 204 self.assertEqual(int(frame.FindValue("j", lldb.eValueTypeVariableLocal).GetValue()), 42 * 42) 205