blob: 21002513ae342db12afcc76f77cea2fa28bda033 [file]
//===-- 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);
}