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