xref: /llvm-project/lldb/test/API/functionalities/thread/step_until/TestStepUntilAPI.py (revision 58fc8029e91bf56811444d4a37a8f517a43bdc11)
1import lldb
2from lldbsuite.test.decorators import *
3from lldbsuite.test.lldbtest import *
4from lldbsuite.test import lldbutil
5
6
7class TestStepUntilAPI(TestBase):
8    NO_DEBUG_INFO_TESTCASE = True
9
10    def setUp(self):
11        super().setUp()
12
13        self.main_source = "main.c"
14        self.main_spec = lldb.SBFileSpec(self.main_source)
15        self.less_than_two = line_number("main.c", "Less than 2")
16        self.greater_than_two = line_number("main.c", "Greater than or equal to 2.")
17        self.back_out_in_main = line_number("main.c", "Back out in main")
18        self.in_foo = line_number("main.c", "In foo")
19
20    def _build_dict_for_discontinuity(self):
21        return dict(
22            CFLAGS_EXTRAS="-funique-basic-block-section-names "
23            + "-ffunction-sections -fbasic-block-sections=list="
24            + self.getSourcePath("function.list"),
25            LD_EXTRAS="-Wl,--script=" + self.getSourcePath("symbol.order"),
26        )
27
28    def _do_until(self, build_dict, args, until_line, expected_line):
29        self.build(dictionary=build_dict)
30        launch_info = lldb.SBLaunchInfo(args)
31        _, _, thread, _ = lldbutil.run_to_source_breakpoint(
32            self, "At the start", self.main_spec, launch_info
33        )
34
35        self.assertSuccess(
36            thread.StepOverUntil(self.frame(), self.main_spec, until_line)
37        )
38
39        self.runCmd("process status")
40
41        line = self.frame().GetLineEntry().GetLine()
42        self.assertEqual(
43            line, expected_line, "Did not get the expected stop line number"
44        )
45
46    def _assertDiscontinuity(self):
47        target = self.target()
48        foo = target.FindFunctions("foo")
49        self.assertEqual(len(foo), 1)
50        foo = foo[0]
51
52        call_me = self.target().FindFunctions("call_me")
53        self.assertEqual(len(call_me), 1)
54        call_me = call_me[0]
55
56        foo_addr = foo.function.GetStartAddress().GetLoadAddress(target)
57        found_before = False
58        found_after = False
59        for range in call_me.function.GetRanges():
60            addr = range.GetBaseAddress().GetLoadAddress(target)
61            if addr < foo_addr:
62                found_before = True
63            if addr > foo_addr:
64                found_after = True
65
66        self.assertTrue(
67            found_before and found_after,
68            "'foo' is not between 'call_me'" + str(foo) + str(call_me),
69        )
70
71    def test_hitting(self):
72        """Test SBThread.StepOverUntil - targeting a line and hitting it."""
73        self._do_until(None, None, self.less_than_two, self.less_than_two)
74
75    @skipIf(oslist=lldbplatformutil.getDarwinOSTriples() + ["windows"])
76    @skipIf(archs=no_match(["x86_64", "aarch64"]))
77    def test_hitting_discontinuous(self):
78        """Test SBThread.StepOverUntil - targeting a line and hitting it -- with
79        discontinuous functions"""
80        self._do_until(
81            self._build_dict_for_discontinuity(),
82            None,
83            self.less_than_two,
84            self.less_than_two,
85        )
86        self._assertDiscontinuity()
87
88    def test_missing(self):
89        """Test SBThread.StepOverUntil - targeting a line and missing it by stepping out to call site"""
90        self._do_until(
91            None, ["foo", "bar", "baz"], self.less_than_two, self.back_out_in_main
92        )
93
94    @skipIf(oslist=lldbplatformutil.getDarwinOSTriples() + ["windows"])
95    @skipIf(archs=no_match(["x86_64", "aarch64"]))
96    def test_missing_discontinuous(self):
97        """Test SBThread.StepOverUntil - targeting a line and missing it by
98        stepping out to call site -- with discontinuous functions"""
99        self._do_until(
100            self._build_dict_for_discontinuity(),
101            ["foo", "bar", "baz"],
102            self.less_than_two,
103            self.back_out_in_main,
104        )
105        self._assertDiscontinuity()
106
107    def test_bad_line(self):
108        """Test that we get an error if attempting to step outside the current
109        function"""
110        self.build()
111        _, _, thread, _ = lldbutil.run_to_source_breakpoint(
112            self, "At the start", self.main_spec
113        )
114        self.assertIn(
115            "step until target not in current function",
116            thread.StepOverUntil(
117                self.frame(), self.main_spec, self.in_foo
118            ).GetCString(),
119        )
120
121    @skipIf(oslist=lldbplatformutil.getDarwinOSTriples() + ["windows"])
122    @skipIf(archs=no_match(["x86_64", "aarch64"]))
123    def test_bad_line_discontinuous(self):
124        """Test that we get an error if attempting to step outside the current
125        function -- and the function is discontinuous"""
126        self.build(dictionary=self._build_dict_for_discontinuity())
127        _, _, thread, _ = lldbutil.run_to_source_breakpoint(
128            self, "At the start", self.main_spec
129        )
130        self.assertIn(
131            "step until target not in current function",
132            thread.StepOverUntil(
133                self.frame(), self.main_spec, self.in_foo
134            ).GetCString(),
135        )
136        self._assertDiscontinuity()
137