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