257 lines
12 KiB
Python
257 lines
12 KiB
Python
"""
|
|
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):
|
|
|
|
mydir = TestBase.compute_mydir(__file__)
|
|
|
|
NO_DEBUG_INFO_TESTCASE = True
|
|
|
|
@expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24528")
|
|
@skipIfReproducer # FIXME: Unexpected packet during (active) replay
|
|
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.assertTrue(error.Success(), "Error making SBStructuredData: %s"%(error.GetCString()))
|
|
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()
|
|
|
|
# Make breakpoints with this resolver using different filters, first ones that will take:
|
|
right = []
|
|
# one with no file or module spec - this one should fire:
|
|
right.append(target.BreakpointCreateFromScript("resolver.Resolver", extra_args, module_list, file_list))
|
|
|
|
# one with the right source file and no module - should also fire:
|
|
file_list.Append(lldb.SBFileSpec("main.c"))
|
|
right.append(target.BreakpointCreateFromScript("resolver.Resolver", extra_args, module_list, file_list))
|
|
# Make sure the help text shows up in the "break list" output:
|
|
self.expect("break list", substrs=["I am a python breakpoint resolver"], msg="Help is listed in break list")
|
|
|
|
# one with the right source file and right module - should also fire:
|
|
module_list.Append(lldb.SBFileSpec("a.out"))
|
|
right.append(target.BreakpointCreateFromScript("resolver.Resolver", extra_args, module_list, file_list))
|
|
|
|
# And one with no source file but the right module:
|
|
file_list.Clear()
|
|
right.append(target.BreakpointCreateFromScript("resolver.Resolver", extra_args, module_list, file_list))
|
|
|
|
# Make sure these all got locations:
|
|
for i in range (0, len(right)):
|
|
self.assertTrue(right[i].GetNumLocations() >= 1, "Breakpoint %d has no locations."%(i))
|
|
|
|
# Now some ones that won't take:
|
|
|
|
module_list.Clear()
|
|
file_list.Clear()
|
|
wrong = []
|
|
|
|
# one with the wrong module - should not fire:
|
|
module_list.Append(lldb.SBFileSpec("noSuchModule"))
|
|
wrong.append(target.BreakpointCreateFromScript("resolver.Resolver", extra_args, module_list, file_list))
|
|
|
|
# one with the wrong file - also should not fire:
|
|
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))
|
|
|
|
# Now make sure the CU level iteration obeys the file filters:
|
|
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))
|
|
|
|
# And the Module filters:
|
|
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))
|
|
|
|
# Now make sure the Function level iteration obeys the file filters:
|
|
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))
|
|
|
|
# And the Module filters:
|
|
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))
|
|
|
|
# Make sure these didn't get locations:
|
|
for i in range(0, len(wrong)):
|
|
self.assertEqual(wrong[i].GetNumLocations(), 0, "Breakpoint %d has locations."%(i))
|
|
|
|
# Now run to main and ensure we hit the breakpoints we should have:
|
|
|
|
lldbutil.run_to_breakpoint_do_run(self, target, right[0])
|
|
|
|
# Test the hit counts:
|
|
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"))
|
|
|
|
# Make a breakpoint that has no __get_depth__, check that that is converted to eSearchDepthModule:
|
|
bkpt = target.BreakpointCreateFromScript("resolver.Resolver", extra_args, module_list, file_list)
|
|
self.assertTrue(bkpt.GetNumLocations() > 0, "Resolver got no locations.")
|
|
self.expect("script print(resolver.Resolver.got_files)", substrs=["2"], msg="Was only passed modules")
|
|
|
|
# Make a breakpoint that asks for modules, check that we didn't get any files:
|
|
bkpt = target.BreakpointCreateFromScript("resolver.ResolverModuleDepth", extra_args, module_list, file_list)
|
|
self.assertTrue(bkpt.GetNumLocations() > 0, "ResolverModuleDepth got no locations.")
|
|
self.expect("script print(resolver.Resolver.got_files)", substrs=["2"], msg="Was only passed modules")
|
|
|
|
# Make a breakpoint that asks for compile units, check that we didn't get any files:
|
|
bkpt = target.BreakpointCreateFromScript("resolver.ResolverCUDepth", extra_args, module_list, file_list)
|
|
self.assertTrue(bkpt.GetNumLocations() > 0, "ResolverCUDepth got no locations.")
|
|
self.expect("script print(resolver.Resolver.got_files)", substrs=["1"], msg="Was passed compile units")
|
|
|
|
# Make a breakpoint that returns a bad value - we should convert that to "modules" so check that:
|
|
bkpt = target.BreakpointCreateFromScript("resolver.ResolverBadDepth", extra_args, module_list, file_list)
|
|
self.assertTrue(bkpt.GetNumLocations() > 0, "ResolverBadDepth got no locations.")
|
|
self.expect("script print(resolver.Resolver.got_files)", substrs=["2"], msg="Was only passed modules")
|
|
|
|
# Make a breakpoint that searches at function depth:
|
|
bkpt = target.BreakpointCreateFromScript("resolver.ResolverFuncDepth", extra_args, module_list, file_list)
|
|
self.assertTrue(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")
|
|
|
|
# Make sure setting a resolver breakpoint doesn't pollute further breakpoint setting
|
|
# by checking the description of a regular file & line breakpoint to make sure it
|
|
# doesn't mention the Python Resolver function:
|
|
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.")
|
|
|
|
# Also make sure the breakpoint was where we expected:
|
|
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):
|
|
# Import breakpoint scripted resolver.
|
|
self.import_resolver_script()
|
|
|
|
# Create a scripted breakpoint.
|
|
self.runCmd("breakpoint set -P resolver.Resolver -k symbol -v break_on_me",
|
|
BREAKPOINT_CREATED)
|
|
|
|
# This is the function to remove breakpoints from the dummy target
|
|
# to get a clean state for the next test case.
|
|
def cleanup():
|
|
self.runCmd('breakpoint delete -D -f', check=False)
|
|
self.runCmd('breakpoint list', check=False)
|
|
|
|
# Execute the cleanup function during test case tear down.
|
|
self.addTearDownHook(cleanup)
|
|
|
|
# Check that target creating doesn't crash.
|
|
target = self.make_target()
|