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