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