582 lines · python
1"""2Test SBTarget APIs.3"""4 5import os6import lldb7from lldbsuite.test.decorators import *8from lldbsuite.test.lldbtest import *9from lldbsuite.test import lldbutil10 11 12class TargetAPITestCase(TestBase):13 def setUp(self):14 # Call super's setUp().15 TestBase.setUp(self)16 # Find the line number to of function 'c'.17 self.line1 = line_number(18 "main.c", "// Find the line number for breakpoint 1 here."19 )20 self.line2 = line_number(21 "main.c", "// Find the line number for breakpoint 2 here."22 )23 self.line_main = line_number("main.c", "// Set a break at entry to main.")24 25 # rdar://problem/970087326 # Find global variable value fails for dwarf if inferior not started27 # (Was CrashTracer: [USER] 1 crash in Python at _lldb.so: lldb_private::MemoryCache::Read + 94)28 #29 # It does not segfaults now. But for dwarf, the variable value is None if30 # the inferior process does not exist yet. The radar has been updated.31 def test_find_global_variables(self):32 """Exercise SBTarget.FindGlobalVariables() API."""33 d = {"EXE": "b.out"}34 self.build(dictionary=d)35 self.setTearDownCleanup(dictionary=d)36 self.find_global_variables("b.out")37 38 def test_find_compile_units(self):39 """Exercise SBTarget.FindCompileUnits() API."""40 d = {"EXE": "b.out"}41 self.build(dictionary=d)42 self.setTearDownCleanup(dictionary=d)43 self.find_compile_units(self.getBuildArtifact("b.out"))44 45 @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24778")46 def test_find_functions(self):47 """Exercise SBTarget.FindFunctions() API."""48 d = {"EXE": "b.out"}49 self.build(dictionary=d)50 self.setTearDownCleanup(dictionary=d)51 self.find_functions("b.out")52 53 def test_get_description(self):54 """Exercise SBTarget.GetDescription() API."""55 self.build()56 self.get_description()57 58 @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr21765")59 def test_resolve_symbol_context_with_address(self):60 """Exercise SBTarget.ResolveSymbolContextForAddress() API."""61 self.build()62 self.resolve_symbol_context_with_address()63 64 def test_get_platform(self):65 d = {"EXE": "b.out"}66 self.build(dictionary=d)67 self.setTearDownCleanup(dictionary=d)68 target = self.create_simple_target("b.out")69 platform = target.platform70 self.assertTrue(platform, VALID_PLATFORM)71 72 def test_get_data_byte_size(self):73 d = {"EXE": "b.out"}74 self.build(dictionary=d)75 self.setTearDownCleanup(dictionary=d)76 target = self.create_simple_target("b.out")77 self.assertEqual(target.data_byte_size, 1)78 79 def test_get_code_byte_size(self):80 d = {"EXE": "b.out"}81 self.build(dictionary=d)82 self.setTearDownCleanup(dictionary=d)83 target = self.create_simple_target("b.out")84 self.assertEqual(target.code_byte_size, 1)85 86 def test_resolve_file_address(self):87 d = {"EXE": "b.out"}88 self.build(dictionary=d)89 self.setTearDownCleanup(dictionary=d)90 target = self.create_simple_target("b.out")91 92 # find the file address in the .data section of the main93 # module94 data_section = self.find_data_section(target)95 data_section_addr = data_section.file_addr96 97 # resolve the above address, and compare the address produced98 # by the resolution against the original address/section99 res_file_addr = target.ResolveFileAddress(data_section_addr)100 self.assertTrue(res_file_addr.IsValid())101 102 self.assertEqual(data_section_addr, res_file_addr.file_addr)103 104 data_section2 = res_file_addr.section105 self.assertIsNotNone(data_section2)106 self.assertEqual(data_section.name, data_section2.name)107 108 def test_get_arch_name(self):109 d = {"EXE": "b.out"}110 self.build(dictionary=d)111 self.setTearDownCleanup(dictionary=d)112 target = self.create_simple_target("b.out")113 114 arch_name = target.arch_name115 self.assertTrue(len(arch_name) > 0, "Got an arch name")116 117 # Test consistency with triple.118 triple = target.triple119 self.assertTrue(len(triple) > 0, "Got a triple")120 self.assertEqual(121 triple.split("-")[0],122 arch_name,123 "Arch name is equal to the first item of the triple",124 )125 126 def test_get_ABIName(self):127 d = {"EXE": "b.out"}128 self.build(dictionary=d)129 self.setTearDownCleanup(dictionary=d)130 target = self.create_simple_target("b.out")131 132 abi_pre_launch = target.GetABIName()133 self.assertNotEqual(len(abi_pre_launch), 0, "Got an ABI string")134 135 breakpoint = target.BreakpointCreateByLocation("main.c", self.line_main)136 self.assertTrue(breakpoint, VALID_BREAKPOINT)137 138 # Put debugger into synchronous mode so when we target.LaunchSimple returns139 # it will guaranteed to be at the breakpoint140 self.dbg.SetAsync(False)141 142 # Launch the process, and do not stop at the entry point.143 process = target.LaunchSimple(None, None, self.get_process_working_directory())144 abi_after_launch = target.GetABIName()145 self.assertEqual(146 abi_pre_launch, abi_after_launch, "ABI's match before and during run"147 )148 149 def test_read_memory(self):150 d = {"EXE": "b.out"}151 self.build(dictionary=d)152 self.setTearDownCleanup(dictionary=d)153 target = self.create_simple_target("b.out")154 155 breakpoint = target.BreakpointCreateByLocation("main.c", self.line_main)156 self.assertTrue(breakpoint, VALID_BREAKPOINT)157 158 # Put debugger into synchronous mode so when we target.LaunchSimple returns159 # it will guaranteed to be at the breakpoint160 self.dbg.SetAsync(False)161 162 # Launch the process, and do not stop at the entry point.163 process = target.LaunchSimple(None, None, self.get_process_working_directory())164 165 # find the file address in the .data section of the main166 # module167 data_section = self.find_data_section(target)168 sb_addr = lldb.SBAddress(data_section, 0)169 error = lldb.SBError()170 content = target.ReadMemory(sb_addr, 1, error)171 self.assertSuccess(error, "Make sure memory read succeeded")172 self.assertEqual(len(content), 1)173 174 # Make sure reading from 0x0 fails175 sb_addr = lldb.SBAddress(0, target)176 self.assertIsNone(target.ReadMemory(sb_addr, 1, error))177 self.assertTrue(error.Fail())178 179 @skipIfWindows # stdio manipulation unsupported on Windows180 @skipIfRemote # stdio manipulation unsupported on remote iOS devices<rdar://problem/54581135>181 @skipIf(oslist=["linux"], archs=["arm$", "aarch64"])182 @no_debug_info_test183 def test_launch_simple(self):184 d = {"EXE": "b.out"}185 self.build(dictionary=d)186 self.setTearDownCleanup(dictionary=d)187 target = self.create_simple_target("b.out")188 189 # Set the debugger to synchronous mode so we only continue after the190 # process has exited.191 self.dbg.SetAsync(False)192 193 process = target.LaunchSimple(194 ["foo", "bar"], ["baz"], self.get_process_working_directory()195 )196 process.Continue()197 self.assertState(process.GetState(), lldb.eStateExited)198 output = process.GetSTDOUT(9999)199 self.assertIn("arg: foo", output)200 self.assertIn("arg: bar", output)201 self.assertIn("env: baz", output)202 203 self.runCmd("setting set target.run-args foo")204 self.runCmd("setting set target.env-vars bar=baz")205 process = target.LaunchSimple(None, None, self.get_process_working_directory())206 process.Continue()207 self.assertState(process.GetState(), lldb.eStateExited)208 output = process.GetSTDOUT(9999)209 self.assertIn("arg: foo", output)210 self.assertIn("env: bar=baz", output)211 212 # Clear all the run args set above.213 self.runCmd("setting clear target.run-args")214 process = target.LaunchSimple(None, None, self.get_process_working_directory())215 process.Continue()216 self.assertEqual(process.GetState(), lldb.eStateExited)217 output = process.GetSTDOUT(9999)218 self.assertNotIn("arg: foo", output)219 220 self.runCmd("settings set target.disable-stdio true")221 process = target.LaunchSimple(None, None, self.get_process_working_directory())222 process.Continue()223 self.assertState(process.GetState(), lldb.eStateExited)224 output = process.GetSTDOUT(9999)225 self.assertEqual(output, "")226 227 def create_simple_target(self, fn):228 exe = self.getBuildArtifact(fn)229 target = self.dbg.CreateTarget(exe)230 self.assertTrue(target, VALID_TARGET)231 return target232 233 def find_data_section(self, target):234 mod = target.GetModuleAtIndex(0)235 data_section = None236 for s in mod.sections:237 sect_type = s.GetSectionType()238 if sect_type == lldb.eSectionTypeData:239 data_section = s240 break241 elif sect_type == lldb.eSectionTypeContainer:242 for i in range(s.GetNumSubSections()):243 ss = s.GetSubSectionAtIndex(i)244 sect_type = ss.GetSectionType()245 if sect_type == lldb.eSectionTypeData:246 data_section = ss247 break248 249 self.assertIsNotNone(data_section)250 return data_section251 252 def find_global_variables(self, exe_name):253 """Exercise SBTarget.FindGlobalVariables() API."""254 exe = self.getBuildArtifact(exe_name)255 256 # Create a target by the debugger.257 target = self.dbg.CreateTarget(exe)258 self.assertTrue(target, VALID_TARGET)259 260 # rdar://problem/9700873261 # Find global variable value fails for dwarf if inferior not started262 # (Was CrashTracer: [USER] 1 crash in Python at _lldb.so: lldb_private::MemoryCache::Read + 94)263 #264 # Remove the lines to create a breakpoint and to start the inferior265 # which are workarounds for the dwarf case.266 267 breakpoint = target.BreakpointCreateByLocation("main.c", self.line1)268 self.assertTrue(breakpoint, VALID_BREAKPOINT)269 270 # Now launch the process, and do not stop at entry point.271 process = target.LaunchSimple(None, None, self.get_process_working_directory())272 self.assertTrue(process, PROCESS_IS_VALID)273 # Make sure we hit our breakpoint:274 thread_list = lldbutil.get_threads_stopped_at_breakpoint(process, breakpoint)275 self.assertEqual(len(thread_list), 1)276 277 value_list = target.FindGlobalVariables("my_global_var_of_char_type", 3)278 self.assertEqual(value_list.GetSize(), 1)279 my_global_var = value_list.GetValueAtIndex(0)280 self.DebugSBValue(my_global_var)281 self.assertTrue(my_global_var)282 self.expect(283 my_global_var.GetName(), exe=False, startstr="my_global_var_of_char_type"284 )285 self.expect(my_global_var.GetTypeName(), exe=False, startstr="char")286 self.expect(my_global_var.GetValue(), exe=False, startstr="'X'")287 288 # While we are at it, let's also exercise the similar289 # SBModule.FindGlobalVariables() API.290 for m in target.module_iter():291 if (292 os.path.normpath(m.GetFileSpec().GetDirectory()) == self.getBuildDir()293 and m.GetFileSpec().GetFilename() == exe_name294 ):295 value_list = m.FindGlobalVariables(296 target, "my_global_var_of_char_type", 3297 )298 self.assertEqual(value_list.GetSize(), 1)299 self.assertEqual(value_list.GetValueAtIndex(0).GetValue(), "'X'")300 break301 302 def find_compile_units(self, exe):303 """Exercise SBTarget.FindCompileUnits() API."""304 source_name = "main.c"305 306 # Create a target by the debugger.307 target = self.dbg.CreateTarget(exe)308 self.assertTrue(target, VALID_TARGET)309 310 list = target.FindCompileUnits(lldb.SBFileSpec(source_name, False))311 # Executable has been built just from one source file 'main.c',312 # so we may check only the first element of list.313 self.assertEqual(314 list[0].GetCompileUnit().GetFileSpec().GetFilename(), source_name315 )316 317 def find_functions(self, exe_name):318 """Exercise SBTarget.FindFunctions() API."""319 exe = self.getBuildArtifact(exe_name)320 321 # Create a target by the debugger.322 target = self.dbg.CreateTarget(exe)323 self.assertTrue(target, VALID_TARGET)324 325 # Try it with a null name:326 list = target.FindFunctions(None, lldb.eFunctionNameTypeAuto)327 self.assertEqual(list.GetSize(), 0)328 329 list = target.FindFunctions("c", lldb.eFunctionNameTypeAuto)330 self.assertEqual(list.GetSize(), 1)331 332 for sc in list:333 self.assertEqual(sc.GetModule().GetFileSpec().GetFilename(), exe_name)334 self.assertEqual(sc.GetSymbol().GetName(), "c")335 336 def get_description(self):337 """Exercise SBTarget.GetDescription() API."""338 exe = self.getBuildArtifact("a.out")339 340 # Create a target by the debugger.341 target = self.dbg.CreateTarget(exe)342 self.assertTrue(target, VALID_TARGET)343 344 from lldbsuite.test.lldbutil import get_description345 346 # get_description() allows no option to mean347 # lldb.eDescriptionLevelBrief.348 desc = get_description(target)349 # desc = get_description(target, option=lldb.eDescriptionLevelBrief)350 if not desc:351 self.fail("SBTarget.GetDescription() failed")352 self.expect(desc, exe=False, substrs=["a.out"])353 self.expect(354 desc, exe=False, matching=False, substrs=["Target", "Module", "Breakpoint"]355 )356 357 desc = get_description(target, option=lldb.eDescriptionLevelFull)358 if not desc:359 self.fail("SBTarget.GetDescription() failed")360 self.expect(361 desc, exe=False, substrs=["Target", "Module", "a.out", "Breakpoint"]362 )363 364 @skipIfRemote365 @no_debug_info_test366 def test_launch_new_process_and_redirect_stdout(self):367 """Exercise SBTarget.Launch() API with redirected stdout."""368 self.build()369 exe = self.getBuildArtifact("a.out")370 371 # Create a target by the debugger.372 target = self.dbg.CreateTarget(exe)373 self.assertTrue(target, VALID_TARGET)374 375 # Add an extra twist of stopping the inferior in a breakpoint, and then continue till it's done.376 # We should still see the entire stdout redirected once the process is377 # finished.378 line = line_number("main.c", "// a(3) -> c(3)")379 breakpoint = target.BreakpointCreateByLocation("main.c", line)380 381 # Now launch the process, do not stop at entry point, and redirect stdout to "stdout.txt" file.382 # The inferior should run to completion after "process.Continue()"383 # call.384 local_path = self.getBuildArtifact("stdout.txt")385 if os.path.exists(local_path):386 os.remove(local_path)387 388 if lldb.remote_platform:389 stdout_path = lldbutil.append_to_process_working_directory(390 self, "lldb-stdout-redirect.txt"391 )392 else:393 stdout_path = local_path394 error = lldb.SBError()395 process = target.Launch(396 self.dbg.GetListener(),397 None,398 None,399 None,400 stdout_path,401 None,402 None,403 0,404 False,405 error,406 )407 process.Continue()408 # self.runCmd("process status")409 if lldb.remote_platform:410 # copy output file to host411 lldb.remote_platform.Get(412 lldb.SBFileSpec(stdout_path), lldb.SBFileSpec(local_path)413 )414 415 # The 'stdout.txt' file should now exist.416 self.assertTrue(417 os.path.isfile(local_path),418 "'stdout.txt' exists due to redirected stdout via SBTarget.Launch() API.",419 )420 421 # Read the output file produced by running the program.422 with open(local_path, "r") as f:423 output = f.read()424 425 self.expect(output, exe=False, substrs=["a(1)", "b(2)", "a(3)"])426 427 def resolve_symbol_context_with_address(self):428 """Exercise SBTarget.ResolveSymbolContextForAddress() API."""429 exe = self.getBuildArtifact("a.out")430 431 # Create a target by the debugger.432 target = self.dbg.CreateTarget(exe)433 self.assertTrue(target, VALID_TARGET)434 435 # Now create the two breakpoints inside function 'a'.436 breakpoint1 = target.BreakpointCreateByLocation("main.c", self.line1)437 breakpoint2 = target.BreakpointCreateByLocation("main.c", self.line2)438 self.trace("breakpoint1:", breakpoint1)439 self.trace("breakpoint2:", breakpoint2)440 self.assertTrue(441 breakpoint1 and breakpoint1.GetNumLocations() == 1, VALID_BREAKPOINT442 )443 self.assertTrue(444 breakpoint2 and breakpoint2.GetNumLocations() == 1, VALID_BREAKPOINT445 )446 447 # Now launch the process, and do not stop at entry point.448 process = target.LaunchSimple(None, None, self.get_process_working_directory())449 self.assertTrue(process, PROCESS_IS_VALID)450 451 # Frame #0 should be on self.line1.452 self.assertState(process.GetState(), lldb.eStateStopped)453 thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint)454 self.assertTrue(455 thread.IsValid(),456 "There should be a thread stopped due to breakpoint condition",457 )458 # self.runCmd("process status")459 frame0 = thread.GetFrameAtIndex(0)460 lineEntry = frame0.GetLineEntry()461 self.assertEqual(lineEntry.GetLine(), self.line1)462 463 address1 = lineEntry.GetStartAddress()464 465 # Continue the inferior, the breakpoint 2 should be hit.466 process.Continue()467 self.assertState(process.GetState(), lldb.eStateStopped)468 thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint)469 self.assertTrue(470 thread.IsValid(),471 "There should be a thread stopped due to breakpoint condition",472 )473 # self.runCmd("process status")474 frame0 = thread.GetFrameAtIndex(0)475 lineEntry = frame0.GetLineEntry()476 self.assertEqual(lineEntry.GetLine(), self.line2)477 478 address2 = lineEntry.GetStartAddress()479 480 self.trace("address1:", address1)481 self.trace("address2:", address2)482 483 # Now call SBTarget.ResolveSymbolContextForAddress() with the addresses484 # from our line entry.485 context1 = target.ResolveSymbolContextForAddress(486 address1, lldb.eSymbolContextEverything487 )488 context2 = target.ResolveSymbolContextForAddress(489 address2, lldb.eSymbolContextEverything490 )491 492 self.assertTrue(context1 and context2)493 self.trace("context1:", context1)494 self.trace("context2:", context2)495 496 # Verify that the context point to the same function 'a'.497 symbol1 = context1.GetSymbol()498 symbol2 = context2.GetSymbol()499 self.assertTrue(symbol1 and symbol2)500 self.trace("symbol1:", symbol1)501 self.trace("symbol2:", symbol2)502 503 from lldbsuite.test.lldbutil import get_description504 505 desc1 = get_description(symbol1)506 desc2 = get_description(symbol2)507 self.assertTrue(508 desc1 and desc2 and desc1 == desc2,509 "The two addresses should resolve to the same symbol",510 )511 512 @skipIfRemote513 def test_default_arch(self):514 """Test the other two target create methods using LLDB_ARCH_DEFAULT."""515 self.build()516 exe = self.getBuildArtifact("a.out")517 target = self.dbg.CreateTargetWithFileAndArch(exe, lldb.LLDB_ARCH_DEFAULT)518 self.assertTrue(target.IsValid(), "Default arch made a valid target.")519 # This should also work with the target's triple:520 target2 = self.dbg.CreateTargetWithFileAndArch(exe, target.GetTriple())521 self.assertTrue(target2.IsValid(), "Round trip with triple works")522 # And this triple should work for the FileAndTriple API:523 target3 = self.dbg.CreateTargetWithFileAndTargetTriple(exe, target.GetTriple())524 self.assertTrue(target3.IsValid())525 526 @skipIfWindows527 def test_is_loaded(self):528 """Exercise SBTarget.IsLoaded(SBModule&) API."""529 d = {"EXE": "b.out"}530 self.build(dictionary=d)531 self.setTearDownCleanup(dictionary=d)532 target = self.create_simple_target("b.out")533 534 self.assertFalse(target.IsLoaded(lldb.SBModule()))535 536 num_modules = target.GetNumModules()537 for i in range(num_modules):538 module = target.GetModuleAtIndex(i)539 self.assertFalse(540 target.IsLoaded(module),541 "Target that isn't " "running shouldn't have any module loaded.",542 )543 544 process = target.LaunchSimple(None, None, self.get_process_working_directory())545 546 for i in range(num_modules):547 module = target.GetModuleAtIndex(i)548 self.assertTrue(549 target.IsLoaded(module),550 "Running the target should " "have loaded its modules.",551 )552 553 @no_debug_info_test554 def test_setting_selected_target_with_invalid_target(self):555 """Make sure we don't crash when trying to select invalid target."""556 target = lldb.SBTarget()557 self.dbg.SetSelectedTarget(target)558 559 @no_debug_info_test560 def test_get_api_mutex(self):561 """Make sure we can lock and unlock the API mutex from Python."""562 target = self.dbg.GetDummyTarget()563 564 mutex = target.GetAPIMutex()565 self.assertTrue(mutex.IsValid())566 mutex.lock()567 # The API call below doesn't actually matter, it's just there to568 # confirm we don't block on the API lock.569 target.BreakpointCreateByName("foo", "bar")570 mutex.unlock()571 572 @no_debug_info_test573 def test_get_api_mutex_with_statement(self):574 """Make sure we can lock and unlock the API mutex using a with-statement from Python."""575 target = self.dbg.GetDummyTarget()576 577 with target.GetAPIMutex() as mutex:578 self.assertTrue(mutex.IsValid())579 # The API call below doesn't actually matter, it's just there to580 # confirm we don't block on the API lock.581 target.BreakpointCreateByName("foo", "bar")582