1*99451b44SJordan Rupprecht"""
2*99451b44SJordan RupprechtTest setting breakpoints using a scripted resolver
3*99451b44SJordan Rupprecht"""
4*99451b44SJordan Rupprecht
5*99451b44SJordan Rupprechtimport os
6*99451b44SJordan Rupprechtimport lldb
7*99451b44SJordan Rupprechtimport lldbsuite.test.lldbutil as lldbutil
8*99451b44SJordan Rupprechtfrom lldbsuite.test.decorators import *
9*99451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import *
10*99451b44SJordan Rupprecht
11*99451b44SJordan Rupprecht
12*99451b44SJordan Rupprechtclass TestScriptedResolver(TestBase):
13*99451b44SJordan Rupprecht
14*99451b44SJordan Rupprecht    mydir = TestBase.compute_mydir(__file__)
15*99451b44SJordan Rupprecht
16*99451b44SJordan Rupprecht    NO_DEBUG_INFO_TESTCASE = True
17*99451b44SJordan Rupprecht
18*99451b44SJordan Rupprecht    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24528")
19*99451b44SJordan Rupprecht    def test_scripted_resolver(self):
20*99451b44SJordan Rupprecht        """Use a scripted resolver to set a by symbol name breakpoint"""
21*99451b44SJordan Rupprecht        self.build()
22*99451b44SJordan Rupprecht        self.do_test()
23*99451b44SJordan Rupprecht
24*99451b44SJordan Rupprecht    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24528")
25*99451b44SJordan Rupprecht    def test_search_depths(self):
26*99451b44SJordan Rupprecht        """ Make sure we are called at the right depths depending on what we return
27*99451b44SJordan Rupprecht            from __get_depth__"""
28*99451b44SJordan Rupprecht        self.build()
29*99451b44SJordan Rupprecht        self.do_test_depths()
30*99451b44SJordan Rupprecht
31*99451b44SJordan Rupprecht    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24528")
32*99451b44SJordan Rupprecht    def test_command_line(self):
33*99451b44SJordan Rupprecht        """ Test setting a resolver breakpoint from the command line """
34*99451b44SJordan Rupprecht        self.build()
35*99451b44SJordan Rupprecht        self.do_test_cli()
36*99451b44SJordan Rupprecht
37*99451b44SJordan Rupprecht    def test_bad_command_lines(self):
38*99451b44SJordan Rupprecht        """Make sure we get appropriate errors when we give invalid key/value
39*99451b44SJordan Rupprecht           options"""
40*99451b44SJordan Rupprecht        self.build()
41*99451b44SJordan Rupprecht        self.do_test_bad_options()
42*99451b44SJordan Rupprecht
43*99451b44SJordan Rupprecht    def make_target_and_import(self):
44*99451b44SJordan Rupprecht        target = lldbutil.run_to_breakpoint_make_target(self)
45*99451b44SJordan Rupprecht        interp = self.dbg.GetCommandInterpreter()
46*99451b44SJordan Rupprecht        error = lldb.SBError()
47*99451b44SJordan Rupprecht
48*99451b44SJordan Rupprecht        script_name = os.path.join(self.getSourceDir(), "resolver.py")
49*99451b44SJordan Rupprecht        source_name = os.path.join(self.getSourceDir(), "main.c")
50*99451b44SJordan Rupprecht
51*99451b44SJordan Rupprecht        command = "command script import " + script_name
52*99451b44SJordan Rupprecht        result = lldb.SBCommandReturnObject()
53*99451b44SJordan Rupprecht        interp.HandleCommand(command, result)
54*99451b44SJordan Rupprecht        self.assertTrue(result.Succeeded(), "com scr imp failed: %s"%(result.GetError()))
55*99451b44SJordan Rupprecht        return target
56*99451b44SJordan Rupprecht
57*99451b44SJordan Rupprecht    def make_extra_args(self):
58*99451b44SJordan Rupprecht        json_string = '{"symbol":"break_on_me", "test1": "value1"}'
59*99451b44SJordan Rupprecht        json_stream = lldb.SBStream()
60*99451b44SJordan Rupprecht        json_stream.Print(json_string)
61*99451b44SJordan Rupprecht        extra_args = lldb.SBStructuredData()
62*99451b44SJordan Rupprecht        error = extra_args.SetFromJSON(json_stream)
63*99451b44SJordan Rupprecht        self.assertTrue(error.Success(), "Error making SBStructuredData: %s"%(error.GetCString()))
64*99451b44SJordan Rupprecht        return extra_args
65*99451b44SJordan Rupprecht
66*99451b44SJordan Rupprecht    def do_test(self):
67*99451b44SJordan Rupprecht        """This reads in a python file and sets a breakpoint using it."""
68*99451b44SJordan Rupprecht
69*99451b44SJordan Rupprecht        target = self.make_target_and_import()
70*99451b44SJordan Rupprecht        extra_args = self.make_extra_args()
71*99451b44SJordan Rupprecht
72*99451b44SJordan Rupprecht        file_list = lldb.SBFileSpecList()
73*99451b44SJordan Rupprecht        module_list = lldb.SBFileSpecList()
74*99451b44SJordan Rupprecht
75*99451b44SJordan Rupprecht        # Make breakpoints with this resolver using different filters, first ones that will take:
76*99451b44SJordan Rupprecht        right = []
77*99451b44SJordan Rupprecht        # one with no file or module spec - this one should fire:
78*99451b44SJordan Rupprecht        right.append(target.BreakpointCreateFromScript("resolver.Resolver", extra_args, module_list, file_list))
79*99451b44SJordan Rupprecht
80*99451b44SJordan Rupprecht        # one with the right source file and no module - should also fire:
81*99451b44SJordan Rupprecht        file_list.Append(lldb.SBFileSpec("main.c"))
82*99451b44SJordan Rupprecht        right.append(target.BreakpointCreateFromScript("resolver.Resolver", extra_args, module_list, file_list))
83*99451b44SJordan Rupprecht        # Make sure the help text shows up in the "break list" output:
84*99451b44SJordan Rupprecht        self.expect("break list", substrs=["I am a python breakpoint resolver"], msg="Help is listed in break list")
85*99451b44SJordan Rupprecht
86*99451b44SJordan Rupprecht        # one with the right source file and right module - should also fire:
87*99451b44SJordan Rupprecht        module_list.Append(lldb.SBFileSpec("a.out"))
88*99451b44SJordan Rupprecht        right.append(target.BreakpointCreateFromScript("resolver.Resolver", extra_args, module_list, file_list))
89*99451b44SJordan Rupprecht
90*99451b44SJordan Rupprecht        # And one with no source file but the right module:
91*99451b44SJordan Rupprecht        file_list.Clear()
92*99451b44SJordan Rupprecht        right.append(target.BreakpointCreateFromScript("resolver.Resolver", extra_args, module_list, file_list))
93*99451b44SJordan Rupprecht
94*99451b44SJordan Rupprecht        # Make sure these all got locations:
95*99451b44SJordan Rupprecht        for i in range (0, len(right)):
96*99451b44SJordan Rupprecht            self.assertTrue(right[i].GetNumLocations() >= 1, "Breakpoint %d has no locations."%(i))
97*99451b44SJordan Rupprecht
98*99451b44SJordan Rupprecht        # Now some ones that won't take:
99*99451b44SJordan Rupprecht
100*99451b44SJordan Rupprecht        module_list.Clear()
101*99451b44SJordan Rupprecht        file_list.Clear()
102*99451b44SJordan Rupprecht        wrong = []
103*99451b44SJordan Rupprecht
104*99451b44SJordan Rupprecht        # one with the wrong module - should not fire:
105*99451b44SJordan Rupprecht        module_list.Append(lldb.SBFileSpec("noSuchModule"))
106*99451b44SJordan Rupprecht        wrong.append(target.BreakpointCreateFromScript("resolver.Resolver", extra_args, module_list, file_list))
107*99451b44SJordan Rupprecht
108*99451b44SJordan Rupprecht        # one with the wrong file - also should not fire:
109*99451b44SJordan Rupprecht        file_list.Clear()
110*99451b44SJordan Rupprecht        module_list.Clear()
111*99451b44SJordan Rupprecht        file_list.Append(lldb.SBFileSpec("noFileOfThisName.xxx"))
112*99451b44SJordan Rupprecht        wrong.append(target.BreakpointCreateFromScript("resolver.Resolver", extra_args, module_list, file_list))
113*99451b44SJordan Rupprecht
114*99451b44SJordan Rupprecht        # Now make sure the CU level iteration obeys the file filters:
115*99451b44SJordan Rupprecht        file_list.Clear()
116*99451b44SJordan Rupprecht        module_list.Clear()
117*99451b44SJordan Rupprecht        file_list.Append(lldb.SBFileSpec("no_such_file.xxx"))
118*99451b44SJordan Rupprecht        wrong.append(target.BreakpointCreateFromScript("resolver.ResolverCUDepth", extra_args, module_list, file_list))
119*99451b44SJordan Rupprecht
120*99451b44SJordan Rupprecht        # And the Module filters:
121*99451b44SJordan Rupprecht        file_list.Clear()
122*99451b44SJordan Rupprecht        module_list.Clear()
123*99451b44SJordan Rupprecht        module_list.Append(lldb.SBFileSpec("NoSuchModule.dylib"))
124*99451b44SJordan Rupprecht        wrong.append(target.BreakpointCreateFromScript("resolver.ResolverCUDepth", extra_args, module_list, file_list))
125*99451b44SJordan Rupprecht
126*99451b44SJordan Rupprecht        # Now make sure the Function level iteration obeys the file filters:
127*99451b44SJordan Rupprecht        file_list.Clear()
128*99451b44SJordan Rupprecht        module_list.Clear()
129*99451b44SJordan Rupprecht        file_list.Append(lldb.SBFileSpec("no_such_file.xxx"))
130*99451b44SJordan Rupprecht        wrong.append(target.BreakpointCreateFromScript("resolver.ResolverFuncDepth", extra_args, module_list, file_list))
131*99451b44SJordan Rupprecht
132*99451b44SJordan Rupprecht        # And the Module filters:
133*99451b44SJordan Rupprecht        file_list.Clear()
134*99451b44SJordan Rupprecht        module_list.Clear()
135*99451b44SJordan Rupprecht        module_list.Append(lldb.SBFileSpec("NoSuchModule.dylib"))
136*99451b44SJordan Rupprecht        wrong.append(target.BreakpointCreateFromScript("resolver.ResolverFuncDepth", extra_args, module_list, file_list))
137*99451b44SJordan Rupprecht
138*99451b44SJordan Rupprecht        # Make sure these didn't get locations:
139*99451b44SJordan Rupprecht        for i in range(0, len(wrong)):
140*99451b44SJordan Rupprecht            self.assertEqual(wrong[i].GetNumLocations(), 0, "Breakpoint %d has locations."%(i))
141*99451b44SJordan Rupprecht
142*99451b44SJordan Rupprecht        # Now run to main and ensure we hit the breakpoints we should have:
143*99451b44SJordan Rupprecht
144*99451b44SJordan Rupprecht        lldbutil.run_to_breakpoint_do_run(self, target, right[0])
145*99451b44SJordan Rupprecht
146*99451b44SJordan Rupprecht        # Test the hit counts:
147*99451b44SJordan Rupprecht        for i in range(0, len(right)):
148*99451b44SJordan Rupprecht            self.assertEqual(right[i].GetHitCount(), 1, "Breakpoint %d has the wrong hit count"%(i))
149*99451b44SJordan Rupprecht
150*99451b44SJordan Rupprecht        for i in range(0, len(wrong)):
151*99451b44SJordan Rupprecht            self.assertEqual(wrong[i].GetHitCount(), 0, "Breakpoint %d has the wrong hit count"%(i))
152*99451b44SJordan Rupprecht
153*99451b44SJordan Rupprecht    def do_test_depths(self):
154*99451b44SJordan Rupprecht        """This test uses a class variable in resolver.Resolver which gets set to 1 if we saw
155*99451b44SJordan Rupprecht           compile unit and 2 if we only saw modules.  If the search depth is module, you get passed just
156*99451b44SJordan Rupprecht           the modules with no comp_unit.  If the depth is comp_unit you get comp_units.  So we can use
157*99451b44SJordan Rupprecht           this to test that our callback gets called at the right depth."""
158*99451b44SJordan Rupprecht
159*99451b44SJordan Rupprecht        target = self.make_target_and_import()
160*99451b44SJordan Rupprecht        extra_args = self.make_extra_args()
161*99451b44SJordan Rupprecht
162*99451b44SJordan Rupprecht        file_list = lldb.SBFileSpecList()
163*99451b44SJordan Rupprecht        module_list = lldb.SBFileSpecList()
164*99451b44SJordan Rupprecht        module_list.Append(lldb.SBFileSpec("a.out"))
165*99451b44SJordan Rupprecht
166*99451b44SJordan Rupprecht        # Make a breakpoint that has no __get_depth__, check that that is converted to eSearchDepthModule:
167*99451b44SJordan Rupprecht        bkpt = target.BreakpointCreateFromScript("resolver.Resolver", extra_args, module_list, file_list)
168*99451b44SJordan Rupprecht        self.assertTrue(bkpt.GetNumLocations() > 0, "Resolver got no locations.")
169*99451b44SJordan Rupprecht        self.expect("script print(resolver.Resolver.got_files)", substrs=["2"], msg="Was only passed modules")
170*99451b44SJordan Rupprecht
171*99451b44SJordan Rupprecht        # Make a breakpoint that asks for modules, check that we didn't get any files:
172*99451b44SJordan Rupprecht        bkpt = target.BreakpointCreateFromScript("resolver.ResolverModuleDepth", extra_args, module_list, file_list)
173*99451b44SJordan Rupprecht        self.assertTrue(bkpt.GetNumLocations() > 0, "ResolverModuleDepth got no locations.")
174*99451b44SJordan Rupprecht        self.expect("script print(resolver.Resolver.got_files)", substrs=["2"], msg="Was only passed modules")
175*99451b44SJordan Rupprecht
176*99451b44SJordan Rupprecht        # Make a breakpoint that asks for compile units, check that we didn't get any files:
177*99451b44SJordan Rupprecht        bkpt = target.BreakpointCreateFromScript("resolver.ResolverCUDepth", extra_args, module_list, file_list)
178*99451b44SJordan Rupprecht        self.assertTrue(bkpt.GetNumLocations() > 0, "ResolverCUDepth got no locations.")
179*99451b44SJordan Rupprecht        self.expect("script print(resolver.Resolver.got_files)", substrs=["1"], msg="Was passed compile units")
180*99451b44SJordan Rupprecht
181*99451b44SJordan Rupprecht        # Make a breakpoint that returns a bad value - we should convert that to "modules" so check that:
182*99451b44SJordan Rupprecht        bkpt = target.BreakpointCreateFromScript("resolver.ResolverBadDepth", extra_args, module_list, file_list)
183*99451b44SJordan Rupprecht        self.assertTrue(bkpt.GetNumLocations() > 0, "ResolverBadDepth got no locations.")
184*99451b44SJordan Rupprecht        self.expect("script print(resolver.Resolver.got_files)", substrs=["2"], msg="Was only passed modules")
185*99451b44SJordan Rupprecht
186*99451b44SJordan Rupprecht        # Make a breakpoint that searches at function depth:
187*99451b44SJordan Rupprecht        bkpt = target.BreakpointCreateFromScript("resolver.ResolverFuncDepth", extra_args, module_list, file_list)
188*99451b44SJordan Rupprecht        self.assertTrue(bkpt.GetNumLocations() > 0, "ResolverFuncDepth got no locations.")
189*99451b44SJordan Rupprecht        self.expect("script print(resolver.Resolver.got_files)", substrs=["3"], msg="Was only passed modules")
190*99451b44SJordan Rupprecht        self.expect("script print(resolver.Resolver.func_list)", substrs=['test_func', 'break_on_me', 'main'], msg="Saw all the functions")
191*99451b44SJordan Rupprecht
192*99451b44SJordan Rupprecht    def do_test_cli(self):
193*99451b44SJordan Rupprecht        target = self.make_target_and_import()
194*99451b44SJordan Rupprecht
195*99451b44SJordan Rupprecht        lldbutil.run_break_set_by_script(self, "resolver.Resolver", extra_options="-k symbol -v break_on_me")
196*99451b44SJordan Rupprecht
197*99451b44SJordan Rupprecht        # Make sure setting a resolver breakpoint doesn't pollute further breakpoint setting
198*99451b44SJordan Rupprecht        # by checking the description of a regular file & line breakpoint to make sure it
199*99451b44SJordan Rupprecht        # doesn't mention the Python Resolver function:
200*99451b44SJordan Rupprecht        bkpt_no = lldbutil.run_break_set_by_file_and_line(self, "main.c", 12)
201*99451b44SJordan Rupprecht        bkpt = target.FindBreakpointByID(bkpt_no)
202*99451b44SJordan Rupprecht        strm = lldb.SBStream()
203*99451b44SJordan Rupprecht        bkpt.GetDescription(strm, False)
204*99451b44SJordan Rupprecht        used_resolver = "I am a python breakpoint resolver" in strm.GetData()
205*99451b44SJordan Rupprecht        self.assertFalse(used_resolver, "Found the resolver description in the file & line breakpoint description.")
206*99451b44SJordan Rupprecht
207*99451b44SJordan Rupprecht        # Also make sure the breakpoint was where we expected:
208*99451b44SJordan Rupprecht        bp_loc = bkpt.GetLocationAtIndex(0)
209*99451b44SJordan Rupprecht        bp_sc = bp_loc.GetAddress().GetSymbolContext(lldb.eSymbolContextEverything)
210*99451b44SJordan Rupprecht        bp_se = bp_sc.GetLineEntry()
211*99451b44SJordan Rupprecht        self.assertEqual(bp_se.GetLine(), 12, "Got the right line number")
212*99451b44SJordan Rupprecht        self.assertEqual(bp_se.GetFileSpec().GetFilename(), "main.c", "Got the right filename")
213*99451b44SJordan Rupprecht
214*99451b44SJordan Rupprecht    def do_test_bad_options(self):
215*99451b44SJordan Rupprecht        target = self.make_target_and_import()
216*99451b44SJordan Rupprecht
217*99451b44SJordan Rupprecht        self.expect("break set -P resolver.Resolver -k a_key", error = True, msg="Missing value at end",
218*99451b44SJordan Rupprecht           substrs=['Key: "a_key" missing value'])
219*99451b44SJordan Rupprecht        self.expect("break set -P resolver.Resolver -v a_value", error = True, msg="Missing key at end",
220*99451b44SJordan Rupprecht           substrs=['Value: "a_value" missing matching key'])
221*99451b44SJordan Rupprecht        self.expect("break set -P resolver.Resolver -v a_value -k a_key -v another_value", error = True, msg="Missing key among args",
222*99451b44SJordan Rupprecht           substrs=['Value: "a_value" missing matching key'])
223*99451b44SJordan Rupprecht        self.expect("break set -P resolver.Resolver -k a_key -k a_key -v another_value", error = True, msg="Missing value among args",
224*99451b44SJordan Rupprecht           substrs=['Key: "a_key" missing value'])
225