xref: /llvm-project/lldb/test/API/macosx/indirect_symbol/TestIndirectSymbols.py (revision b49d741c0c3bb21b40c925b4c1a717470181eb8d)
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