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