| """ | |
| Test lldb breakpoint ids. | |
| """ | |
| import lldb | |
| from lldbsuite.test.decorators import * | |
| from lldbsuite.test.lldbtest import * | |
| from lldbsuite.test import lldbutil | |
| class TestCPPBreakpointLocations(TestBase): | |
| SHARED_BUILD_TESTCASE = False | |
| @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24764") | |
| def test(self): | |
| self.do_test(dict()) | |
| @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24764") | |
| @skipIf(compiler=no_match("clang")) | |
| @skipIf(compiler_version=["<", "15.0"]) | |
| def test_simple_template_names(self): | |
| self.do_test(dict(CFLAGS_EXTRAS="-gsimple-template-names")) | |
| def do_test(self, debug_flags): | |
| self.build(dictionary=debug_flags) | |
| self.breakpoint_id_tests() | |
| def verify_breakpoint_locations(self, target, bp_dict): | |
| name = bp_dict["name"] | |
| names = bp_dict["loc_names"] | |
| bp = target.BreakpointCreateByName(name) | |
| self.assertEqual( | |
| bp.GetNumLocations(), | |
| len(names), | |
| "Make sure we find the right number of breakpoint locations for {}".format( | |
| name | |
| ), | |
| ) | |
| bp_loc_names = list() | |
| for bp_loc in bp: | |
| bp_loc_names.append(bp_loc.GetAddress().GetFunction().GetName()) | |
| for name in names: | |
| found = name in bp_loc_names | |
| if not found: | |
| print("Didn't find '%s' in: %s" % (name, bp_loc_names)) | |
| self.assertTrue(found, "Make sure we find all required locations") | |
| def breakpoint_id_tests(self): | |
| # Create a target by the debugger. | |
| exe = self.getBuildArtifact("a.out") | |
| target = self.dbg.CreateTarget(exe) | |
| self.assertTrue(target, VALID_TARGET) | |
| bp_dicts = [ | |
| { | |
| "name": "func1", | |
| "loc_names": ["a::c::func1()", "aa::cc::func1()", "b::c::func1()"], | |
| }, | |
| { | |
| "name": "func2", | |
| "loc_names": ["a::c::func2()", "aa::cc::func2()", "c::d::func2()"], | |
| }, | |
| { | |
| "name": "func3", | |
| "loc_names": [ | |
| "a::c::func3()", | |
| "aa::cc::func3()", | |
| "b::c::func3()", | |
| "c::d::func3()", | |
| ], | |
| }, | |
| {"name": "c::func1", "loc_names": ["a::c::func1()", "b::c::func1()"]}, | |
| {"name": "c::func2", "loc_names": ["a::c::func2()"]}, | |
| {"name": "c::func3", "loc_names": ["a::c::func3()", "b::c::func3()"]}, | |
| {"name": "a::c::func1", "loc_names": ["a::c::func1()"]}, | |
| {"name": "b::c::func1", "loc_names": ["b::c::func1()"]}, | |
| {"name": "c::d::func2", "loc_names": ["c::d::func2()"]}, | |
| {"name": "a::c::func1()", "loc_names": ["a::c::func1()"]}, | |
| {"name": "b::c::func1()", "loc_names": ["b::c::func1()"]}, | |
| {"name": "c::d::func2()", "loc_names": ["c::d::func2()"]}, | |
| # Template cases | |
| {"name": "func<float>", "loc_names": []}, | |
| {"name": "Foo::func<float>", "loc_names": []}, | |
| {"name": "ns::Foo::func<float>", "loc_names": []}, | |
| {"name": "func<int>", "loc_names": ["auto ns::Foo<double>::func<int>()"]}, | |
| { | |
| "name": "Foo<double>::func<int>", | |
| "loc_names": ["auto ns::Foo<double>::func<int>()"], | |
| }, | |
| { | |
| "name": "ns::Foo<double>::func<int>", | |
| "loc_names": ["auto ns::Foo<double>::func<int>()"], | |
| }, | |
| { | |
| "name": "func", | |
| "loc_names": [ | |
| "auto ns::Foo<double>::func<int>()", | |
| "auto ns::Foo<double>::func<ns::Foo<int>>()", | |
| ], | |
| }, | |
| {"name": "operator", "loc_names": []}, | |
| { | |
| "name": "ns::Foo<double>::operator bool", | |
| "loc_names": ["ns::Foo<double>::operator bool()"], | |
| }, | |
| { | |
| "name": "operator a::c", | |
| "loc_names": ["ns::Foo<double>::operator a::c<a::c>()"], | |
| }, | |
| { | |
| "name": "operator ns::Foo<int>", | |
| "loc_names": ["ns::Foo<double>::operator ns::Foo<int><ns::Foo<int>>()"], | |
| }, | |
| {"name": "operator<<<a::c>", "loc_names": []}, | |
| { | |
| "name": "operator<<<int>", | |
| "loc_names": ["void ns::Foo<double>::operator<<<int>(int)"], | |
| }, | |
| { | |
| "name": "ns::Foo<double>::operator<<", | |
| "loc_names": [ | |
| "void ns::Foo<double>::operator<<<int>(int)", | |
| "void ns::Foo<double>::operator<<<ns::Foo<int>>(ns::Foo<int>)", | |
| ], | |
| }, | |
| {"name": "g<float>", "loc_names": []}, | |
| {"name": "g<int>", "loc_names": ["void ns::g<int>()"]}, | |
| {"name": "g<char>", "loc_names": ["void ns::g<char>()"]}, | |
| {"name": "g", "loc_names": ["void ns::g<int>()", "void ns::g<char>()"]}, | |
| {"name": "ns::g<float>", "loc_names": []}, | |
| {"name": "ns::g<int>", "loc_names": ["void ns::g<int>()"]}, | |
| {"name": "ns::g<char>", "loc_names": ["void ns::g<char>()"]}, | |
| {"name": "ns::g", "loc_names": ["void ns::g<int>()", "void ns::g<char>()"]}, | |
| ] | |
| for bp_dict in bp_dicts: | |
| self.verify_breakpoint_locations(target, bp_dict) | |
| @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24764") | |
| @requireNotWasm( | |
| "Wasm emits a single merged destructor rather than the distinct D1/D2" | |
| "variants whose mangled names this test looks up by hand." | |
| ) | |
| def test_destructors(self): | |
| self.build() | |
| exe = self.getBuildArtifact("a.out") | |
| target = self.dbg.CreateTarget(exe) | |
| # Don't skip prologue, so we can check the breakpoint address more | |
| # easily | |
| self.runCmd("settings set target.skip-prologue false") | |
| try: | |
| names = ["~c", "c::~c", "c::~c()"] | |
| loc_names = {"a::c::~c()", "b::c::~c()"} | |
| # TODO: For windows targets we should put windows mangled names | |
| # here | |
| symbols = ["_ZN1a1cD1Ev", "_ZN1a1cD2Ev", "_ZN1b1cD1Ev", "_ZN1b1cD2Ev"] | |
| for name in names: | |
| bp = target.BreakpointCreateByName(name) | |
| bp_loc_names = { | |
| bp_loc.GetAddress().GetFunction().GetName() for bp_loc in bp | |
| } | |
| self.assertEqual( | |
| bp_loc_names, loc_names, "Breakpoint set on the correct symbol" | |
| ) | |
| bp_addresses = {bp_loc.GetLoadAddress() for bp_loc in bp} | |
| symbol_addresses = set() | |
| for symbol in symbols: | |
| sc_list = target.FindSymbols(symbol, lldb.eSymbolTypeCode) | |
| self.assertEqual(sc_list.GetSize(), 1, "Found symbol " + symbol) | |
| symbol = sc_list.GetContextAtIndex(0).GetSymbol() | |
| symbol_addresses.add( | |
| symbol.GetStartAddress().GetLoadAddress(target) | |
| ) | |
| self.assertEqual( | |
| symbol_addresses, bp_addresses, "Breakpoint set on correct address" | |
| ) | |
| finally: | |
| self.runCmd("settings clear target.skip-prologue") |