aboutsummaryrefslogtreecommitdiff
path: root/lldb/test/API/functionalities/thread/jump/TestThreadJump.py
blob: 715846c10f23f2724b91ffbfd338930482e32a56 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
"""
Test jumping to different places.
"""


import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil


class ThreadJumpTestCase(TestBase):
    def setUp(self):
        TestBase.setUp(self)
        self.build()

    def test(self):
        """Test thread jump handling."""
        exe = self.getBuildArtifact("a.out")
        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)

        # Find the line numbers for our breakpoints.
        self.mark1 = line_number("main.cpp", "// 1st marker")
        self.mark2 = line_number("main.cpp", "// 2nd marker")
        self.mark3 = line_number("main.cpp", "// 3rd marker")
        self.mark4 = line_number("main.cpp", "// 4th marker")
        self.mark5 = line_number("other.cpp", "// other marker")

        lldbutil.run_break_set_by_file_and_line(
            self, "main.cpp", self.mark3, num_expected_locations=1
        )
        self.runCmd("run", RUN_SUCCEEDED)

        # The stop reason of the thread should be breakpoint 1.
        self.expect(
            "thread list",
            STOPPED_DUE_TO_BREAKPOINT + " 1",
            substrs=[
                "stopped",
                "main.cpp:{}".format(self.mark3),
                "stop reason = breakpoint 1",
            ],
        )

        # Try the int path, force it to return 'a'
        self.do_min_test(self.mark3, self.mark1, "i", "4")
        # Try the int path, force it to return 'b'
        self.do_min_test(self.mark3, self.mark2, "i", "5")
        # Try the double path, force it to return 'a'
        self.do_min_test(self.mark4, self.mark1, "j", "7")
        # Expected to fail on powerpc64le architecture
        if not self.isPPC64le():
            # Try the double path, force it to return 'b'
            self.do_min_test(self.mark4, self.mark2, "j", "8")

        # Try jumping to another function in a different file.
        self.runCmd("thread jump --file other.cpp --line %i --force" % self.mark5)
        self.expect("process status", substrs=["at other.cpp:%i" % self.mark5])

        # Try jumping to another function (without forcing)
        self.expect(
            "j main.cpp:%i" % self.mark1,
            COMMAND_FAILED_AS_EXPECTED,
            error=True,
            substrs=["error"],
        )

    @expectedFailureAll(compiler="clang", compiler_version=["<", "17.0"])
    def test_jump_offset(self):
        """Test Thread Jump by negative or positive offset"""
        exe = self.getBuildArtifact("a.out")
        file_name = "main.cpp"
        self.runCmd(f"target create {exe}", CURRENT_EXECUTABLE_SET)

        pos_jump = line_number(file_name, "// jump_offset 1")
        neg_jump = line_number(file_name, "// jump_offset 2")
        pos_breakpoint = line_number(file_name, "// breakpoint 1")
        neg_breakpoint = line_number(file_name, "// breakpoint 2")
        pos_jump_offset = pos_jump - pos_breakpoint
        neg_jump_offset = neg_jump - neg_breakpoint

        var_1, var_1_value = ("var_1", "10")
        var_2, var_2_value = ("var_2", "40")
        var_3, var_3_value = ("var_3", "10")

        # create pos_breakpoint and neg_breakpoint
        lldbutil.run_break_set_by_file_and_line(
            self, file_name, pos_breakpoint, num_expected_locations=1
        )
        lldbutil.run_break_set_by_file_and_line(
            self, file_name, neg_breakpoint, num_expected_locations=1
        )

        self.runCmd("run", RUN_SUCCEEDED)

        # test positive jump
        # The stop reason of the thread should be breakpoint 1.
        self.expect(
            "thread list",
            STOPPED_DUE_TO_BREAKPOINT + " 1",
            substrs=[
                "stopped",
                f"{file_name}:{pos_breakpoint}",
                "stop reason = breakpoint 1",
            ],
        )

        self.runCmd(f"thread jump --by +{pos_jump_offset}")
        self.expect("process status", substrs=[f"at {file_name}:{pos_jump}"])
        self.expect(f"print {var_1}", substrs=[var_1_value])

        self.runCmd("thread step-over")
        self.expect(f"print {var_2}", substrs=[var_2_value])

        self.runCmd("continue")

        # test negative jump
        # The stop reason of the thread should be breakpoint 1.
        self.expect(
            "thread list",
            STOPPED_DUE_TO_BREAKPOINT + " 2",
            substrs=[
                "stopped",
                f"{file_name}:{neg_breakpoint}",
                "stop reason = breakpoint 2",
            ],
        )

        self.runCmd(f"thread jump --by {neg_jump_offset}")
        self.expect("process status", substrs=[f"at {file_name}:{neg_jump}"])
        self.runCmd("thread step-over")
        self.expect(f"print {var_3}", substrs=[var_3_value])

    def do_min_test(self, start, jump, var, value):
        # jump to the start marker
        self.runCmd("j %i" % start)
        self.runCmd("thread step-in")  # step into the min fn
        # jump to the branch we're interested in
        self.runCmd("j %i" % jump)
        self.runCmd("thread step-out")  # return out
        self.runCmd("thread step-over")  # assign to the global
        self.expect("expr %s" % var, substrs=[value])  # check it