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