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