| //===-- 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); | |
| } |