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