199451b44SJordan Rupprecht"""
299451b44SJordan RupprechtTest setting breakpoints using a scripted resolver
399451b44SJordan Rupprecht"""
499451b44SJordan Rupprecht
599451b44SJordan Rupprechtimport os
699451b44SJordan Rupprechtimport lldb
799451b44SJordan Rupprechtimport lldbsuite.test.lldbutil as lldbutil
899451b44SJordan Rupprechtfrom lldbsuite.test.decorators import *
999451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import *
1099451b44SJordan Rupprecht
1199451b44SJordan Rupprecht
1299451b44SJordan Rupprechtclass TestScriptedResolver(TestBase):
1399451b44SJordan Rupprecht
1499451b44SJordan Rupprecht    mydir = TestBase.compute_mydir(__file__)
1599451b44SJordan Rupprecht
1699451b44SJordan Rupprecht    NO_DEBUG_INFO_TESTCASE = True
1799451b44SJordan Rupprecht
1899451b44SJordan Rupprecht    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24528")
1999451b44SJordan Rupprecht    def test_scripted_resolver(self):
2099451b44SJordan Rupprecht        """Use a scripted resolver to set a by symbol name breakpoint"""
2199451b44SJordan Rupprecht        self.build()
2299451b44SJordan Rupprecht        self.do_test()
2399451b44SJordan Rupprecht
2499451b44SJordan Rupprecht    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24528")
2599451b44SJordan Rupprecht    def test_search_depths(self):
2699451b44SJordan Rupprecht        """ Make sure we are called at the right depths depending on what we return
2799451b44SJordan Rupprecht            from __get_depth__"""
2899451b44SJordan Rupprecht        self.build()
2999451b44SJordan Rupprecht        self.do_test_depths()
3099451b44SJordan Rupprecht
3199451b44SJordan Rupprecht    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24528")
3299451b44SJordan Rupprecht    def test_command_line(self):
3399451b44SJordan Rupprecht        """ Test setting a resolver breakpoint from the command line """
3499451b44SJordan Rupprecht        self.build()
3599451b44SJordan Rupprecht        self.do_test_cli()
3699451b44SJordan Rupprecht
3799451b44SJordan Rupprecht    def test_bad_command_lines(self):
3899451b44SJordan Rupprecht        """Make sure we get appropriate errors when we give invalid key/value
3999451b44SJordan Rupprecht           options"""
4099451b44SJordan Rupprecht        self.build()
4199451b44SJordan Rupprecht        self.do_test_bad_options()
4299451b44SJordan Rupprecht
43185ef697STatyana Krasnukha    def test_copy_from_dummy_target(self):
44185ef697STatyana Krasnukha        """Make sure we don't crash during scripted breakpoint copy from dummy target"""
45185ef697STatyana Krasnukha        self.build()
46185ef697STatyana Krasnukha        self.do_test_copy_from_dummy_target()
47185ef697STatyana Krasnukha
4899451b44SJordan Rupprecht    def make_target_and_import(self):
49185ef697STatyana Krasnukha        target = self.make_target()
50185ef697STatyana Krasnukha        self.import_resolver_script()
51185ef697STatyana Krasnukha        return target
52185ef697STatyana Krasnukha
53185ef697STatyana Krasnukha    def make_target(self):
54185ef697STatyana Krasnukha        return lldbutil.run_to_breakpoint_make_target(self)
55185ef697STatyana Krasnukha
56185ef697STatyana Krasnukha    def import_resolver_script(self):
5799451b44SJordan Rupprecht        interp = self.dbg.GetCommandInterpreter()
5899451b44SJordan Rupprecht        error = lldb.SBError()
5999451b44SJordan Rupprecht
6099451b44SJordan Rupprecht        script_name = os.path.join(self.getSourceDir(), "resolver.py")
6199451b44SJordan Rupprecht        source_name = os.path.join(self.getSourceDir(), "main.c")
6299451b44SJordan Rupprecht
6399451b44SJordan Rupprecht        command = "command script import " + script_name
6499451b44SJordan Rupprecht        result = lldb.SBCommandReturnObject()
6599451b44SJordan Rupprecht        interp.HandleCommand(command, result)
6699451b44SJordan Rupprecht        self.assertTrue(result.Succeeded(), "com scr imp failed: %s"%(result.GetError()))
6799451b44SJordan Rupprecht
6899451b44SJordan Rupprecht    def make_extra_args(self):
6999451b44SJordan Rupprecht        json_string = '{"symbol":"break_on_me", "test1": "value1"}'
7099451b44SJordan Rupprecht        json_stream = lldb.SBStream()
7199451b44SJordan Rupprecht        json_stream.Print(json_string)
7299451b44SJordan Rupprecht        extra_args = lldb.SBStructuredData()
7399451b44SJordan Rupprecht        error = extra_args.SetFromJSON(json_stream)
74*779bbbf2SDave Lee        self.assertSuccess(error, "Error making SBStructuredData")
7599451b44SJordan Rupprecht        return extra_args
7699451b44SJordan Rupprecht
7799451b44SJordan Rupprecht    def do_test(self):
7899451b44SJordan Rupprecht        """This reads in a python file and sets a breakpoint using it."""
7999451b44SJordan Rupprecht
8099451b44SJordan Rupprecht        target = self.make_target_and_import()
8199451b44SJordan Rupprecht        extra_args = self.make_extra_args()
8299451b44SJordan Rupprecht
8399451b44SJordan Rupprecht        file_list = lldb.SBFileSpecList()
8499451b44SJordan Rupprecht        module_list = lldb.SBFileSpecList()
8599451b44SJordan Rupprecht
8699451b44SJordan Rupprecht        # Make breakpoints with this resolver using different filters, first ones that will take:
8799451b44SJordan Rupprecht        right = []
8899451b44SJordan Rupprecht        # one with no file or module spec - this one should fire:
8999451b44SJordan Rupprecht        right.append(target.BreakpointCreateFromScript("resolver.Resolver", extra_args, module_list, file_list))
9099451b44SJordan Rupprecht
9199451b44SJordan Rupprecht        # one with the right source file and no module - should also fire:
9299451b44SJordan Rupprecht        file_list.Append(lldb.SBFileSpec("main.c"))
9399451b44SJordan Rupprecht        right.append(target.BreakpointCreateFromScript("resolver.Resolver", extra_args, module_list, file_list))
9499451b44SJordan Rupprecht        # Make sure the help text shows up in the "break list" output:
9599451b44SJordan Rupprecht        self.expect("break list", substrs=["I am a python breakpoint resolver"], msg="Help is listed in break list")
9699451b44SJordan Rupprecht
9799451b44SJordan Rupprecht        # one with the right source file and right module - should also fire:
9899451b44SJordan Rupprecht        module_list.Append(lldb.SBFileSpec("a.out"))
9999451b44SJordan Rupprecht        right.append(target.BreakpointCreateFromScript("resolver.Resolver", extra_args, module_list, file_list))
10099451b44SJordan Rupprecht
10199451b44SJordan Rupprecht        # And one with no source file but the right module:
10299451b44SJordan Rupprecht        file_list.Clear()
10399451b44SJordan Rupprecht        right.append(target.BreakpointCreateFromScript("resolver.Resolver", extra_args, module_list, file_list))
10499451b44SJordan Rupprecht
10599451b44SJordan Rupprecht        # Make sure these all got locations:
10699451b44SJordan Rupprecht        for i in range (0, len(right)):
10799451b44SJordan Rupprecht            self.assertTrue(right[i].GetNumLocations() >= 1, "Breakpoint %d has no locations."%(i))
10899451b44SJordan Rupprecht
10999451b44SJordan Rupprecht        # Now some ones that won't take:
11099451b44SJordan Rupprecht
11199451b44SJordan Rupprecht        module_list.Clear()
11299451b44SJordan Rupprecht        file_list.Clear()
11399451b44SJordan Rupprecht        wrong = []
11499451b44SJordan Rupprecht
11599451b44SJordan Rupprecht        # one with the wrong module - should not fire:
11699451b44SJordan Rupprecht        module_list.Append(lldb.SBFileSpec("noSuchModule"))
11799451b44SJordan Rupprecht        wrong.append(target.BreakpointCreateFromScript("resolver.Resolver", extra_args, module_list, file_list))
11899451b44SJordan Rupprecht
11999451b44SJordan Rupprecht        # one with the wrong file - also should not fire:
12099451b44SJordan Rupprecht        file_list.Clear()
12199451b44SJordan Rupprecht        module_list.Clear()
12299451b44SJordan Rupprecht        file_list.Append(lldb.SBFileSpec("noFileOfThisName.xxx"))
12399451b44SJordan Rupprecht        wrong.append(target.BreakpointCreateFromScript("resolver.Resolver", extra_args, module_list, file_list))
12499451b44SJordan Rupprecht
12599451b44SJordan Rupprecht        # Now make sure the CU level iteration obeys the file filters:
12699451b44SJordan Rupprecht        file_list.Clear()
12799451b44SJordan Rupprecht        module_list.Clear()
12899451b44SJordan Rupprecht        file_list.Append(lldb.SBFileSpec("no_such_file.xxx"))
12999451b44SJordan Rupprecht        wrong.append(target.BreakpointCreateFromScript("resolver.ResolverCUDepth", extra_args, module_list, file_list))
13099451b44SJordan Rupprecht
13199451b44SJordan Rupprecht        # And the Module filters:
13299451b44SJordan Rupprecht        file_list.Clear()
13399451b44SJordan Rupprecht        module_list.Clear()
13499451b44SJordan Rupprecht        module_list.Append(lldb.SBFileSpec("NoSuchModule.dylib"))
13599451b44SJordan Rupprecht        wrong.append(target.BreakpointCreateFromScript("resolver.ResolverCUDepth", extra_args, module_list, file_list))
13699451b44SJordan Rupprecht
13799451b44SJordan Rupprecht        # Now make sure the Function level iteration obeys the file filters:
13899451b44SJordan Rupprecht        file_list.Clear()
13999451b44SJordan Rupprecht        module_list.Clear()
14099451b44SJordan Rupprecht        file_list.Append(lldb.SBFileSpec("no_such_file.xxx"))
14199451b44SJordan Rupprecht        wrong.append(target.BreakpointCreateFromScript("resolver.ResolverFuncDepth", extra_args, module_list, file_list))
14299451b44SJordan Rupprecht
14399451b44SJordan Rupprecht        # And the Module filters:
14499451b44SJordan Rupprecht        file_list.Clear()
14599451b44SJordan Rupprecht        module_list.Clear()
14699451b44SJordan Rupprecht        module_list.Append(lldb.SBFileSpec("NoSuchModule.dylib"))
14799451b44SJordan Rupprecht        wrong.append(target.BreakpointCreateFromScript("resolver.ResolverFuncDepth", extra_args, module_list, file_list))
14899451b44SJordan Rupprecht
14999451b44SJordan Rupprecht        # Make sure these didn't get locations:
15099451b44SJordan Rupprecht        for i in range(0, len(wrong)):
15199451b44SJordan Rupprecht            self.assertEqual(wrong[i].GetNumLocations(), 0, "Breakpoint %d has locations."%(i))
15299451b44SJordan Rupprecht
15399451b44SJordan Rupprecht        # Now run to main and ensure we hit the breakpoints we should have:
15499451b44SJordan Rupprecht
15599451b44SJordan Rupprecht        lldbutil.run_to_breakpoint_do_run(self, target, right[0])
15699451b44SJordan Rupprecht
15799451b44SJordan Rupprecht        # Test the hit counts:
15899451b44SJordan Rupprecht        for i in range(0, len(right)):
15999451b44SJordan Rupprecht            self.assertEqual(right[i].GetHitCount(), 1, "Breakpoint %d has the wrong hit count"%(i))
16099451b44SJordan Rupprecht
16199451b44SJordan Rupprecht        for i in range(0, len(wrong)):
16299451b44SJordan Rupprecht            self.assertEqual(wrong[i].GetHitCount(), 0, "Breakpoint %d has the wrong hit count"%(i))
16399451b44SJordan Rupprecht
16499451b44SJordan Rupprecht    def do_test_depths(self):
16599451b44SJordan Rupprecht        """This test uses a class variable in resolver.Resolver which gets set to 1 if we saw
16699451b44SJordan Rupprecht           compile unit and 2 if we only saw modules.  If the search depth is module, you get passed just
16799451b44SJordan Rupprecht           the modules with no comp_unit.  If the depth is comp_unit you get comp_units.  So we can use
16899451b44SJordan Rupprecht           this to test that our callback gets called at the right depth."""
16999451b44SJordan Rupprecht
17099451b44SJordan Rupprecht        target = self.make_target_and_import()
17199451b44SJordan Rupprecht        extra_args = self.make_extra_args()
17299451b44SJordan Rupprecht
17399451b44SJordan Rupprecht        file_list = lldb.SBFileSpecList()
17499451b44SJordan Rupprecht        module_list = lldb.SBFileSpecList()
17599451b44SJordan Rupprecht        module_list.Append(lldb.SBFileSpec("a.out"))
17699451b44SJordan Rupprecht
17799451b44SJordan Rupprecht        # Make a breakpoint that has no __get_depth__, check that that is converted to eSearchDepthModule:
17899451b44SJordan Rupprecht        bkpt = target.BreakpointCreateFromScript("resolver.Resolver", extra_args, module_list, file_list)
17999451b44SJordan Rupprecht        self.assertTrue(bkpt.GetNumLocations() > 0, "Resolver got no locations.")
18099451b44SJordan Rupprecht        self.expect("script print(resolver.Resolver.got_files)", substrs=["2"], msg="Was only passed modules")
18199451b44SJordan Rupprecht
18299451b44SJordan Rupprecht        # Make a breakpoint that asks for modules, check that we didn't get any files:
18399451b44SJordan Rupprecht        bkpt = target.BreakpointCreateFromScript("resolver.ResolverModuleDepth", extra_args, module_list, file_list)
18499451b44SJordan Rupprecht        self.assertTrue(bkpt.GetNumLocations() > 0, "ResolverModuleDepth got no locations.")
18599451b44SJordan Rupprecht        self.expect("script print(resolver.Resolver.got_files)", substrs=["2"], msg="Was only passed modules")
18699451b44SJordan Rupprecht
18799451b44SJordan Rupprecht        # Make a breakpoint that asks for compile units, check that we didn't get any files:
18899451b44SJordan Rupprecht        bkpt = target.BreakpointCreateFromScript("resolver.ResolverCUDepth", extra_args, module_list, file_list)
18999451b44SJordan Rupprecht        self.assertTrue(bkpt.GetNumLocations() > 0, "ResolverCUDepth got no locations.")
19099451b44SJordan Rupprecht        self.expect("script print(resolver.Resolver.got_files)", substrs=["1"], msg="Was passed compile units")
19199451b44SJordan Rupprecht
19299451b44SJordan Rupprecht        # Make a breakpoint that returns a bad value - we should convert that to "modules" so check that:
19399451b44SJordan Rupprecht        bkpt = target.BreakpointCreateFromScript("resolver.ResolverBadDepth", extra_args, module_list, file_list)
19499451b44SJordan Rupprecht        self.assertTrue(bkpt.GetNumLocations() > 0, "ResolverBadDepth got no locations.")
19599451b44SJordan Rupprecht        self.expect("script print(resolver.Resolver.got_files)", substrs=["2"], msg="Was only passed modules")
19699451b44SJordan Rupprecht
19799451b44SJordan Rupprecht        # Make a breakpoint that searches at function depth:
19899451b44SJordan Rupprecht        bkpt = target.BreakpointCreateFromScript("resolver.ResolverFuncDepth", extra_args, module_list, file_list)
19999451b44SJordan Rupprecht        self.assertTrue(bkpt.GetNumLocations() > 0, "ResolverFuncDepth got no locations.")
20099451b44SJordan Rupprecht        self.expect("script print(resolver.Resolver.got_files)", substrs=["3"], msg="Was only passed modules")
20199451b44SJordan Rupprecht        self.expect("script print(resolver.Resolver.func_list)", substrs=['test_func', 'break_on_me', 'main'], msg="Saw all the functions")
20299451b44SJordan Rupprecht
20399451b44SJordan Rupprecht    def do_test_cli(self):
20499451b44SJordan Rupprecht        target = self.make_target_and_import()
20599451b44SJordan Rupprecht
20699451b44SJordan Rupprecht        lldbutil.run_break_set_by_script(self, "resolver.Resolver", extra_options="-k symbol -v break_on_me")
20799451b44SJordan Rupprecht
20899451b44SJordan Rupprecht        # Make sure setting a resolver breakpoint doesn't pollute further breakpoint setting
20999451b44SJordan Rupprecht        # by checking the description of a regular file & line breakpoint to make sure it
21099451b44SJordan Rupprecht        # doesn't mention the Python Resolver function:
21199451b44SJordan Rupprecht        bkpt_no = lldbutil.run_break_set_by_file_and_line(self, "main.c", 12)
21299451b44SJordan Rupprecht        bkpt = target.FindBreakpointByID(bkpt_no)
21399451b44SJordan Rupprecht        strm = lldb.SBStream()
21499451b44SJordan Rupprecht        bkpt.GetDescription(strm, False)
21599451b44SJordan Rupprecht        used_resolver = "I am a python breakpoint resolver" in strm.GetData()
21699451b44SJordan Rupprecht        self.assertFalse(used_resolver, "Found the resolver description in the file & line breakpoint description.")
21799451b44SJordan Rupprecht
21899451b44SJordan Rupprecht        # Also make sure the breakpoint was where we expected:
21999451b44SJordan Rupprecht        bp_loc = bkpt.GetLocationAtIndex(0)
22099451b44SJordan Rupprecht        bp_sc = bp_loc.GetAddress().GetSymbolContext(lldb.eSymbolContextEverything)
22199451b44SJordan Rupprecht        bp_se = bp_sc.GetLineEntry()
22299451b44SJordan Rupprecht        self.assertEqual(bp_se.GetLine(), 12, "Got the right line number")
22399451b44SJordan Rupprecht        self.assertEqual(bp_se.GetFileSpec().GetFilename(), "main.c", "Got the right filename")
22499451b44SJordan Rupprecht
22599451b44SJordan Rupprecht    def do_test_bad_options(self):
22699451b44SJordan Rupprecht        target = self.make_target_and_import()
22799451b44SJordan Rupprecht
22899451b44SJordan Rupprecht        self.expect("break set -P resolver.Resolver -k a_key", error = True, msg="Missing value at end",
22999451b44SJordan Rupprecht           substrs=['Key: "a_key" missing value'])
23099451b44SJordan Rupprecht        self.expect("break set -P resolver.Resolver -v a_value", error = True, msg="Missing key at end",
23199451b44SJordan Rupprecht           substrs=['Value: "a_value" missing matching key'])
23299451b44SJordan Rupprecht        self.expect("break set -P resolver.Resolver -v a_value -k a_key -v another_value", error = True, msg="Missing key among args",
23399451b44SJordan Rupprecht           substrs=['Value: "a_value" missing matching key'])
23499451b44SJordan Rupprecht        self.expect("break set -P resolver.Resolver -k a_key -k a_key -v another_value", error = True, msg="Missing value among args",
23599451b44SJordan Rupprecht           substrs=['Key: "a_key" missing value'])
236185ef697STatyana Krasnukha
237185ef697STatyana Krasnukha    def do_test_copy_from_dummy_target(self):
238185ef697STatyana Krasnukha        # Import breakpoint scripted resolver.
239185ef697STatyana Krasnukha        self.import_resolver_script()
240185ef697STatyana Krasnukha
241185ef697STatyana Krasnukha        # Create a scripted breakpoint.
242185ef697STatyana Krasnukha        self.runCmd("breakpoint set -P resolver.Resolver -k symbol -v break_on_me",
243185ef697STatyana Krasnukha                    BREAKPOINT_CREATED)
244185ef697STatyana Krasnukha
245185ef697STatyana Krasnukha        # This is the function to remove breakpoints from the dummy target
246185ef697STatyana Krasnukha        # to get a clean state for the next test case.
247185ef697STatyana Krasnukha        def cleanup():
248185ef697STatyana Krasnukha            self.runCmd('breakpoint delete -D -f', check=False)
249185ef697STatyana Krasnukha            self.runCmd('breakpoint list', check=False)
250185ef697STatyana Krasnukha
251185ef697STatyana Krasnukha        # Execute the cleanup function during test case tear down.
252185ef697STatyana Krasnukha        self.addTearDownHook(cleanup)
253185ef697STatyana Krasnukha
254185ef697STatyana Krasnukha        # Check that target creating doesn't crash.
255185ef697STatyana Krasnukha        target = self.make_target()
256