| //===-- ScriptedThreadPlanPythonInterface.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-python.h" |
| |
| #include "lldb/Core/PluginManager.h" |
| #include "lldb/Target/ThreadPlan.h" |
| #include "lldb/Utility/LLDBLog.h" |
| #include "lldb/Utility/Log.h" |
| #include "lldb/Utility/StreamString.h" |
| #include "lldb/lldb-enumerations.h" |
| |
| #include "../SWIGPythonBridge.h" |
| #include "../ScriptInterpreterPythonImpl.h" |
| #include "ScriptedThreadPlanPythonInterface.h" |
| |
| using namespace lldb; |
| using namespace lldb_private; |
| using namespace lldb_private::python; |
| |
| ScriptedThreadPlanPythonInterface::ScriptedThreadPlanPythonInterface( |
| ScriptInterpreterPythonImpl &interpreter) |
| : ScriptedThreadPlanInterface(), ScriptedPythonInterface(interpreter) {} |
| |
| llvm::Expected<StructuredData::GenericSP> |
| ScriptedThreadPlanPythonInterface::CreatePluginObject( |
| const ScriptedMetadata &scripted_metadata, |
| lldb::ThreadPlanSP thread_plan_sp) { |
| StructuredDataImpl args_sp(scripted_metadata.GetArgsSP()); |
| return ScriptedPythonInterface::CreatePluginObject(scripted_metadata, nullptr, |
| thread_plan_sp, args_sp); |
| } |
| |
| llvm::Expected<bool> |
| ScriptedThreadPlanPythonInterface::ExplainsStop(Event *event) { |
| llvm::Expected<std::optional<StructuredData::ObjectSP>> obj_or_err = |
| DispatchToOptional("explains_stop", event); |
| if (!obj_or_err) |
| return obj_or_err.takeError(); |
| |
| // Absent or None: the plan doesn't claim to explain the stop. |
| StructuredData::ObjectSP obj = obj_or_err->value_or(nullptr); |
| if (!obj || !obj->IsValid()) |
| return false; |
| |
| return obj->GetBooleanValue(); |
| } |
| |
| llvm::Expected<bool> |
| ScriptedThreadPlanPythonInterface::ShouldStop(Event *event) { |
| llvm::Expected<std::optional<StructuredData::ObjectSP>> obj_or_err = |
| DispatchToOptional("should_stop", event); |
| if (!obj_or_err) |
| return obj_or_err.takeError(); |
| |
| // Absent or None: the plan doesn't ask to stop. |
| StructuredData::ObjectSP obj = obj_or_err->value_or(nullptr); |
| if (!obj || !obj->IsValid()) |
| return false; |
| |
| return obj->GetBooleanValue(); |
| } |
| |
| llvm::Expected<bool> ScriptedThreadPlanPythonInterface::IsStale() { |
| llvm::Expected<std::optional<StructuredData::ObjectSP>> obj_or_err = |
| DispatchToOptional("is_stale"); |
| if (!obj_or_err) |
| return obj_or_err.takeError(); |
| |
| // Absent or None: assume the plan is still fresh. |
| StructuredData::ObjectSP obj = obj_or_err->value_or(nullptr); |
| if (!obj || !obj->IsValid()) |
| return false; |
| |
| return obj->GetBooleanValue(); |
| } |
| |
| llvm::Expected<lldb::StateType> |
| ScriptedThreadPlanPythonInterface::GetRunState() { |
| llvm::Expected<std::optional<StructuredData::ObjectSP>> obj_or_err = |
| DispatchToOptional("should_step"); |
| if (!obj_or_err) |
| return obj_or_err.takeError(); |
| |
| StructuredData::ObjectSP obj = obj_or_err->value_or(nullptr); |
| if (!obj || !obj->IsValid()) |
| return lldb::eStateStepping; |
| |
| // A thread plan's run state can formally be eStateSuspended, but that state |
| // is decided by the thread plan negotiation, not by the plan itself. So a |
| // scripted plan's contract is only running or stepping: a bool. |
| if (StructuredData::Boolean *should_step = obj->GetAsBoolean()) |
| return should_step->GetValue() ? lldb::eStateStepping : lldb::eStateRunning; |
| |
| if (Log *log = GetLog(LLDBLog::Script)) { |
| StreamString reply; |
| obj->Dump(reply, /*pretty_print=*/false); |
| LLDB_LOG(log, "should_step returned {0}, not a bool; stepping.", |
| reply.GetData()); |
| } |
| return lldb::eStateStepping; |
| } |
| |
| llvm::Error |
| ScriptedThreadPlanPythonInterface::GetStopDescription(lldb::StreamSP &stream) { |
| return DispatchToOptional("stop_description", stream).takeError(); |
| } |
| |
| void ScriptedThreadPlanPythonInterface::Initialize() { |
| const std::vector<llvm::StringRef> ci_usages = { |
| "thread step-scripted -C <script-name> [-k key -v value ...]"}; |
| const std::vector<llvm::StringRef> api_usages = { |
| "SBThread.StepUsingScriptedThreadPlan"}; |
| PluginManager::RegisterPlugin( |
| GetPluginNameStatic(), |
| llvm::StringRef("Alter thread stepping logic and stop reason"), |
| CreateInstance, eScriptedExtensionScriptedThreadPlan, |
| eScriptLanguagePython, {ci_usages, api_usages}); |
| } |
| |
| void ScriptedThreadPlanPythonInterface::Terminate() { |
| PluginManager::UnregisterPlugin(CreateInstance); |
| } |