jingham created this revision. jingham added a reviewer: teemperor. Herald added subscribers: lldb-commits, JDevlieghere. Herald added a project: LLDB.
This allows you to use "break read" and "break write" for scripted breakpoints. This is the test Raphael was offering to have Jan write in, plus the code to support it: https://reviews.llvm.org/D68638 Repository: rLLDB LLDB https://reviews.llvm.org/D68750 Files: lldb/include/lldb/Breakpoint/BreakpointResolverScripted.h lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/TestBreakpointSerialization.py lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/resolver.py lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/side_effect.py lldb/source/Breakpoint/BreakpointResolver.cpp lldb/source/Breakpoint/BreakpointResolverScripted.cpp lldb/source/Target/Target.cpp
Index: lldb/source/Target/Target.cpp =================================================================== --- lldb/source/Target/Target.cpp +++ lldb/source/Target/Target.cpp @@ -609,8 +609,7 @@ extra_args_impl->SetObjectSP(extra_args_sp); BreakpointResolverSP resolver_sp(new BreakpointResolverScripted( - nullptr, class_name, depth, extra_args_impl, - *GetDebugger().GetScriptInterpreter())); + nullptr, class_name, depth, extra_args_impl)); return CreateBreakpoint(filter_sp, resolver_sp, internal, false, true); } Index: lldb/source/Breakpoint/BreakpointResolverScripted.cpp =================================================================== --- lldb/source/Breakpoint/BreakpointResolverScripted.cpp +++ lldb/source/Breakpoint/BreakpointResolverScripted.cpp @@ -29,8 +29,7 @@ Breakpoint *bkpt, const llvm::StringRef class_name, lldb::SearchDepth depth, - StructuredDataImpl *args_data, - ScriptInterpreter &script_interp) + StructuredDataImpl *args_data) : BreakpointResolver(bkpt, BreakpointResolver::PythonResolver), m_class_name(class_name), m_depth(depth), m_args_ptr(args_data) { CreateImplementationIfNeeded(); @@ -68,45 +67,25 @@ llvm::StringRef class_name; bool success; - if (!bkpt) - return nullptr; - success = options_dict.GetValueForKeyAsString( GetKey(OptionNames::PythonClassName), class_name); if (!success) { error.SetErrorString("BRFL::CFSD: Couldn't find class name entry."); return nullptr; } - lldb::SearchDepth depth; - int depth_as_int; - success = options_dict.GetValueForKeyAsInteger( - GetKey(OptionNames::SearchDepth), depth_as_int); - if (!success) { - error.SetErrorString("BRFL::CFSD: Couldn't find class name entry."); - return nullptr; - } - if (depth_as_int >= (int) OptionNames::LastOptionName) { - error.SetErrorString("BRFL::CFSD: Invalid value for search depth."); - return nullptr; - } - depth = (lldb::SearchDepth) depth_as_int; + // The Python function will actually provide the search depth, this is a + // placeholder. + lldb::SearchDepth depth = lldb::eSearchDepthTarget; StructuredDataImpl *args_data_impl = new StructuredDataImpl(); StructuredData::Dictionary *args_dict = nullptr; success = options_dict.GetValueForKeyAsDictionary( GetKey(OptionNames::ScriptArgs), args_dict); if (success) { - // FIXME: The resolver needs a copy of the ARGS dict that it can own, - // so I need to make a copy constructor for the Dictionary so I can pass - // that to it here. For now the args are empty. - //StructuredData::Dictionary *dict_copy = new StructuredData::Dictionary(args_dict); - + args_data_impl->SetObjectSP(args_dict->shared_from_this()); } - ScriptInterpreter *script_interp = bkpt->GetTarget() - .GetDebugger() - .GetScriptInterpreter(); - return new BreakpointResolverScripted(bkpt, class_name, depth, args_data_impl, - *script_interp); + return new BreakpointResolverScripted(bkpt, class_name, depth, + args_data_impl); } StructuredData::ObjectSP @@ -116,6 +95,10 @@ options_dict_sp->AddStringItem(GetKey(OptionNames::PythonClassName), m_class_name); + if (m_args_ptr->IsValid()) + options_dict_sp->AddItem(GetKey(OptionNames::ScriptArgs), + m_args_ptr->GetObjectSP()); + return WrapOptionsDict(options_dict_sp); } @@ -173,11 +156,10 @@ lldb::BreakpointResolverSP BreakpointResolverScripted::CopyForBreakpoint(Breakpoint &breakpoint) { - ScriptInterpreter *script_interp = GetScriptInterpreter(); // FIXME: Have to make a copy of the arguments from the m_args_ptr and then // pass that to the new resolver. lldb::BreakpointResolverSP ret_sp( - new BreakpointResolverScripted(&breakpoint, m_class_name, - m_depth, nullptr, *script_interp)); + new BreakpointResolverScripted(&breakpoint, m_class_name, m_depth, + nullptr)); return ret_sp; } Index: lldb/source/Breakpoint/BreakpointResolver.cpp =================================================================== --- lldb/source/Breakpoint/BreakpointResolver.cpp +++ lldb/source/Breakpoint/BreakpointResolver.cpp @@ -34,7 +34,8 @@ // BreakpointResolver: const char *BreakpointResolver::g_ty_to_name[] = {"FileAndLine", "Address", "SymbolName", "SourceRegex", - "Exception", "Unknown"}; + "Python", "Exception", + "Unknown"}; const char *BreakpointResolver::g_option_names[static_cast<uint32_t>( BreakpointResolver::OptionNames::LastOptionName)] = { Index: lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/side_effect.py =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/side_effect.py @@ -0,0 +1 @@ +g_extra_args = None Index: lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/resolver.py =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/resolver.py @@ -0,0 +1,17 @@ +import lldb +import side_effect + +class Resolver: + """This resolver class is just so I can read out the extra_args.""" + + def __init__(self, bkpt, extra_args, dict): + self.bkpt = bkpt + side_effect.g_extra_args = extra_args + + def __callback__(self, sym_ctx): + """Doesn't actually do anything.""" + return + + def get_short_help(self): + return "I am a python breakpoint resolver that does nothing" + Index: lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/TestBreakpointSerialization.py =================================================================== --- lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/TestBreakpointSerialization.py +++ lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/TestBreakpointSerialization.py @@ -47,7 +47,12 @@ self.build() self.setup_targets_and_cleanup() self.do_check_names() - + + def test_scripted_extra_args(self): + self.build() + self.setup_targets_and_cleanup() + self.do_check_extra_args() + def setup_targets_and_cleanup(self): def cleanup (): self.RemoveTempFile(self.bkpts_file_path) @@ -289,3 +294,85 @@ error = self.copy_target.BreakpointsCreateFromFile(self.bkpts_file_spec, names_list, copy_bps) self.assertTrue(error.Success(), "Failed reading breakpoints from file: %s"%(error.GetCString())) self.assertTrue(copy_bps.GetSize() == 1, "Found the matching breakpoint.") + + def do_check_extra_args(self): + + import side_effect + interp = self.dbg.GetCommandInterpreter() + error = lldb.SBError() + + script_name = os.path.join(self.getSourceDir(), "resolver.py") + + command = "command script import " + script_name + result = lldb.SBCommandReturnObject() + interp.HandleCommand(command, result) + self.assertTrue(result.Succeeded(), "com scr imp failed: %s"%(result.GetError())) + + # First make sure a scripted breakpoint with no args works: + bkpt = self.orig_target.BreakpointCreateFromScript("resolver.Resolver", lldb.SBStructuredData(), + lldb.SBFileSpecList(), lldb.SBFileSpecList()) + self.assertTrue(bkpt.IsValid(), "Bkpt is valid") + write_bps = lldb.SBBreakpointList(self.orig_target) + + error = self.orig_target.BreakpointsWriteToFile(self.bkpts_file_spec, write_bps) + self.assertTrue(error.Success(), "Failed writing breakpoints: %s"%(error.GetCString())) + + side_effect.g_extra_args = None + copy_bps = lldb.SBBreakpointList(self.copy_target) + error = self.copy_target.BreakpointsCreateFromFile(self.bkpts_file_spec, copy_bps) + self.assertTrue(error.Success(), "Failed reading breakpoints: %s"%(error.GetCString())) + + self.assertEqual(copy_bps.GetSize(), 1, "Got one breakpoint from file.") + no_keys = lldb.SBStringList() + side_effect.g_extra_args.GetKeys(no_keys) + self.assertEqual(no_keys.GetSize(), 0, "Should have no keys") + + self.orig_target.DeleteAllBreakpoints() + self.copy_target.DeleteAllBreakpoints() + + # Now try one with extra args: + + extra_args = lldb.SBStructuredData() + stream = lldb.SBStream() + stream.Print('{"first_arg" : "first_value", "second_arg" : "second_value"}') + extra_args.SetFromJSON(stream) + self.assertTrue(extra_args.IsValid(), "SBStructuredData is valid.") + + bkpt = self.orig_target.BreakpointCreateFromScript("resolver.Resolver", + extra_args, lldb.SBFileSpecList(), lldb.SBFileSpecList()) + self.assertTrue(bkpt.IsValid(), "Bkpt is valid") + write_bps = lldb.SBBreakpointList(self.orig_target) + + error = self.orig_target.BreakpointsWriteToFile(self.bkpts_file_spec, write_bps) + self.assertTrue(error.Success(), "Failed writing breakpoints: %s"%(error.GetCString())) + + orig_extra_args = side_effect.g_extra_args + self.assertTrue(orig_extra_args.IsValid(), "Extra args originally valid") + + orig_keys = lldb.SBStringList() + orig_extra_args.GetKeys(orig_keys) + self.assertEqual(2, orig_keys.GetSize(), "Should have two keys") + + side_effect.g_extra_args = None + + copy_bps = lldb.SBBreakpointList(self.copy_target) + error = self.copy_target.BreakpointsCreateFromFile(self.bkpts_file_spec, copy_bps) + self.assertTrue(error.Success(), "Failed reading breakpoints: %s"%(error.GetCString())) + + self.assertEqual(copy_bps.GetSize(), 1, "Got one breakpoint from file.") + + copy_extra_args = side_effect.g_extra_args + copy_keys = lldb.SBStringList() + copy_extra_args.GetKeys(copy_keys) + self.assertEqual(2, copy_keys.GetSize(), "Copy should have two keys") + + for idx in range(0, orig_keys.GetSize()): + key = orig_keys.GetStringAtIndex(idx) + copy_value = copy_extra_args.GetValueForKey(key).GetStringValue(100) + + if key == "first_arg": + self.assertEqual(copy_value, "first_value") + elif key == "second_arg": + self.assertEqual(copy_value, "second_value") + else: + self.Fail("Unknown key: %s"%(key)) Index: lldb/include/lldb/Breakpoint/BreakpointResolverScripted.h =================================================================== --- lldb/include/lldb/Breakpoint/BreakpointResolverScripted.h +++ lldb/include/lldb/Breakpoint/BreakpointResolverScripted.h @@ -26,8 +26,7 @@ BreakpointResolverScripted(Breakpoint *bkpt, const llvm::StringRef class_name, lldb::SearchDepth depth, - StructuredDataImpl *args_data, - ScriptInterpreter &script_interp); + StructuredDataImpl *args_data); ~BreakpointResolverScripted() override;
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits