1"""Test stepping and setting breakpoints in indirect and re-exported symbols.""" 2 3 4import lldb 5from lldbsuite.test.decorators import * 6from lldbsuite.test.lldbtest import * 7from lldbsuite.test import lldbutil 8 9 10class TestIndirectFunctions(TestBase): 11 def setUp(self): 12 # Call super's setUp(). 13 TestBase.setUp(self) 14 # Find the line numbers that we will step to in main: 15 self.main_source = "main.c" 16 17 @skipUnlessDarwin 18 @add_test_categories(["pyapi"]) 19 @skipIf(bugnumber="rdar://120796553") 20 def test_with_python_api(self): 21 """Test stepping and setting breakpoints in indirect and re-exported symbols.""" 22 self.build() 23 exe = self.getBuildArtifact("a.out") 24 25 target = self.dbg.CreateTarget(exe) 26 self.assertTrue(target, VALID_TARGET) 27 28 lib1 = self.getBuildArtifact("libindirect.dylib") 29 lib2 = self.getBuildArtifact("libreexport.dylib") 30 self.registerSharedLibrariesWithTarget(target, [lib1, lib2]) 31 32 self.main_source_spec = lldb.SBFileSpec(self.main_source) 33 34 break1 = target.BreakpointCreateBySourceRegex( 35 "Set breakpoint here to step in indirect.", self.main_source_spec 36 ) 37 self.assertTrue(break1, VALID_BREAKPOINT) 38 39 break2 = target.BreakpointCreateBySourceRegex( 40 "Set breakpoint here to step in reexported.", self.main_source_spec 41 ) 42 self.assertTrue(break2, VALID_BREAKPOINT) 43 44 # Now launch the process, and do not stop at entry point. 45 process = target.LaunchSimple(None, None, self.get_process_working_directory()) 46 47 self.assertTrue(process, PROCESS_IS_VALID) 48 49 # The stop reason of the thread should be breakpoint. 50 threads = lldbutil.get_threads_stopped_at_breakpoint(process, break1) 51 if len(threads) != 1: 52 self.fail("Failed to stop at breakpoint 1.") 53 54 thread = threads[0] 55 56 # Now do a step-into, and we should end up in the hidden target of this 57 # indirect function. 58 thread.StepInto() 59 curr_function = thread.GetFrameAtIndex(0).GetFunctionName() 60 self.assertEqual( 61 curr_function, 62 "call_through_indirect_hidden", 63 "Stepped into indirect symbols.", 64 ) 65 66 # Now set a breakpoint using the indirect symbol name, and make sure we 67 # get to that: 68 break_indirect = target.BreakpointCreateByName("call_through_indirect") 69 self.assertTrue(break_indirect, VALID_BREAKPOINT) 70 71 # Now continue should take us to the second call through the indirect 72 # symbol: 73 74 threads = lldbutil.continue_to_breakpoint(process, break_indirect) 75 self.assertEqual(len(threads), 1, "Stopped at breakpoint in indirect function.") 76 curr_function = thread.GetFrameAtIndex(0).GetFunctionName() 77 self.assertEqual( 78 curr_function, 79 "call_through_indirect_hidden", 80 "Stepped into indirect symbols.", 81 ) 82 83 # Delete this breakpoint so it won't get in the way: 84 target.BreakpointDelete(break_indirect.GetID()) 85 86 # Now continue to the site of the first re-exported function call in 87 # main: 88 threads = lldbutil.continue_to_breakpoint(process, break2) 89 90 # This is stepping Into through a re-exported symbol to an indirect 91 # symbol: 92 thread.StepInto() 93 curr_function = thread.GetFrameAtIndex(0).GetFunctionName() 94 self.assertEqual( 95 curr_function, 96 "call_through_indirect_hidden", 97 "Stepped into indirect symbols.", 98 ) 99 100 # And the last bit is to set a breakpoint on the re-exported symbol and 101 # make sure we are again in out target function. 102 break_reexported = target.BreakpointCreateByName("reexport_to_indirect") 103 self.assertEqual(break_reexported.GetNumLocations(), 1, VALID_BREAKPOINT) 104 105 # Now continue should take us to the second call through the indirect 106 # symbol: 107 108 threads = lldbutil.continue_to_breakpoint(process, break_reexported) 109 self.assertEqual( 110 len(threads), 1, "Stopped at breakpoint in reexported function target." 111 ) 112 curr_function = thread.GetFrameAtIndex(0).GetFunctionName() 113 self.assertEqual( 114 curr_function, 115 "call_through_indirect_hidden", 116 "Stepped into indirect symbols.", 117 ) 118