"""
Test breakpoint names.
"""
import os
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
class BreakpointNames(TestBase):
NO_DEBUG_INFO_TESTCASE = True
@add_test_categories(["pyapi"])
def test_setting_names(self):
"""Use Python APIs to test that we can set breakpoint names."""
self.build()
self.setup_target()
self.do_check_names()
def test_illegal_names(self):
"""Use Python APIs to test that we don't allow illegal names."""
self.build()
self.setup_target()
self.do_check_illegal_names()
def test_using_names(self):
"""Use Python APIs to test that operations on names works correctly."""
self.build()
self.setup_target()
self.do_check_using_names()
def test_configuring_names(self):
"""Use Python APIs to test that configuring options on breakpoint names works correctly."""
self.build()
self.make_a_dummy_name()
self.setup_target()
self.do_check_configuring_names()
def test_configuring_permissions_sb(self):
"""Use Python APIs to test that configuring permissions on names works correctly."""
self.build()
self.setup_target()
self.do_check_configuring_permissions_sb()
def test_configuring_permissions_cli(self):
"""Use Python APIs to test that configuring permissions on names works correctly."""
self.build()
self.setup_target()
self.do_check_configuring_permissions_cli()
def setup_target(self):
exe = self.getBuildArtifact("a.out")
# Create a targets we are making breakpoint in and copying to:
self.target = self.dbg.CreateTarget(exe)
self.assertTrue(self.target, VALID_TARGET)
self.main_file_spec = lldb.SBFileSpec(
os.path.join(self.getSourceDir(), "main.c")
)
def check_name_in_target(self, bkpt_name):
name_list = lldb.SBStringList()
self.target.GetBreakpointNames(name_list)
found_it = False
for name in name_list:
if name == bkpt_name:
found_it = True
break
self.assertTrue(
found_it, "Didn't find the name %s in the target's name list:" % (bkpt_name)
)
def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
# These are the settings we're going to be putting into names & breakpoints:
self.bp_name_string = "ABreakpoint"
self.is_one_shot = True
self.ignore_count = 1000
self.condition = "1 == 2"
self.auto_continue = True
self.tid = 0xAAAA
self.tidx = 10
self.thread_name = "Fooey"
self.queue_name = "Blooey"
self.cmd_list = lldb.SBStringList()
self.cmd_list.AppendString("frame var")
self.cmd_list.AppendString("bt")
self.help_string = "I do something interesting"
def do_check_names(self):
"""Use Python APIs to check that we can set & retrieve breakpoint names"""
bkpt = self.target.BreakpointCreateByLocation(self.main_file_spec, 10)
bkpt_name = "ABreakpoint"
other_bkpt_name = "_AnotherBreakpoint"
# Add a name and make sure we match it:
success = bkpt.AddNameWithErrorHandling(bkpt_name)
self.assertSuccess(success, "We couldn't add a legal name to a breakpoint.")
matches = bkpt.MatchesName(bkpt_name)
self.assertTrue(matches, "We didn't match the name we just set")
# Make sure we don't match irrelevant names:
matches = bkpt.MatchesName("NotABreakpoint")
self.assertTrue(not matches, "We matched a name we didn't set.")
# Make sure the name is also in the target:
self.check_name_in_target(bkpt_name)
# Add another name, make sure that works too:
bkpt.AddNameWithErrorHandling(other_bkpt_name)
matches = bkpt.MatchesName(bkpt_name)
self.assertTrue(
matches, "Adding a name means we didn't match the name we just set"
)
self.check_name_in_target(other_bkpt_name)
# Remove the name and make sure we no longer match it:
bkpt.RemoveName(bkpt_name)
matches = bkpt.MatchesName(bkpt_name)
self.assertTrue(not matches, "We still match a name after removing it.")
# Make sure the name list has the remaining name:
name_list = lldb.SBStringList()
bkpt.GetNames(name_list)
num_names = name_list.GetSize()
self.assertEqual(
num_names, 1, "Name list has %d items, expected 1." % (num_names)
)
name = name_list.GetStringAtIndex(0)
self.assertEqual(
name,
other_bkpt_name,
"Remaining name was: %s expected %s." % (name, other_bkpt_name),
)
def do_check_illegal_names(self):
"""Use Python APIs to check that we reject illegal names."""
bkpt = self.target.BreakpointCreateByLocation(self.main_file_spec, 10)
bad_names = [
"-CantStartWithADash",
"1CantStartWithANumber",
"^CantStartWithNonAlpha",
"CantHave-ADash",
"Cant Have Spaces",
]
for bad_name in bad_names:
success = bkpt.AddNameWithErrorHandling(bad_name)
self.assertTrue(
success.Fail(), "We allowed an illegal name: %s" % (bad_name)
)
bp_name = lldb.SBBreakpointName(self.target, bad_name)
self.assertFalse(
bp_name.IsValid(),
"We made a breakpoint name with an illegal name: %s" % (bad_name),
)
retval = lldb.SBCommandReturnObject()
self.dbg.GetCommandInterpreter().HandleCommand(
"break set -n whatever -N '%s'" % (bad_name), retval
)
self.assertTrue(
not retval.Succeeded(),
"break set succeeded with: illegal name: %s" % (bad_name),
)
def do_check_using_names(self):
"""Use Python APIs to check names work in place of breakpoint ID's."""
# Create a dummy breakpoint to use up ID 1
_ = self.target.BreakpointCreateByLocation(self.main_file_spec, 30)
# Create a breakpoint to test with
bkpt = self.target.BreakpointCreateByLocation(self.main_file_spec, 10)
bkpt_name = "ABreakpoint"
bkpt_id = bkpt.GetID()
other_bkpt_name = "_AnotherBreakpoint"
# Add a name and make sure we match it:
success = bkpt.AddNameWithErrorHandling(bkpt_name)
self.assertSuccess(success, "We couldn't add a legal name to a breakpoint.")
bkpts = lldb.SBBreakpointList(self.target)
self.target.FindBreakpointsByName(bkpt_name, bkpts)
self.assertEqual(bkpts.GetSize(), 1, "One breakpoint matched.")
found_bkpt = bkpts.GetBreakpointAtIndex(0)
self.assertEqual(bkpt.GetID(), found_bkpt.GetID(), "The right breakpoint.")
self.assertEqual(bkpt.GetID(), bkpt_id, "With the same ID as before.")
retval = lldb.SBCommandReturnObject()
self.dbg.GetCommandInterpreter().HandleCommand(
"break disable %s" % (bkpt_name), retval
)
self.assertTrue(
retval.Succeeded(), "break disable failed with: %s." % (retval.GetError())
)
self.assertTrue(not bkpt.IsEnabled(), "We didn't disable the breakpoint.")
# Also make sure we don't apply commands to non-matching names:
self.dbg.GetCommandInterpreter().HandleCommand(
"break modify --one-shot 1 %s" % (other_bkpt_name), retval
)
self.assertTrue(
retval.Succeeded(), "break modify failed with: %s." % (retval.GetError())
)
self.assertTrue(
not bkpt.IsOneShot(), "We applied one-shot to the wrong breakpoint."
)
def check_option_values(self, bp_object):
self.assertEqual(bp_object.IsOneShot(), self.is_one_shot, "IsOneShot")
self.assertEqual(bp_object.GetIgnoreCount(), self.ignore_count, "IgnoreCount")
self.assertEqual(bp_object.GetCondition(), self.condition, "Condition")
self.assertEqual(
bp_object.GetAutoContinue(), self.auto_continue, "AutoContinue"
)
self.assertEqual(bp_object.GetThreadID(), self.tid, "Thread ID")
self.assertEqual(bp_object.GetThreadIndex(), self.tidx, "Thread Index")
self.assertEqual(bp_object.GetThreadName(), self.thread_name, "Thread Name")
self.assertEqual(bp_object.GetQueueName(), self.queue_name, "Queue Name")
set_cmds = lldb.SBStringList()
bp_object.GetCommandLineCommands(set_cmds)
self.assertEqual(
set_cmds.GetSize(), self.cmd_list.GetSize(), "Size of command line commands"
)
for idx in range(0, set_cmds.GetSize()):
self.assertEqual(
self.cmd_list.GetStringAtIndex(idx),
set_cmds.GetStringAtIndex(idx),
"Command %d" % (idx),
)
def make_a_dummy_name(self):
"This makes a breakpoint name in the dummy target to make sure it gets copied over"
dummy_target = self.dbg.GetDummyTarget()
self.assertTrue(dummy_target.IsValid(), "Dummy target was not valid.")
def cleanup():
self.dbg.GetDummyTarget().DeleteBreakpointName(self.bp_name_string)
# Execute the cleanup function during test case tear down.
self.addTearDownHook(cleanup)
# Now find it in the dummy target, and make sure these settings took:
bp_name = lldb.SBBreakpointName(dummy_target, self.bp_name_string)
# Make sure the name is right:
self.assertEqual(
bp_name.GetName(),
self.bp_name_string,
"Wrong bp_name: %s" % (bp_name.GetName()),
)
bp_name.SetOneShot(self.is_one_shot)
bp_name.SetIgnoreCount(self.ignore_count)
bp_name.SetCondition(self.condition)
bp_name.SetAutoContinue(self.auto_continue)
bp_name.SetThreadID(self.tid)
bp_name.SetThreadIndex(self.tidx)
bp_name.SetThreadName(self.thread_name)
bp_name.SetQueueName(self.queue_name)
bp_name.SetCommandLineCommands(self.cmd_list)
# Now look it up again, and make sure it got set correctly.
bp_name = lldb.SBBreakpointName(dummy_target, self.bp_name_string)
self.assertTrue(bp_name.IsValid(), "Failed to make breakpoint name.")
self.check_option_values(bp_name)
def do_check_configuring_names(self):
"""Use Python APIs to check that configuring breakpoint names works correctly."""
other_bp_name_string = "AnotherBreakpointName"
cl_bp_name_string = "CLBreakpointName"
# Now find the version copied in from the dummy target, and make sure these settings took:
bp_name = lldb.SBBreakpointName(self.target, self.bp_name_string)
self.assertTrue(bp_name.IsValid(), "Failed to make breakpoint name.")
self.check_option_values(bp_name)
# Now add this name to a breakpoint, and make sure it gets configured properly
bkpt = self.target.BreakpointCreateByLocation(self.main_file_spec, 10)
success = bkpt.AddNameWithErrorHandling(self.bp_name_string)
self.assertSuccess(success, "Couldn't add this name to the breakpoint")
self.check_option_values(bkpt)
# Now make a name from this breakpoint, and make sure the new name is properly configured:
new_name = lldb.SBBreakpointName(bkpt, other_bp_name_string)
self.assertTrue(
new_name.IsValid(), "Couldn't make a valid bp_name from a breakpoint."
)
self.check_option_values(bkpt)
# Now change the name's option and make sure it gets propagated to
# the breakpoint:
new_auto_continue = not self.auto_continue
bp_name.SetAutoContinue(new_auto_continue)
self.assertEqual(
bp_name.GetAutoContinue(),
new_auto_continue,
"Couldn't change auto-continue on the name",
)
self.assertEqual(
bkpt.GetAutoContinue(),
new_auto_continue,
"Option didn't propagate to the breakpoint.",
)
# Now make this same breakpoint name - but from the command line
cmd_str = (
"breakpoint name configure %s -o %d -i %d -c '%s' -G %d -t %d -x %d -T '%s' -q '%s' -H '%s'"
% (
cl_bp_name_string,
self.is_one_shot,
self.ignore_count,
self.condition,
self.auto_continue,
self.tid,
self.tidx,
self.thread_name,
self.queue_name,
self.help_string,
)
)
for cmd in self.cmd_list:
cmd_str += " -C '%s'" % (cmd)
self.runCmd(cmd_str, check=True)
# Now look up this name again and check its options:
cl_name = lldb.SBBreakpointName(self.target, cl_bp_name_string)
self.check_option_values(cl_name)
# Also check the help string:
self.assertEqual(
self.help_string, cl_name.GetHelpString(), "Help string didn't match"
)
# Change the name and make sure that works:
new_help = "I do something even more interesting"
cl_name.SetHelpString(new_help)
self.assertEqual(new_help, cl_name.GetHelpString(), "SetHelpString didn't")
# We should have three names now, make sure the target can list them:
name_list = lldb.SBStringList()
self.target.GetBreakpointNames(name_list)
for name_string in [
self.bp_name_string,
other_bp_name_string,
cl_bp_name_string,
]:
self.assertIn(
name_string, name_list, "Didn't find %s in names" % (name_string)
)
# Delete the name from the current target. Make sure that works and deletes the
# name from the breakpoint as well:
self.target.DeleteBreakpointName(self.bp_name_string)
name_list.Clear()
self.target.GetBreakpointNames(name_list)
self.assertNotIn(
self.bp_name_string,
name_list,
"Didn't delete %s from a real target" % (self.bp_name_string),
)
# Also make sure the name got removed from breakpoints holding it:
self.assertFalse(
bkpt.MatchesName(self.bp_name_string),
"Didn't remove the name from the breakpoint.",
)
# Test that deleting the name we injected into the dummy target works (there's also a
# cleanup that will do this, but that won't test the result...
dummy_target = self.dbg.GetDummyTarget()
dummy_target.DeleteBreakpointName(self.bp_name_string)
name_list.Clear()
dummy_target.GetBreakpointNames(name_list)
self.assertNotIn(
self.bp_name_string,
name_list,
"Didn't delete %s from the dummy target" % (self.bp_name_string),
)
# Also make sure the name got removed from breakpoints holding it:
self.assertFalse(
bkpt.MatchesName(self.bp_name_string),
"Didn't remove the name from the breakpoint.",
)
def check_permission_results(self, bp_name):
self.assertFalse(bp_name.GetAllowDelete(), "Didn't set allow delete.")
protected_bkpt = self.target.BreakpointCreateByLocation(self.main_file_spec, 10)
protected_id = protected_bkpt.GetID()
unprotected_bkpt = self.target.BreakpointCreateByLocation(
self.main_file_spec, 10
)
unprotected_id = unprotected_bkpt.GetID()
success = protected_bkpt.AddNameWithErrorHandling(self.bp_name_string)
self.assertSuccess(success, "Couldn't add this name to the breakpoint")
self.target.DisableAllBreakpoints()
self.assertTrue(
protected_bkpt.IsEnabled(), "Didnt' keep breakpoint from being disabled"
)
self.assertFalse(
unprotected_bkpt.IsEnabled(),
"Protected too many breakpoints from disabling.",
)
# Try from the command line too:
unprotected_bkpt.SetEnabled(True)
result = lldb.SBCommandReturnObject()
self.dbg.GetCommandInterpreter().HandleCommand("break disable", result)
self.assertTrue(result.Succeeded())
self.assertTrue(
protected_bkpt.IsEnabled(), "Didnt' keep breakpoint from being disabled"
)
self.assertFalse(
unprotected_bkpt.IsEnabled(),
"Protected too many breakpoints from disabling.",
)
self.target.DeleteAllBreakpoints()
bkpt = self.target.FindBreakpointByID(protected_id)
self.assertTrue(
bkpt.IsValid(), "Didn't keep the breakpoint from being deleted."
)
bkpt = self.target.FindBreakpointByID(unprotected_id)
self.assertFalse(
bkpt.IsValid(), "Protected too many breakpoints from deletion."
)
# Remake the unprotected breakpoint and try again from the command line:
unprotected_bkpt = self.target.BreakpointCreateByLocation(
self.main_file_spec, 10
)
unprotected_id = unprotected_bkpt.GetID()
self.dbg.GetCommandInterpreter().HandleCommand("break delete -f", result)
self.assertTrue(result.Succeeded())
bkpt = self.target.FindBreakpointByID(protected_id)
self.assertTrue(
bkpt.IsValid(), "Didn't keep the breakpoint from being deleted."
)
bkpt = self.target.FindBreakpointByID(unprotected_id)
self.assertFalse(
bkpt.IsValid(), "Protected too many breakpoints from deletion."
)
def do_check_configuring_permissions_sb(self):
bp_name = lldb.SBBreakpointName(self.target, self.bp_name_string)
# Make a breakpoint name with delete disallowed:
bp_name = lldb.SBBreakpointName(self.target, self.bp_name_string)
self.assertTrue(
bp_name.IsValid(), "Failed to make breakpoint name for valid name."
)
bp_name.SetAllowDelete(False)
bp_name.SetAllowDisable(False)
bp_name.SetAllowList(False)
self.check_permission_results(bp_name)
def do_check_configuring_permissions_cli(self):
# Make the name with the right options using the command line:
self.runCmd(
"breakpoint name configure -L 0 -D 0 -A 0 %s" % (self.bp_name_string),
check=True,
)
# Now look up the breakpoint we made, and check that it works.
bp_name = lldb.SBBreakpointName(self.target, self.bp_name_string)
self.assertTrue(
bp_name.IsValid(), "Didn't make a breakpoint name we could find."
)
self.check_permission_results(bp_name)