1""" 2Test SBProcess APIs, including ReadMemory(), WriteMemory(), and others. 3""" 4 5import lldb 6from lldbsuite.test.decorators import * 7from lldbsuite.test.lldbtest import * 8from lldbsuite.test.lldbutil import get_stopped_thread, state_type_to_str 9 10 11class ProcessAPITestCase(TestBase): 12 13 def setUp(self): 14 # Call super's setUp(). 15 TestBase.setUp(self) 16 # Find the line number to break inside main(). 17 self.line = line_number( 18 "main.cpp", 19 "// Set break point at this line and check variable 'my_char'.") 20 21 def test_scripted_implementation(self): 22 self.build() 23 exe = self.getBuildArtifact("a.out") 24 25 (target, process, _, _) = \ 26 lldbutil.run_to_source_breakpoint(self, "Set break point", 27 lldb.SBFileSpec("main.cpp")) 28 29 self.assertTrue(process, PROCESS_IS_VALID) 30 self.assertEqual(process.GetScriptedImplementation(), None) 31 32 33 def test_read_memory(self): 34 """Test Python SBProcess.ReadMemory() API.""" 35 self.build() 36 exe = self.getBuildArtifact("a.out") 37 38 target = self.dbg.CreateTarget(exe) 39 self.assertTrue(target, VALID_TARGET) 40 41 breakpoint = target.BreakpointCreateByLocation("main.cpp", self.line) 42 self.assertTrue(breakpoint, VALID_BREAKPOINT) 43 44 # Launch the process, and do not stop at the entry point. 45 process = target.LaunchSimple( 46 None, None, self.get_process_working_directory()) 47 48 thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint) 49 self.assertTrue( 50 thread.IsValid(), 51 "There should be a thread stopped due to breakpoint") 52 frame = thread.GetFrameAtIndex(0) 53 54 # Get the SBValue for the global variable 'my_char'. 55 val = frame.FindValue("my_char", lldb.eValueTypeVariableGlobal) 56 self.DebugSBValue(val) 57 58 # Due to the typemap magic (see lldb.swig), we pass in 1 to ReadMemory and 59 # expect to get a Python string as the result object! 60 error = lldb.SBError() 61 self.assertFalse(val.TypeIsPointerType()) 62 content = process.ReadMemory( 63 val.AddressOf().GetValueAsUnsigned(), 1, error) 64 if not error.Success(): 65 self.fail("SBProcess.ReadMemory() failed") 66 if self.TraceOn(): 67 print("memory content:", content) 68 69 self.expect( 70 content, 71 "Result from SBProcess.ReadMemory() matches our expected output: 'x'", 72 exe=False, 73 startstr=b'x') 74 75 # Read (char *)my_char_ptr. 76 val = frame.FindValue("my_char_ptr", lldb.eValueTypeVariableGlobal) 77 self.DebugSBValue(val) 78 cstring = process.ReadCStringFromMemory( 79 val.GetValueAsUnsigned(), 256, error) 80 if not error.Success(): 81 self.fail("SBProcess.ReadCStringFromMemory() failed") 82 if self.TraceOn(): 83 print("cstring read is:", cstring) 84 85 self.expect( 86 cstring, 87 "Result from SBProcess.ReadCStringFromMemory() matches our expected output", 88 exe=False, 89 startstr='Does it work?') 90 91 # Get the SBValue for the global variable 'my_cstring'. 92 val = frame.FindValue("my_cstring", lldb.eValueTypeVariableGlobal) 93 self.DebugSBValue(val) 94 95 # Due to the typemap magic (see lldb.swig), we pass in 256 to read at most 256 bytes 96 # from the address, and expect to get a Python string as the result 97 # object! 98 self.assertFalse(val.TypeIsPointerType()) 99 cstring = process.ReadCStringFromMemory( 100 val.AddressOf().GetValueAsUnsigned(), 256, error) 101 if not error.Success(): 102 self.fail("SBProcess.ReadCStringFromMemory() failed") 103 if self.TraceOn(): 104 print("cstring read is:", cstring) 105 106 self.expect( 107 cstring, 108 "Result from SBProcess.ReadCStringFromMemory() matches our expected output", 109 exe=False, 110 startstr='lldb.SBProcess.ReadCStringFromMemory() works!') 111 112 # Get the SBValue for the global variable 'my_uint32'. 113 val = frame.FindValue("my_uint32", lldb.eValueTypeVariableGlobal) 114 self.DebugSBValue(val) 115 116 # Due to the typemap magic (see lldb.swig), we pass in 4 to read 4 bytes 117 # from the address, and expect to get an int as the result! 118 self.assertFalse(val.TypeIsPointerType()) 119 my_uint32 = process.ReadUnsignedFromMemory( 120 val.AddressOf().GetValueAsUnsigned(), 4, error) 121 if not error.Success(): 122 self.fail("SBProcess.ReadCStringFromMemory() failed") 123 if self.TraceOn(): 124 print("uint32 read is:", my_uint32) 125 126 if my_uint32 != 12345: 127 self.fail( 128 "Result from SBProcess.ReadUnsignedFromMemory() does not match our expected output") 129 130 def test_write_memory(self): 131 """Test Python SBProcess.WriteMemory() API.""" 132 self.build() 133 exe = self.getBuildArtifact("a.out") 134 135 target = self.dbg.CreateTarget(exe) 136 self.assertTrue(target, VALID_TARGET) 137 138 breakpoint = target.BreakpointCreateByLocation("main.cpp", self.line) 139 self.assertTrue(breakpoint, VALID_BREAKPOINT) 140 141 # Launch the process, and do not stop at the entry point. 142 process = target.LaunchSimple( 143 None, None, self.get_process_working_directory()) 144 145 thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint) 146 self.assertTrue( 147 thread.IsValid(), 148 "There should be a thread stopped due to breakpoint") 149 frame = thread.GetFrameAtIndex(0) 150 151 # Get the SBValue for the global variable 'my_char'. 152 val = frame.FindValue("my_char", lldb.eValueTypeVariableGlobal) 153 self.DebugSBValue(val) 154 155 # If the variable does not have a load address, there's no sense 156 # continuing. 157 if not val.GetLocation().startswith("0x"): 158 return 159 160 # OK, let's get the hex location of the variable. 161 location = int(val.GetLocation(), 16) 162 163 # The program logic makes the 'my_char' variable to have memory content as 'x'. 164 # But we want to use the WriteMemory() API to assign 'a' to the 165 # variable. 166 167 # Now use WriteMemory() API to write 'a' into the global variable. 168 error = lldb.SBError() 169 result = process.WriteMemory(location, 'a', error) 170 if not error.Success() or result != 1: 171 self.fail("SBProcess.WriteMemory() failed") 172 173 # Read from the memory location. This time it should be 'a'. 174 # Due to the typemap magic (see lldb.swig), we pass in 1 to ReadMemory and 175 # expect to get a Python string as the result object! 176 content = process.ReadMemory(location, 1, error) 177 if not error.Success(): 178 self.fail("SBProcess.ReadMemory() failed") 179 if self.TraceOn(): 180 print("memory content:", content) 181 182 self.expect( 183 content, 184 "Result from SBProcess.ReadMemory() matches our expected output: 'a'", 185 exe=False, 186 startstr=b'a') 187 188 def test_access_my_int(self): 189 """Test access 'my_int' using Python SBProcess.GetByteOrder() and other APIs.""" 190 self.build() 191 exe = self.getBuildArtifact("a.out") 192 193 target = self.dbg.CreateTarget(exe) 194 self.assertTrue(target, VALID_TARGET) 195 196 breakpoint = target.BreakpointCreateByLocation("main.cpp", self.line) 197 self.assertTrue(breakpoint, VALID_BREAKPOINT) 198 199 # Launch the process, and do not stop at the entry point. 200 process = target.LaunchSimple( 201 None, None, self.get_process_working_directory()) 202 203 thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint) 204 self.assertTrue( 205 thread.IsValid(), 206 "There should be a thread stopped due to breakpoint") 207 frame = thread.GetFrameAtIndex(0) 208 209 # Get the SBValue for the global variable 'my_int'. 210 val = frame.FindValue("my_int", lldb.eValueTypeVariableGlobal) 211 self.DebugSBValue(val) 212 213 # If the variable does not have a load address, there's no sense 214 # continuing. 215 if not val.GetLocation().startswith("0x"): 216 return 217 218 # OK, let's get the hex location of the variable. 219 location = int(val.GetLocation(), 16) 220 221 # Note that the canonical from of the bytearray is little endian. 222 from lldbsuite.test.lldbutil import int_to_bytearray, bytearray_to_int 223 224 byteSize = val.GetByteSize() 225 bytes = int_to_bytearray(256, byteSize) 226 227 byteOrder = process.GetByteOrder() 228 if byteOrder == lldb.eByteOrderBig: 229 bytes.reverse() 230 elif byteOrder == lldb.eByteOrderLittle: 231 pass 232 else: 233 # Neither big endian nor little endian? Return for now. 234 # Add more logic here if we want to handle other types. 235 return 236 237 # The program logic makes the 'my_int' variable to have int type and value of 0. 238 # But we want to use the WriteMemory() API to assign 256 to the 239 # variable. 240 241 # Now use WriteMemory() API to write 256 into the global variable. 242 error = lldb.SBError() 243 result = process.WriteMemory(location, bytes, error) 244 if not error.Success() or result != byteSize: 245 self.fail("SBProcess.WriteMemory() failed") 246 247 # Make sure that the val we got originally updates itself to notice the 248 # change: 249 self.expect( 250 val.GetValue(), 251 "SBProcess.ReadMemory() successfully writes (int)256 to the memory location for 'my_int'", 252 exe=False, 253 startstr='256') 254 255 # And for grins, get the SBValue for the global variable 'my_int' 256 # again, to make sure that also tracks the new value: 257 val = frame.FindValue("my_int", lldb.eValueTypeVariableGlobal) 258 self.expect( 259 val.GetValue(), 260 "SBProcess.ReadMemory() successfully writes (int)256 to the memory location for 'my_int'", 261 exe=False, 262 startstr='256') 263 264 # Now read the memory content. The bytearray should have (byte)1 as 265 # the second element. 266 content = process.ReadMemory(location, byteSize, error) 267 if not error.Success(): 268 self.fail("SBProcess.ReadMemory() failed") 269 270 # The bytearray_to_int utility function expects a little endian 271 # bytearray. 272 if byteOrder == lldb.eByteOrderBig: 273 content = bytearray(content, 'ascii') 274 content.reverse() 275 276 new_value = bytearray_to_int(content, byteSize) 277 if new_value != 256: 278 self.fail("Memory content read from 'my_int' does not match (int)256") 279 280 # Dump the memory content.... 281 if self.TraceOn(): 282 for i in content: 283 print("byte:", i) 284 285 def test_remote_launch(self): 286 """Test SBProcess.RemoteLaunch() API with a process not in eStateConnected, and it should fail.""" 287 self.build() 288 exe = self.getBuildArtifact("a.out") 289 290 target = self.dbg.CreateTarget(exe) 291 self.assertTrue(target, VALID_TARGET) 292 293 # Launch the process, and do not stop at the entry point. 294 process = target.LaunchSimple( 295 None, None, self.get_process_working_directory()) 296 297 if self.TraceOn(): 298 print("process state:", state_type_to_str(process.GetState())) 299 self.assertTrue(process.GetState() != lldb.eStateConnected) 300 301 error = lldb.SBError() 302 success = process.RemoteLaunch( 303 None, None, None, None, None, None, 0, False, error) 304 self.assertTrue( 305 not success, 306 "RemoteLaunch() should fail for process state != eStateConnected") 307 308 def test_get_num_supported_hardware_watchpoints(self): 309 """Test SBProcess.GetNumSupportedHardwareWatchpoints() API with a process.""" 310 self.build() 311 exe = self.getBuildArtifact("a.out") 312 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 313 314 target = self.dbg.CreateTarget(exe) 315 self.assertTrue(target, VALID_TARGET) 316 317 breakpoint = target.BreakpointCreateByLocation("main.cpp", self.line) 318 self.assertTrue(breakpoint, VALID_BREAKPOINT) 319 320 # Launch the process, and do not stop at the entry point. 321 process = target.LaunchSimple( 322 None, None, self.get_process_working_directory()) 323 324 error = lldb.SBError() 325 num = process.GetNumSupportedHardwareWatchpoints(error) 326 if self.TraceOn() and error.Success(): 327 print("Number of supported hardware watchpoints: %d" % num) 328 329 @no_debug_info_test 330 @skipIfRemote 331 def test_get_process_info(self): 332 """Test SBProcess::GetProcessInfo() API with a locally launched process.""" 333 self.build() 334 exe = self.getBuildArtifact("a.out") 335 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 336 337 target = self.dbg.CreateTarget(exe) 338 self.assertTrue(target, VALID_TARGET) 339 340 # Launch the process and stop at the entry point. 341 launch_info = target.GetLaunchInfo() 342 launch_info.SetWorkingDirectory(self.get_process_working_directory()) 343 launch_flags = launch_info.GetLaunchFlags() 344 launch_flags |= lldb.eLaunchFlagStopAtEntry 345 launch_info.SetLaunchFlags(launch_flags) 346 error = lldb.SBError() 347 process = target.Launch(launch_info, error) 348 349 if not error.Success(): 350 self.fail("Failed to launch process") 351 352 # Verify basic process info can be retrieved successfully 353 process_info = process.GetProcessInfo() 354 self.assertTrue(process_info.IsValid()) 355 file_spec = process_info.GetExecutableFile() 356 self.assertTrue(file_spec.IsValid()) 357 process_name = process_info.GetName() 358 self.assertIsNotNone(process_name, "Process has a name") 359 self.assertGreater(len(process_name), 0, "Process name isn't blank") 360 self.assertEqual(file_spec.GetFilename(), "a.out") 361 self.assertNotEqual( 362 process_info.GetProcessID(), lldb.LLDB_INVALID_PROCESS_ID, 363 "Process ID is valid") 364 triple = process_info.GetTriple() 365 self.assertIsNotNone(triple, "Process has a triple") 366 367 # Additional process info varies by platform, so just check that 368 # whatever info was retrieved is consistent and nothing blows up. 369 if process_info.UserIDIsValid(): 370 self.assertNotEqual( 371 process_info.GetUserID(), lldb.UINT32_MAX, 372 "Process user ID is valid") 373 else: 374 self.assertEqual( 375 process_info.GetUserID(), lldb.UINT32_MAX, 376 "Process user ID is invalid") 377 378 if process_info.GroupIDIsValid(): 379 self.assertNotEqual( 380 process_info.GetGroupID(), lldb.UINT32_MAX, 381 "Process group ID is valid") 382 else: 383 self.assertEqual( 384 process_info.GetGroupID(), lldb.UINT32_MAX, 385 "Process group ID is invalid") 386 387 if process_info.EffectiveUserIDIsValid(): 388 self.assertNotEqual( 389 process_info.GetEffectiveUserID(), lldb.UINT32_MAX, 390 "Process effective user ID is valid") 391 else: 392 self.assertEqual( 393 process_info.GetEffectiveUserID(), lldb.UINT32_MAX, 394 "Process effective user ID is invalid") 395 396 if process_info.EffectiveGroupIDIsValid(): 397 self.assertNotEqual( 398 process_info.GetEffectiveGroupID(), lldb.UINT32_MAX, 399 "Process effective group ID is valid") 400 else: 401 self.assertEqual( 402 process_info.GetEffectiveGroupID(), lldb.UINT32_MAX, 403 "Process effective group ID is invalid") 404 405 process_info.GetParentProcessID() 406 407 def test_allocate_deallocate_memory(self): 408 """Test Python SBProcess.AllocateMemory() and SBProcess.DeallocateMemory() APIs.""" 409 self.build() 410 (target, process, main_thread, main_breakpoint) = lldbutil.run_to_source_breakpoint( 411 self, "// Set break point at this line", lldb.SBFileSpec("main.cpp")) 412 413 # Allocate a block of memory in the target process 414 error = lldb.SBError() 415 addr = process.AllocateMemory(16384, lldb.ePermissionsReadable, error) 416 if not error.Success() or addr == lldb.LLDB_INVALID_ADDRESS: 417 self.fail("SBProcess.AllocateMemory() failed") 418 419 # Now use WriteMemory() API to write 'a' into the allocated 420 # memory. Note that the debugger can do this even though the 421 # block is not set writable. 422 result = process.WriteMemory(addr, 'a', error) 423 if not error.Success() or result != 1: 424 self.fail("SBProcess.WriteMemory() failed") 425 426 # Read from the memory location. This time it should be 'a'. 427 # Due to the typemap magic (see lldb.swig), we pass in 1 to ReadMemory and 428 # expect to get a Python string as the result object! 429 content = process.ReadMemory(addr, 1, error) 430 if not error.Success(): 431 self.fail("SBProcess.ReadMemory() failed") 432 if self.TraceOn(): 433 print("memory content:", content) 434 435 self.expect( 436 content, 437 "Result from SBProcess.ReadMemory() matches our expected output: 'a'", 438 exe=False, 439 startstr=b'a') 440 441 # Verify that the process itself can read the allocated memory 442 frame = main_thread.GetFrameAtIndex(0) 443 val = frame.EvaluateExpression( 444 "test_read(reinterpret_cast<char *>({:#x}))".format(addr)) 445 self.expect(val.GetValue(), 446 "Result of test_read() matches expected output 'a'", 447 exe=False, 448 startstr="'a'") 449 450 # Verify that the process cannot write into the block 451 val = frame.EvaluateExpression( 452 "test_write(reinterpret_cast<char *>({:#x}), 'b')".format(addr)) 453 if val.GetError().Success(): 454 self.fail( 455 "test_write() to allocated memory without write permission unexpectedly succeeded") 456 457 # Deallocate the memory 458 error = process.DeallocateMemory(addr) 459 if not error.Success(): 460 self.fail("SBProcess.DeallocateMemory() failed") 461