| """ |
| Test lldb breakpoint ids. |
| """ |
| |
| import lldb |
| from lldbsuite.test.decorators import * |
| from lldbsuite.test.lldbtest import * |
| from lldbsuite.test import lldbutil |
| |
| |
| class TestCPPBreakpointLocations(TestBase): |
| @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") |
| 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") |