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