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