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