| //===-- BreakpointResolverScripted.cpp ------------------------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "lldb/Breakpoint/BreakpointResolverScripted.h" | |
| #include "lldb/Breakpoint/BreakpointLocation.h" | |
| #include "lldb/Core/Debugger.h" | |
| #include "lldb/Core/Module.h" | |
| #include "lldb/Core/Section.h" | |
| #include "lldb/Core/StructuredDataImpl.h" | |
| #include "lldb/Interpreter/CommandInterpreter.h" | |
| #include "lldb/Interpreter/ScriptInterpreter.h" | |
| #include "lldb/Target/Process.h" | |
| #include "lldb/Target/Target.h" | |
| #include "lldb/Utility/Log.h" | |
| #include "lldb/Utility/StreamString.h" | |
| #include "llvm/Support/FormatVariadic.h" | |
| using namespace lldb; | |
| using namespace lldb_private; | |
| // BreakpointResolverScripted: | |
| BreakpointResolverScripted::BreakpointResolverScripted( | |
| const BreakpointSP &bkpt, const llvm::StringRef class_name, | |
| lldb::SearchDepth depth, const StructuredDataImpl &args_data) | |
| : BreakpointResolver(bkpt, BreakpointResolver::PythonResolver), | |
| m_class_name(std::string(class_name)), m_depth(depth), m_args(args_data) { | |
| if (bkpt) | |
| CreateImplementationIfNeeded(bkpt); | |
| } | |
| void BreakpointResolverScripted::CreateImplementationIfNeeded( | |
| BreakpointSP breakpoint_sp) { | |
| // This version has to be called with a valid breakpoint_sp | |
| // But the interface might have been made before we sent the breakpoint to | |
| // the interface. If so, do that here: | |
| assert(breakpoint_sp); | |
| if (m_interface_sp) { | |
| if (!m_breakpoint_sent) { | |
| m_interface_sp->SetBreakpoint(breakpoint_sp); | |
| m_breakpoint_sent = true; | |
| } | |
| return; | |
| } | |
| if (m_class_name.empty()) | |
| return; | |
| if (!breakpoint_sp) | |
| return; | |
| TargetSP target_sp = breakpoint_sp->GetTargetSP(); | |
| if (target_sp) | |
| CreateImplementationIfNeeded(*target_sp.get(), breakpoint_sp); | |
| } | |
| void BreakpointResolverScripted::CreateImplementationIfNeeded( | |
| Target &target, BreakpointSP breakpoint_sp) { | |
| if (m_interface_sp) { | |
| if (!m_breakpoint_sent && breakpoint_sp) { | |
| m_interface_sp->SetBreakpoint(breakpoint_sp); | |
| m_breakpoint_sent = true; | |
| } | |
| return; | |
| } | |
| ScriptInterpreter *script_interp = | |
| target.GetDebugger().GetScriptInterpreter(); | |
| if (!script_interp) | |
| return; | |
| if (!m_interface_sp) | |
| m_interface_sp = script_interp->CreateScriptedBreakpointInterface(); | |
| if (!m_interface_sp) { | |
| m_error = Status::FromErrorStringWithFormat( | |
| "BreakpointResolverScripted::%s () - ERROR: %s", __FUNCTION__, | |
| "Script interpreter couldn't create Scripted Breakpoint Interface"); | |
| return; | |
| } | |
| StructuredData::ObjectSP args_obj = m_args.GetObjectSP(); | |
| StructuredData::DictionarySP args_dict_sp; | |
| if (args_obj && args_obj->GetType() == lldb::eStructuredDataTypeDictionary) | |
| args_dict_sp = | |
| std::static_pointer_cast<StructuredData::Dictionary>(args_obj); | |
| ScriptedMetadata scripted_metadata(m_class_name, args_dict_sp); | |
| auto obj_or_err = | |
| m_interface_sp->CreatePluginObject(scripted_metadata, breakpoint_sp); | |
| if (!obj_or_err) { | |
| m_interface_sp.reset(); | |
| std::string msg = llvm::toString(obj_or_err.takeError()); | |
| Debugger::ReportError( | |
| llvm::formatv("failed to create BreakpointResolverScripted: {0}", msg) | |
| .str(), | |
| target.GetDebugger().GetID()); | |
| m_error = Status(msg); | |
| return; | |
| } | |
| StructuredData::ObjectSP object_sp = *obj_or_err; | |
| if (!object_sp || !object_sp->IsValid()) { | |
| m_error = Status::FromErrorStringWithFormat( | |
| "ScriptedBreakpoint::%s () - ERROR: %s", __FUNCTION__, | |
| "Failed to create valid script object"); | |
| } | |
| if (breakpoint_sp) | |
| m_breakpoint_sent = true; | |
| } | |
| bool BreakpointResolverScripted::OverridesResolver( | |
| Target &target, BreakpointResolverSP original_sp) { | |
| // At this point neither resolver has been assigned a breakpoint, so pass | |
| // in an empty one. | |
| CreateImplementationIfNeeded(target, {}); | |
| if (!m_interface_sp) | |
| return false; | |
| StructuredData::ObjectSP serialized_sp = | |
| original_sp->SerializeToStructuredData(); | |
| StructuredDataImpl impl(serialized_sp); | |
| return m_interface_sp->OverridesResolver(target, impl); | |
| } | |
| void BreakpointResolverScripted::NotifyBreakpointSet() { | |
| CreateImplementationIfNeeded(GetBreakpoint()); | |
| } | |
| BreakpointResolverSP BreakpointResolverScripted::CreateFromStructuredData( | |
| const StructuredData::Dictionary &options_dict, Status &error) { | |
| llvm::StringRef class_name; | |
| bool success; | |
| success = options_dict.GetValueForKeyAsString( | |
| GetKey(OptionNames::PythonClassName), class_name); | |
| if (!success) { | |
| error = | |
| Status::FromErrorString("BRFL::CFSD: Couldn't find class name entry."); | |
| return nullptr; | |
| } | |
| // The Python function will actually provide the search depth, this is a | |
| // placeholder. | |
| lldb::SearchDepth depth = lldb::eSearchDepthTarget; | |
| StructuredDataImpl args_data_impl; | |
| StructuredData::Dictionary *args_dict = nullptr; | |
| if (options_dict.GetValueForKeyAsDictionary(GetKey(OptionNames::ScriptArgs), | |
| args_dict)) | |
| args_data_impl.SetObjectSP(args_dict->shared_from_this()); | |
| return std::make_shared<BreakpointResolverScripted>(nullptr, class_name, | |
| depth, args_data_impl); | |
| } | |
| StructuredData::ObjectSP | |
| BreakpointResolverScripted::SerializeToStructuredData() { | |
| StructuredData::DictionarySP options_dict_sp( | |
| new StructuredData::Dictionary()); | |
| options_dict_sp->AddStringItem(GetKey(OptionNames::PythonClassName), | |
| m_class_name); | |
| if (m_args.IsValid()) | |
| options_dict_sp->AddItem(GetKey(OptionNames::ScriptArgs), | |
| m_args.GetObjectSP()); | |
| return WrapOptionsDict(options_dict_sp); | |
| } | |
| ScriptInterpreter *BreakpointResolverScripted::GetScriptInterpreter() { | |
| return GetBreakpoint()->GetTarget().GetDebugger().GetScriptInterpreter(); | |
| } | |
| Searcher::CallbackReturn BreakpointResolverScripted::SearchCallback( | |
| SearchFilter &filter, SymbolContext &context, Address *addr) { | |
| bool should_continue = true; | |
| if (!m_interface_sp) | |
| return Searcher::eCallbackReturnStop; | |
| should_continue = m_interface_sp->ResolverCallback(context); | |
| if (should_continue) | |
| return Searcher::eCallbackReturnContinue; | |
| return Searcher::eCallbackReturnStop; | |
| } | |
| lldb::SearchDepth | |
| BreakpointResolverScripted::GetDepth() { | |
| lldb::SearchDepth depth = lldb::eSearchDepthModule; | |
| if (m_interface_sp) | |
| depth = m_interface_sp->GetDepth(); | |
| return depth; | |
| } | |
| void BreakpointResolverScripted::GetDescription(Stream *s) { | |
| StructuredData::GenericSP generic_sp; | |
| std::optional<std::string> short_help; | |
| CreateImplementationIfNeeded(GetBreakpoint()); | |
| if (m_interface_sp) { | |
| short_help = m_interface_sp->GetShortHelp(); | |
| } | |
| if (short_help && !short_help->empty()) | |
| s->PutCString(short_help->c_str()); | |
| else | |
| s->Printf("python class = %s", m_class_name.c_str()); | |
| } | |
| std::optional<std::string> BreakpointResolverScripted::GetLocationDescription( | |
| lldb::BreakpointLocationSP bp_loc_sp, lldb::DescriptionLevel level) { | |
| CreateImplementationIfNeeded(GetBreakpoint()); | |
| if (m_interface_sp) | |
| return m_interface_sp->GetLocationDescription(bp_loc_sp, level); | |
| return {}; | |
| } | |
| lldb::BreakpointLocationSP | |
| BreakpointResolverScripted::WasHit(lldb::StackFrameSP frame_sp, | |
| lldb::BreakpointLocationSP bp_loc_sp) { | |
| if (m_interface_sp) | |
| return m_interface_sp->WasHit(frame_sp, bp_loc_sp); | |
| return {}; | |
| } | |
| void BreakpointResolverScripted::Dump(Stream *s) const {} | |
| lldb::BreakpointResolverSP | |
| BreakpointResolverScripted::CopyForBreakpoint(BreakpointSP &breakpoint) { | |
| return std::make_shared<BreakpointResolverScripted>(breakpoint, m_class_name, | |
| m_depth, m_args); | |
| } |