xref: /llvm-project/lldb/test/API/functionalities/breakpoint/cpp/TestCPPBreakpointLocations.py (revision 80fcecb13c388ff087a27a4b0e7ca3dd8c98eaa4)
1"""
2Test lldb breakpoint ids.
3"""
4
5import lldb
6from lldbsuite.test.decorators import *
7from lldbsuite.test.lldbtest import *
8from lldbsuite.test import lldbutil
9
10
11class TestCPPBreakpointLocations(TestBase):
12    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24764")
13    def test(self):
14        self.do_test(dict())
15
16    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24764")
17    @skipIf(compiler=no_match("clang"))
18    @skipIf(compiler_version=["<", "15.0"])
19    def test_simple_template_names(self):
20        self.do_test(dict(CFLAGS_EXTRAS="-gsimple-template-names"))
21
22    def do_test(self, debug_flags):
23        self.build(dictionary=debug_flags)
24        self.breakpoint_id_tests()
25
26    def verify_breakpoint_locations(self, target, bp_dict):
27        name = bp_dict["name"]
28        names = bp_dict["loc_names"]
29        bp = target.BreakpointCreateByName(name)
30        self.assertEqual(
31            bp.GetNumLocations(),
32            len(names),
33            "Make sure we find the right number of breakpoint locations for {}".format(
34                name
35            ),
36        )
37
38        bp_loc_names = list()
39        for bp_loc in bp:
40            bp_loc_names.append(bp_loc.GetAddress().GetFunction().GetName())
41
42        for name in names:
43            found = name in bp_loc_names
44            if not found:
45                print("Didn't find '%s' in: %s" % (name, bp_loc_names))
46            self.assertTrue(found, "Make sure we find all required locations")
47
48    def breakpoint_id_tests(self):
49        # Create a target by the debugger.
50        exe = self.getBuildArtifact("a.out")
51        target = self.dbg.CreateTarget(exe)
52        self.assertTrue(target, VALID_TARGET)
53        bp_dicts = [
54            {
55                "name": "func1",
56                "loc_names": ["a::c::func1()", "aa::cc::func1()", "b::c::func1()"],
57            },
58            {
59                "name": "func2",
60                "loc_names": ["a::c::func2()", "aa::cc::func2()", "c::d::func2()"],
61            },
62            {
63                "name": "func3",
64                "loc_names": [
65                    "a::c::func3()",
66                    "aa::cc::func3()",
67                    "b::c::func3()",
68                    "c::d::func3()",
69                ],
70            },
71            {"name": "c::func1", "loc_names": ["a::c::func1()", "b::c::func1()"]},
72            {"name": "c::func2", "loc_names": ["a::c::func2()"]},
73            {"name": "c::func3", "loc_names": ["a::c::func3()", "b::c::func3()"]},
74            {"name": "a::c::func1", "loc_names": ["a::c::func1()"]},
75            {"name": "b::c::func1", "loc_names": ["b::c::func1()"]},
76            {"name": "c::d::func2", "loc_names": ["c::d::func2()"]},
77            {"name": "a::c::func1()", "loc_names": ["a::c::func1()"]},
78            {"name": "b::c::func1()", "loc_names": ["b::c::func1()"]},
79            {"name": "c::d::func2()", "loc_names": ["c::d::func2()"]},
80            # Template cases
81            {"name": "func<float>", "loc_names": []},
82            {"name": "Foo::func<float>", "loc_names": []},
83            {"name": "ns::Foo::func<float>", "loc_names": []},
84            {"name": "func<int>", "loc_names": ["auto ns::Foo<double>::func<int>()"]},
85            {
86                "name": "Foo<double>::func<int>",
87                "loc_names": ["auto ns::Foo<double>::func<int>()"],
88            },
89            {
90                "name": "ns::Foo<double>::func<int>",
91                "loc_names": ["auto ns::Foo<double>::func<int>()"],
92            },
93            {
94                "name": "func",
95                "loc_names": [
96                    "auto ns::Foo<double>::func<int>()",
97                    "auto ns::Foo<double>::func<ns::Foo<int>>()",
98                ],
99            },
100            {"name": "operator", "loc_names": []},
101            {
102                "name": "ns::Foo<double>::operator bool",
103                "loc_names": ["ns::Foo<double>::operator bool()"],
104            },
105            {
106                "name": "operator a::c",
107                "loc_names": ["ns::Foo<double>::operator a::c<a::c>()"],
108            },
109            {
110                "name": "operator ns::Foo<int>",
111                "loc_names": ["ns::Foo<double>::operator ns::Foo<int><ns::Foo<int>>()"],
112            },
113            {"name": "operator<<<a::c>", "loc_names": []},
114            {
115                "name": "operator<<<int>",
116                "loc_names": ["void ns::Foo<double>::operator<<<int>(int)"],
117            },
118            {
119                "name": "ns::Foo<double>::operator<<",
120                "loc_names": [
121                    "void ns::Foo<double>::operator<<<int>(int)",
122                    "void ns::Foo<double>::operator<<<ns::Foo<int>>(ns::Foo<int>)",
123                ],
124            },
125            {"name": "g<float>", "loc_names": []},
126            {"name": "g<int>", "loc_names": ["void ns::g<int>()"]},
127            {"name": "g<char>", "loc_names": ["void ns::g<char>()"]},
128            {"name": "g", "loc_names": ["void ns::g<int>()", "void ns::g<char>()"]},
129            {"name": "ns::g<float>", "loc_names": []},
130            {"name": "ns::g<int>", "loc_names": ["void ns::g<int>()"]},
131            {"name": "ns::g<char>", "loc_names": ["void ns::g<char>()"]},
132            {"name": "ns::g", "loc_names": ["void ns::g<int>()", "void ns::g<char>()"]},
133        ]
134
135        for bp_dict in bp_dicts:
136            self.verify_breakpoint_locations(target, bp_dict)
137
138    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24764")
139    def test_destructors(self):
140        self.build()
141        exe = self.getBuildArtifact("a.out")
142        target = self.dbg.CreateTarget(exe)
143
144        # Don't skip prologue, so we can check the breakpoint address more
145        # easily
146        self.runCmd("settings set target.skip-prologue false")
147        try:
148            names = ["~c", "c::~c", "c::~c()"]
149            loc_names = {"a::c::~c()", "b::c::~c()"}
150            # TODO: For windows targets we should put windows mangled names
151            # here
152            symbols = ["_ZN1a1cD1Ev", "_ZN1a1cD2Ev", "_ZN1b1cD1Ev", "_ZN1b1cD2Ev"]
153
154            for name in names:
155                bp = target.BreakpointCreateByName(name)
156
157                bp_loc_names = {
158                    bp_loc.GetAddress().GetFunction().GetName() for bp_loc in bp
159                }
160                self.assertEqual(
161                    bp_loc_names, loc_names, "Breakpoint set on the correct symbol"
162                )
163
164                bp_addresses = {bp_loc.GetLoadAddress() for bp_loc in bp}
165                symbol_addresses = set()
166                for symbol in symbols:
167                    sc_list = target.FindSymbols(symbol, lldb.eSymbolTypeCode)
168                    self.assertEqual(sc_list.GetSize(), 1, "Found symbol " + symbol)
169                    symbol = sc_list.GetContextAtIndex(0).GetSymbol()
170                    symbol_addresses.add(
171                        symbol.GetStartAddress().GetLoadAddress(target)
172                    )
173
174                self.assertEqual(
175                    symbol_addresses, bp_addresses, "Breakpoint set on correct address"
176                )
177        finally:
178            self.runCmd("settings clear target.skip-prologue")
179