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