"""
Test setting breakpoints using a scripted resolver
"""
import os
import lldb
import lldbsuite.test.lldbutil as lldbutil
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
class TestScriptedResolver(TestBase):
NO_DEBUG_INFO_TESTCASE = True
@expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24528")
def test_scripted_resolver(self):
"""Use a scripted resolver to set a by symbol name breakpoint"""
self.build()
self.do_test()
@expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24528")
def test_search_depths(self):
"""Make sure we are called at the right depths depending on what we return
from __get_depth__"""
self.build()
self.do_test_depths()
@expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24528")
def test_command_line(self):
"""Test setting a resolver breakpoint from the command line"""
self.build()
self.do_test_cli()
def test_bad_command_lines(self):
"""Make sure we get appropriate errors when we give invalid key/value
options"""
self.build()
self.do_test_bad_options()
def test_copy_from_dummy_target(self):
"""Make sure we don't crash during scripted breakpoint copy from dummy target"""
self.build()
self.do_test_copy_from_dummy_target()
def make_target_and_import(self):
target = self.make_target()
self.import_resolver_script()
return target
def make_target(self):
return lldbutil.run_to_breakpoint_make_target(self)
def import_resolver_script(self):
interp = self.dbg.GetCommandInterpreter()
error = lldb.SBError()
script_name = os.path.join(self.getSourceDir(), "resolver.py")
source_name = os.path.join(self.getSourceDir(), "main.c")
command = "command script import " + script_name
result = lldb.SBCommandReturnObject()
interp.HandleCommand(command, result)
self.assertTrue(
result.Succeeded(), "com scr imp failed: %s" % (result.GetError())
)
def make_extra_args(self):
json_string = '{"symbol":"break_on_me", "test1": "value1"}'
json_stream = lldb.SBStream()
json_stream.Print(json_string)
extra_args = lldb.SBStructuredData()
error = extra_args.SetFromJSON(json_stream)
self.assertSuccess(error, "Error making SBStructuredData")
return extra_args
def do_test(self):
"""This reads in a python file and sets a breakpoint using it."""
target = self.make_target_and_import()
extra_args = self.make_extra_args()
file_list = lldb.SBFileSpecList()
module_list = lldb.SBFileSpecList()
right = []
right.append(
target.BreakpointCreateFromScript(
"resolver.Resolver", extra_args, module_list, file_list
)
)
file_list.Append(lldb.SBFileSpec("main.c"))
right.append(
target.BreakpointCreateFromScript(
"resolver.Resolver", extra_args, module_list, file_list
)
)
self.expect(
"break list",
substrs=["I am a python breakpoint resolver"],
msg="Help is listed in break list",
)
module_list.Append(lldb.SBFileSpec("a.out"))
right.append(
target.BreakpointCreateFromScript(
"resolver.Resolver", extra_args, module_list, file_list
)
)
file_list.Clear()
right.append(
target.BreakpointCreateFromScript(
"resolver.Resolver", extra_args, module_list, file_list
)
)
for i in range(0, len(right)):
self.assertGreaterEqual(
right[i].GetNumLocations(), 1, "Breakpoint %d has no locations." % (i)
)
module_list.Clear()
file_list.Clear()
wrong = []
module_list.Append(lldb.SBFileSpec("noSuchModule"))
wrong.append(
target.BreakpointCreateFromScript(
"resolver.Resolver", extra_args, module_list, file_list
)
)
file_list.Clear()
module_list.Clear()
file_list.Append(lldb.SBFileSpec("noFileOfThisName.xxx"))
wrong.append(
target.BreakpointCreateFromScript(
"resolver.Resolver", extra_args, module_list, file_list
)
)
file_list.Clear()
module_list.Clear()
file_list.Append(lldb.SBFileSpec("no_such_file.xxx"))
wrong.append(
target.BreakpointCreateFromScript(
"resolver.ResolverCUDepth", extra_args, module_list, file_list
)
)
file_list.Clear()
module_list.Clear()
module_list.Append(lldb.SBFileSpec("NoSuchModule.dylib"))
wrong.append(
target.BreakpointCreateFromScript(
"resolver.ResolverCUDepth", extra_args, module_list, file_list
)
)
file_list.Clear()
module_list.Clear()
file_list.Append(lldb.SBFileSpec("no_such_file.xxx"))
wrong.append(
target.BreakpointCreateFromScript(
"resolver.ResolverFuncDepth", extra_args, module_list, file_list
)
)
file_list.Clear()
module_list.Clear()
module_list.Append(lldb.SBFileSpec("NoSuchModule.dylib"))
wrong.append(
target.BreakpointCreateFromScript(
"resolver.ResolverFuncDepth", extra_args, module_list, file_list
)
)
for i in range(0, len(wrong)):
self.assertEqual(
wrong[i].GetNumLocations(), 0, "Breakpoint %d has locations." % (i)
)
lldbutil.run_to_breakpoint_do_run(self, target, right[0])
for i in range(0, len(right)):
self.assertEqual(
right[i].GetHitCount(), 1, "Breakpoint %d has the wrong hit count" % (i)
)
for i in range(0, len(wrong)):
self.assertEqual(
wrong[i].GetHitCount(), 0, "Breakpoint %d has the wrong hit count" % (i)
)
def do_test_depths(self):
"""This test uses a class variable in resolver.Resolver which gets set to 1 if we saw
compile unit and 2 if we only saw modules. If the search depth is module, you get passed just
the modules with no comp_unit. If the depth is comp_unit you get comp_units. So we can use
this to test that our callback gets called at the right depth."""
target = self.make_target_and_import()
extra_args = self.make_extra_args()
file_list = lldb.SBFileSpecList()
module_list = lldb.SBFileSpecList()
module_list.Append(lldb.SBFileSpec("a.out"))
bkpt = target.BreakpointCreateFromScript(
"resolver.Resolver", extra_args, module_list, file_list
)
self.assertGreater(bkpt.GetNumLocations(), 0, "Resolver got no locations.")
self.expect(
"script print(resolver.Resolver.got_files)",
substrs=["2"],
msg="Was only passed modules",
)
bkpt = target.BreakpointCreateFromScript(
"resolver.ResolverModuleDepth", extra_args, module_list, file_list
)
self.assertGreater(
bkpt.GetNumLocations(), 0, "ResolverModuleDepth got no locations."
)
self.expect(
"script print(resolver.Resolver.got_files)",
substrs=["2"],
msg="Was only passed modules",
)
bkpt = target.BreakpointCreateFromScript(
"resolver.ResolverCUDepth", extra_args, module_list, file_list
)
self.assertGreater(
bkpt.GetNumLocations(), 0, "ResolverCUDepth got no locations."
)
self.expect(
"script print(resolver.Resolver.got_files)",
substrs=["1"],
msg="Was passed compile units",
)
bkpt = target.BreakpointCreateFromScript(
"resolver.ResolverBadDepth", extra_args, module_list, file_list
)
self.assertGreater(
bkpt.GetNumLocations(), 0, "ResolverBadDepth got no locations."
)
self.expect(
"script print(resolver.Resolver.got_files)",
substrs=["2"],
msg="Was only passed modules",
)
bkpt = target.BreakpointCreateFromScript(
"resolver.ResolverFuncDepth", extra_args, module_list, file_list
)
self.assertGreater(
bkpt.GetNumLocations(), 0, "ResolverFuncDepth got no locations."
)
self.expect(
"script print(resolver.Resolver.got_files)",
substrs=["3"],
msg="Was only passed modules",
)
self.expect(
"script print(resolver.Resolver.func_list)",
substrs=["test_func", "break_on_me", "main"],
msg="Saw all the functions",
)
def do_test_cli(self):
target = self.make_target_and_import()
lldbutil.run_break_set_by_script(
self, "resolver.Resolver", extra_options="-k symbol -v break_on_me"
)
bkpt_no = lldbutil.run_break_set_by_file_and_line(self, "main.c", 12)
bkpt = target.FindBreakpointByID(bkpt_no)
strm = lldb.SBStream()
bkpt.GetDescription(strm, False)
used_resolver = "I am a python breakpoint resolver" in strm.GetData()
self.assertFalse(
used_resolver,
"Found the resolver description in the file & line breakpoint description.",
)
bp_loc = bkpt.GetLocationAtIndex(0)
bp_sc = bp_loc.GetAddress().GetSymbolContext(lldb.eSymbolContextEverything)
bp_se = bp_sc.GetLineEntry()
self.assertEqual(bp_se.GetLine(), 12, "Got the right line number")
self.assertEqual(
bp_se.GetFileSpec().GetFilename(), "main.c", "Got the right filename"
)
def do_test_bad_options(self):
target = self.make_target_and_import()
self.expect(
"break set -P resolver.Resolver -k a_key",
error=True,
msg="Missing value at end",
substrs=['Key: "a_key" missing value'],
)
self.expect(
"break set -P resolver.Resolver -v a_value",
error=True,
msg="Missing key at end",
substrs=['Value: "a_value" missing matching key'],
)
self.expect(
"break set -P resolver.Resolver -v a_value -k a_key -v another_value",
error=True,
msg="Missing key among args",
substrs=['Value: "a_value" missing matching key'],
)
self.expect(
"break set -P resolver.Resolver -k a_key -k a_key -v another_value",
error=True,
msg="Missing value among args",
substrs=['Key: "a_key" missing value'],
)
def do_test_copy_from_dummy_target(self):
self.import_resolver_script()
self.runCmd(
"breakpoint set -P resolver.Resolver -k symbol -v break_on_me",
BREAKPOINT_CREATED,
)
def cleanup():
self.runCmd("breakpoint delete -D -f", check=False)
self.runCmd("breakpoint list", check=False)
self.addTearDownHook(cleanup)
target = self.make_target()