xref: /llvm-project/lldb/test/API/functionalities/breakpoint/breakpoint_names/TestBreakpointNames.py (revision 1eeeab82c6eb185f5139e633a59c2dbcb15616e4)
1"""
2Test breakpoint names.
3"""
4
5
6import os
7import lldb
8from lldbsuite.test.decorators import *
9from lldbsuite.test.lldbtest import *
10from lldbsuite.test import lldbutil
11
12
13class BreakpointNames(TestBase):
14    NO_DEBUG_INFO_TESTCASE = True
15
16    @add_test_categories(["pyapi"])
17    def test_setting_names(self):
18        """Use Python APIs to test that we can set breakpoint names."""
19        self.build()
20        self.setup_target()
21        self.do_check_names()
22
23    def test_illegal_names(self):
24        """Use Python APIs to test that we don't allow illegal names."""
25        self.build()
26        self.setup_target()
27        self.do_check_illegal_names()
28
29    def test_using_names(self):
30        """Use Python APIs to test that operations on names works correctly."""
31        self.build()
32        self.setup_target()
33        self.do_check_using_names()
34
35    def test_configuring_names(self):
36        """Use Python APIs to test that configuring options on breakpoint names works correctly."""
37        self.build()
38        self.make_a_dummy_name()
39        self.setup_target()
40        self.do_check_configuring_names()
41
42    def test_configuring_permissions_sb(self):
43        """Use Python APIs to test that configuring permissions on names works correctly."""
44        self.build()
45        self.setup_target()
46        self.do_check_configuring_permissions_sb()
47
48    def test_configuring_permissions_cli(self):
49        """Use Python APIs to test that configuring permissions on names works correctly."""
50        self.build()
51        self.setup_target()
52        self.do_check_configuring_permissions_cli()
53
54    def setup_target(self):
55        exe = self.getBuildArtifact("a.out")
56
57        # Create a targets we are making breakpoint in and copying to:
58        self.target = self.dbg.CreateTarget(exe)
59        self.assertTrue(self.target, VALID_TARGET)
60        self.main_file_spec = lldb.SBFileSpec(
61            os.path.join(self.getSourceDir(), "main.c")
62        )
63
64    def check_name_in_target(self, bkpt_name):
65        name_list = lldb.SBStringList()
66        self.target.GetBreakpointNames(name_list)
67        found_it = False
68        for name in name_list:
69            if name == bkpt_name:
70                found_it = True
71                break
72        self.assertTrue(
73            found_it, "Didn't find the name %s in the target's name list:" % (bkpt_name)
74        )
75
76    def setUp(self):
77        # Call super's setUp().
78        TestBase.setUp(self)
79
80        # These are the settings we're going to be putting into names & breakpoints:
81        self.bp_name_string = "ABreakpoint"
82        self.is_one_shot = True
83        self.ignore_count = 1000
84        self.condition = "1 == 2"
85        self.auto_continue = True
86        self.tid = 0xAAAA
87        self.tidx = 10
88        self.thread_name = "Fooey"
89        self.queue_name = "Blooey"
90        self.cmd_list = lldb.SBStringList()
91        self.cmd_list.AppendString("frame var")
92        self.cmd_list.AppendString("bt")
93        self.help_string = "I do something interesting"
94
95    def do_check_names(self):
96        """Use Python APIs to check that we can set & retrieve breakpoint names"""
97        bkpt = self.target.BreakpointCreateByLocation(self.main_file_spec, 10)
98        bkpt_name = "ABreakpoint"
99        other_bkpt_name = "_AnotherBreakpoint"
100
101        # Add a name and make sure we match it:
102        success = bkpt.AddNameWithErrorHandling(bkpt_name)
103        self.assertSuccess(success, "We couldn't add a legal name to a breakpoint.")
104
105        matches = bkpt.MatchesName(bkpt_name)
106        self.assertTrue(matches, "We didn't match the name we just set")
107
108        # Make sure we don't match irrelevant names:
109        matches = bkpt.MatchesName("NotABreakpoint")
110        self.assertTrue(not matches, "We matched a name we didn't set.")
111
112        # Make sure the name is also in the target:
113        self.check_name_in_target(bkpt_name)
114
115        # Add another name, make sure that works too:
116        bkpt.AddNameWithErrorHandling(other_bkpt_name)
117
118        matches = bkpt.MatchesName(bkpt_name)
119        self.assertTrue(
120            matches, "Adding a name means we didn't match the name we just set"
121        )
122        self.check_name_in_target(other_bkpt_name)
123
124        # Remove the name and make sure we no longer match it:
125        bkpt.RemoveName(bkpt_name)
126        matches = bkpt.MatchesName(bkpt_name)
127        self.assertTrue(not matches, "We still match a name after removing it.")
128
129        # Make sure the name list has the remaining name:
130        name_list = lldb.SBStringList()
131        bkpt.GetNames(name_list)
132        num_names = name_list.GetSize()
133        self.assertEqual(
134            num_names, 1, "Name list has %d items, expected 1." % (num_names)
135        )
136
137        name = name_list.GetStringAtIndex(0)
138        self.assertEqual(
139            name,
140            other_bkpt_name,
141            "Remaining name was: %s expected %s." % (name, other_bkpt_name),
142        )
143
144    def do_check_illegal_names(self):
145        """Use Python APIs to check that we reject illegal names."""
146        bkpt = self.target.BreakpointCreateByLocation(self.main_file_spec, 10)
147        bad_names = [
148            "-CantStartWithADash",
149            "1CantStartWithANumber",
150            "^CantStartWithNonAlpha",
151            "CantHave-ADash",
152            "Cant Have Spaces",
153        ]
154        for bad_name in bad_names:
155            success = bkpt.AddNameWithErrorHandling(bad_name)
156            self.assertTrue(
157                success.Fail(), "We allowed an illegal name: %s" % (bad_name)
158            )
159            bp_name = lldb.SBBreakpointName(self.target, bad_name)
160            self.assertFalse(
161                bp_name.IsValid(),
162                "We made a breakpoint name with an illegal name: %s" % (bad_name),
163            )
164
165            retval = lldb.SBCommandReturnObject()
166            self.dbg.GetCommandInterpreter().HandleCommand(
167                "break set -n whatever -N '%s'" % (bad_name), retval
168            )
169            self.assertTrue(
170                not retval.Succeeded(),
171                "break set succeeded with: illegal name: %s" % (bad_name),
172            )
173
174    def do_check_using_names(self):
175        """Use Python APIs to check names work in place of breakpoint ID's."""
176
177        # Create a dummy breakpoint to use up ID 1
178        _ = self.target.BreakpointCreateByLocation(self.main_file_spec, 30)
179
180        # Create a breakpoint to test with
181        bkpt = self.target.BreakpointCreateByLocation(self.main_file_spec, 10)
182        bkpt_name = "ABreakpoint"
183        bkpt_id = bkpt.GetID()
184        other_bkpt_name = "_AnotherBreakpoint"
185
186        # Add a name and make sure we match it:
187        success = bkpt.AddNameWithErrorHandling(bkpt_name)
188        self.assertSuccess(success, "We couldn't add a legal name to a breakpoint.")
189
190        bkpts = lldb.SBBreakpointList(self.target)
191        self.target.FindBreakpointsByName(bkpt_name, bkpts)
192
193        self.assertEqual(bkpts.GetSize(), 1, "One breakpoint matched.")
194        found_bkpt = bkpts.GetBreakpointAtIndex(0)
195        self.assertEqual(bkpt.GetID(), found_bkpt.GetID(), "The right breakpoint.")
196        self.assertEqual(bkpt.GetID(), bkpt_id, "With the same ID as before.")
197
198        retval = lldb.SBCommandReturnObject()
199        self.dbg.GetCommandInterpreter().HandleCommand(
200            "break disable %s" % (bkpt_name), retval
201        )
202        self.assertTrue(
203            retval.Succeeded(), "break disable failed with: %s." % (retval.GetError())
204        )
205        self.assertTrue(not bkpt.IsEnabled(), "We didn't disable the breakpoint.")
206
207        # Also make sure we don't apply commands to non-matching names:
208        self.dbg.GetCommandInterpreter().HandleCommand(
209            "break modify --one-shot 1 %s" % (other_bkpt_name), retval
210        )
211        self.assertTrue(
212            retval.Succeeded(), "break modify failed with: %s." % (retval.GetError())
213        )
214        self.assertTrue(
215            not bkpt.IsOneShot(), "We applied one-shot to the wrong breakpoint."
216        )
217
218    def check_option_values(self, bp_object):
219        self.assertEqual(bp_object.IsOneShot(), self.is_one_shot, "IsOneShot")
220        self.assertEqual(bp_object.GetIgnoreCount(), self.ignore_count, "IgnoreCount")
221        self.assertEqual(bp_object.GetCondition(), self.condition, "Condition")
222        self.assertEqual(
223            bp_object.GetAutoContinue(), self.auto_continue, "AutoContinue"
224        )
225        self.assertEqual(bp_object.GetThreadID(), self.tid, "Thread ID")
226        self.assertEqual(bp_object.GetThreadIndex(), self.tidx, "Thread Index")
227        self.assertEqual(bp_object.GetThreadName(), self.thread_name, "Thread Name")
228        self.assertEqual(bp_object.GetQueueName(), self.queue_name, "Queue Name")
229        set_cmds = lldb.SBStringList()
230        bp_object.GetCommandLineCommands(set_cmds)
231        self.assertEqual(
232            set_cmds.GetSize(), self.cmd_list.GetSize(), "Size of command line commands"
233        )
234        for idx in range(0, set_cmds.GetSize()):
235            self.assertEqual(
236                self.cmd_list.GetStringAtIndex(idx),
237                set_cmds.GetStringAtIndex(idx),
238                "Command %d" % (idx),
239            )
240
241    def make_a_dummy_name(self):
242        "This makes a breakpoint name in the dummy target to make sure it gets copied over"
243
244        dummy_target = self.dbg.GetDummyTarget()
245        self.assertTrue(dummy_target.IsValid(), "Dummy target was not valid.")
246
247        def cleanup():
248            self.dbg.GetDummyTarget().DeleteBreakpointName(self.bp_name_string)
249
250        # Execute the cleanup function during test case tear down.
251        self.addTearDownHook(cleanup)
252
253        # Now find it in the dummy target, and make sure these settings took:
254        bp_name = lldb.SBBreakpointName(dummy_target, self.bp_name_string)
255        # Make sure the name is right:
256        self.assertEqual(
257            bp_name.GetName(),
258            self.bp_name_string,
259            "Wrong bp_name: %s" % (bp_name.GetName()),
260        )
261        bp_name.SetOneShot(self.is_one_shot)
262        bp_name.SetIgnoreCount(self.ignore_count)
263        bp_name.SetCondition(self.condition)
264        bp_name.SetAutoContinue(self.auto_continue)
265        bp_name.SetThreadID(self.tid)
266        bp_name.SetThreadIndex(self.tidx)
267        bp_name.SetThreadName(self.thread_name)
268        bp_name.SetQueueName(self.queue_name)
269        bp_name.SetCommandLineCommands(self.cmd_list)
270
271        # Now look it up again, and make sure it got set correctly.
272        bp_name = lldb.SBBreakpointName(dummy_target, self.bp_name_string)
273        self.assertTrue(bp_name.IsValid(), "Failed to make breakpoint name.")
274        self.check_option_values(bp_name)
275
276    def do_check_configuring_names(self):
277        """Use Python APIs to check that configuring breakpoint names works correctly."""
278        other_bp_name_string = "AnotherBreakpointName"
279        cl_bp_name_string = "CLBreakpointName"
280
281        # Now find the version copied in from the dummy target, and make sure these settings took:
282        bp_name = lldb.SBBreakpointName(self.target, self.bp_name_string)
283        self.assertTrue(bp_name.IsValid(), "Failed to make breakpoint name.")
284        self.check_option_values(bp_name)
285
286        # Now add this name to a breakpoint, and make sure it gets configured properly
287        bkpt = self.target.BreakpointCreateByLocation(self.main_file_spec, 10)
288        success = bkpt.AddNameWithErrorHandling(self.bp_name_string)
289        self.assertSuccess(success, "Couldn't add this name to the breakpoint")
290        self.check_option_values(bkpt)
291
292        # Now make a name from this breakpoint, and make sure the new name is properly configured:
293        new_name = lldb.SBBreakpointName(bkpt, other_bp_name_string)
294        self.assertTrue(
295            new_name.IsValid(), "Couldn't make a valid bp_name from a breakpoint."
296        )
297        self.check_option_values(bkpt)
298
299        # Now change the name's option and make sure it gets propagated to
300        # the breakpoint:
301        new_auto_continue = not self.auto_continue
302        bp_name.SetAutoContinue(new_auto_continue)
303        self.assertEqual(
304            bp_name.GetAutoContinue(),
305            new_auto_continue,
306            "Couldn't change auto-continue on the name",
307        )
308        self.assertEqual(
309            bkpt.GetAutoContinue(),
310            new_auto_continue,
311            "Option didn't propagate to the breakpoint.",
312        )
313
314        # Now make this same breakpoint name - but from the command line
315        cmd_str = (
316            "breakpoint name configure %s -o %d -i %d -c '%s' -G %d -t %d -x %d -T '%s' -q '%s' -H '%s'"
317            % (
318                cl_bp_name_string,
319                self.is_one_shot,
320                self.ignore_count,
321                self.condition,
322                self.auto_continue,
323                self.tid,
324                self.tidx,
325                self.thread_name,
326                self.queue_name,
327                self.help_string,
328            )
329        )
330        for cmd in self.cmd_list:
331            cmd_str += " -C '%s'" % (cmd)
332
333        self.runCmd(cmd_str, check=True)
334        # Now look up this name again and check its options:
335        cl_name = lldb.SBBreakpointName(self.target, cl_bp_name_string)
336        self.check_option_values(cl_name)
337        # Also check the help string:
338        self.assertEqual(
339            self.help_string, cl_name.GetHelpString(), "Help string didn't match"
340        )
341        # Change the name and make sure that works:
342        new_help = "I do something even more interesting"
343        cl_name.SetHelpString(new_help)
344        self.assertEqual(new_help, cl_name.GetHelpString(), "SetHelpString didn't")
345
346        # We should have three names now, make sure the target can list them:
347        name_list = lldb.SBStringList()
348        self.target.GetBreakpointNames(name_list)
349        for name_string in [
350            self.bp_name_string,
351            other_bp_name_string,
352            cl_bp_name_string,
353        ]:
354            self.assertIn(
355                name_string, name_list, "Didn't find %s in names" % (name_string)
356            )
357
358        # Delete the name from the current target.  Make sure that works and deletes the
359        # name from the breakpoint as well:
360        self.target.DeleteBreakpointName(self.bp_name_string)
361        name_list.Clear()
362        self.target.GetBreakpointNames(name_list)
363        self.assertNotIn(
364            self.bp_name_string,
365            name_list,
366            "Didn't delete %s from a real target" % (self.bp_name_string),
367        )
368        # Also make sure the name got removed from breakpoints holding it:
369        self.assertFalse(
370            bkpt.MatchesName(self.bp_name_string),
371            "Didn't remove the name from the breakpoint.",
372        )
373
374        # Test that deleting the name we injected into the dummy target works (there's also a
375        # cleanup that will do this, but that won't test the result...
376        dummy_target = self.dbg.GetDummyTarget()
377        dummy_target.DeleteBreakpointName(self.bp_name_string)
378        name_list.Clear()
379        dummy_target.GetBreakpointNames(name_list)
380        self.assertNotIn(
381            self.bp_name_string,
382            name_list,
383            "Didn't delete %s from the dummy target" % (self.bp_name_string),
384        )
385        # Also make sure the name got removed from breakpoints holding it:
386        self.assertFalse(
387            bkpt.MatchesName(self.bp_name_string),
388            "Didn't remove the name from the breakpoint.",
389        )
390
391    def check_permission_results(self, bp_name):
392        self.assertFalse(bp_name.GetAllowDelete(), "Didn't set allow delete.")
393        protected_bkpt = self.target.BreakpointCreateByLocation(self.main_file_spec, 10)
394        protected_id = protected_bkpt.GetID()
395
396        unprotected_bkpt = self.target.BreakpointCreateByLocation(
397            self.main_file_spec, 10
398        )
399        unprotected_id = unprotected_bkpt.GetID()
400
401        success = protected_bkpt.AddNameWithErrorHandling(self.bp_name_string)
402        self.assertSuccess(success, "Couldn't add this name to the breakpoint")
403
404        self.target.DisableAllBreakpoints()
405        self.assertTrue(
406            protected_bkpt.IsEnabled(), "Didnt' keep breakpoint from being disabled"
407        )
408        self.assertFalse(
409            unprotected_bkpt.IsEnabled(),
410            "Protected too many breakpoints from disabling.",
411        )
412
413        # Try from the command line too:
414        unprotected_bkpt.SetEnabled(True)
415        result = lldb.SBCommandReturnObject()
416        self.dbg.GetCommandInterpreter().HandleCommand("break disable", result)
417        self.assertTrue(result.Succeeded())
418        self.assertTrue(
419            protected_bkpt.IsEnabled(), "Didnt' keep breakpoint from being disabled"
420        )
421        self.assertFalse(
422            unprotected_bkpt.IsEnabled(),
423            "Protected too many breakpoints from disabling.",
424        )
425
426        self.target.DeleteAllBreakpoints()
427        bkpt = self.target.FindBreakpointByID(protected_id)
428        self.assertTrue(
429            bkpt.IsValid(), "Didn't keep the breakpoint from being deleted."
430        )
431        bkpt = self.target.FindBreakpointByID(unprotected_id)
432        self.assertFalse(
433            bkpt.IsValid(), "Protected too many breakpoints from deletion."
434        )
435
436        # Remake the unprotected breakpoint and try again from the command line:
437        unprotected_bkpt = self.target.BreakpointCreateByLocation(
438            self.main_file_spec, 10
439        )
440        unprotected_id = unprotected_bkpt.GetID()
441
442        self.dbg.GetCommandInterpreter().HandleCommand("break delete -f", result)
443        self.assertTrue(result.Succeeded())
444        bkpt = self.target.FindBreakpointByID(protected_id)
445        self.assertTrue(
446            bkpt.IsValid(), "Didn't keep the breakpoint from being deleted."
447        )
448        bkpt = self.target.FindBreakpointByID(unprotected_id)
449        self.assertFalse(
450            bkpt.IsValid(), "Protected too many breakpoints from deletion."
451        )
452
453    def do_check_configuring_permissions_sb(self):
454        bp_name = lldb.SBBreakpointName(self.target, self.bp_name_string)
455
456        # Make a breakpoint name with delete disallowed:
457        bp_name = lldb.SBBreakpointName(self.target, self.bp_name_string)
458        self.assertTrue(
459            bp_name.IsValid(), "Failed to make breakpoint name for valid name."
460        )
461
462        bp_name.SetAllowDelete(False)
463        bp_name.SetAllowDisable(False)
464        bp_name.SetAllowList(False)
465        self.check_permission_results(bp_name)
466
467    def do_check_configuring_permissions_cli(self):
468        # Make the name with the right options using the command line:
469        self.runCmd(
470            "breakpoint name configure -L 0 -D 0 -A 0 %s" % (self.bp_name_string),
471            check=True,
472        )
473        # Now look up the breakpoint we made, and check that it works.
474        bp_name = lldb.SBBreakpointName(self.target, self.bp_name_string)
475        self.assertTrue(
476            bp_name.IsValid(), "Didn't make a breakpoint name we could find."
477        )
478        self.check_permission_results(bp_name)
479