Path: blob/main/contrib/llvm-project/lldb/source/Target/ScriptedThreadPlan.cpp
213764 views
//===-- ScriptedThreadPlan.cpp --------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "lldb/Target/ThreadPlan.h"910#include "lldb/Core/Debugger.h"11#include "lldb/Interpreter/CommandInterpreter.h"12#include "lldb/Interpreter/Interfaces/ScriptedThreadPlanInterface.h"13#include "lldb/Interpreter/ScriptInterpreter.h"14#include "lldb/Target/Process.h"15#include "lldb/Target/RegisterContext.h"16#include "lldb/Target/ScriptedThreadPlan.h"17#include "lldb/Target/Target.h"18#include "lldb/Target/Thread.h"19#include "lldb/Utility/LLDBLog.h"20#include "lldb/Utility/Log.h"21#include "lldb/Utility/State.h"2223using namespace lldb;24using namespace lldb_private;2526ScriptedThreadPlan::ScriptedThreadPlan(Thread &thread, const char *class_name,27const StructuredDataImpl &args_data)28: ThreadPlan(ThreadPlan::eKindPython, "Script based Thread Plan", thread,29eVoteNoOpinion, eVoteNoOpinion),30m_class_name(class_name), m_args_data(args_data), m_did_push(false),31m_stop_others(false) {32ScriptInterpreter *interpreter = GetScriptInterpreter();33if (!interpreter) {34SetPlanComplete(false);35// FIXME: error handling36// error = Status::FromErrorStringWithFormat(37// "ScriptedThreadPlan::%s () - ERROR: %s", __FUNCTION__,38// "Couldn't get script interpreter");39return;40}4142m_interface = interpreter->CreateScriptedThreadPlanInterface();43if (!m_interface) {44SetPlanComplete(false);45// FIXME: error handling46// error = Status::FromErrorStringWithFormat(47// "ScriptedThreadPlan::%s () - ERROR: %s", __FUNCTION__,48// "Script interpreter couldn't create Scripted Thread Plan Interface");49return;50}5152SetIsControllingPlan(true);53SetOkayToDiscard(true);54SetPrivate(false);55}5657bool ScriptedThreadPlan::ValidatePlan(Stream *error) {58if (!m_did_push)59return true;6061if (!m_implementation_sp) {62if (error)63error->Printf("Error constructing Python ThreadPlan: %s",64m_error_str.empty() ? "<unknown error>"65: m_error_str.c_str());66return false;67}6869return true;70}7172ScriptInterpreter *ScriptedThreadPlan::GetScriptInterpreter() {73return m_process.GetTarget().GetDebugger().GetScriptInterpreter();74}7576void ScriptedThreadPlan::DidPush() {77// We set up the script side in DidPush, so that it can push other plans in78// the constructor, and doesn't have to care about the details of DidPush.79m_did_push = true;80if (m_interface) {81auto obj_or_err = m_interface->CreatePluginObject(82m_class_name, this->shared_from_this(), m_args_data);83if (!obj_or_err) {84m_error_str = llvm::toString(obj_or_err.takeError());85SetPlanComplete(false);86} else87m_implementation_sp = *obj_or_err;88}89}9091bool ScriptedThreadPlan::ShouldStop(Event *event_ptr) {92Log *log = GetLog(LLDBLog::Thread);93LLDB_LOGF(log, "%s called on Scripted Thread Plan: %s )",94LLVM_PRETTY_FUNCTION, m_class_name.c_str());9596bool should_stop = true;97if (m_implementation_sp) {98auto should_stop_or_err = m_interface->ShouldStop(event_ptr);99if (!should_stop_or_err) {100LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), should_stop_or_err.takeError(),101"Can't call ScriptedThreadPlan::ShouldStop.");102SetPlanComplete(false);103} else104should_stop = *should_stop_or_err;105}106return should_stop;107}108109bool ScriptedThreadPlan::IsPlanStale() {110Log *log = GetLog(LLDBLog::Thread);111LLDB_LOGF(log, "%s called on Scripted Thread Plan: %s )",112LLVM_PRETTY_FUNCTION, m_class_name.c_str());113114bool is_stale = true;115if (m_implementation_sp) {116auto is_stale_or_err = m_interface->IsStale();117if (!is_stale_or_err) {118LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), is_stale_or_err.takeError(),119"Can't call ScriptedThreadPlan::IsStale.");120SetPlanComplete(false);121} else122is_stale = *is_stale_or_err;123}124return is_stale;125}126127bool ScriptedThreadPlan::DoPlanExplainsStop(Event *event_ptr) {128Log *log = GetLog(LLDBLog::Thread);129LLDB_LOGF(log, "%s called on Scripted Thread Plan: %s )",130LLVM_PRETTY_FUNCTION, m_class_name.c_str());131132bool explains_stop = true;133if (m_implementation_sp) {134auto explains_stop_or_error = m_interface->ExplainsStop(event_ptr);135if (!explains_stop_or_error) {136LLDB_LOG_ERROR(GetLog(LLDBLog::Thread),137explains_stop_or_error.takeError(),138"Can't call ScriptedThreadPlan::ExplainsStop.");139SetPlanComplete(false);140} else141explains_stop = *explains_stop_or_error;142}143return explains_stop;144}145146bool ScriptedThreadPlan::MischiefManaged() {147Log *log = GetLog(LLDBLog::Thread);148LLDB_LOGF(log, "%s called on Scripted Thread Plan: %s )",149LLVM_PRETTY_FUNCTION, m_class_name.c_str());150bool mischief_managed = true;151if (m_implementation_sp) {152// I don't really need mischief_managed, since it's simpler to just call153// SetPlanComplete in should_stop.154mischief_managed = IsPlanComplete();155if (mischief_managed) {156// We need to cache the stop reason here we'll need it in GetDescription.157GetDescription(&m_stop_description, eDescriptionLevelBrief);158m_implementation_sp.reset();159}160}161return mischief_managed;162}163164lldb::StateType ScriptedThreadPlan::GetPlanRunState() {165Log *log = GetLog(LLDBLog::Thread);166LLDB_LOGF(log, "%s called on Scripted Thread Plan: %s )",167LLVM_PRETTY_FUNCTION, m_class_name.c_str());168lldb::StateType run_state = eStateRunning;169if (m_implementation_sp)170run_state = m_interface->GetRunState();171return run_state;172}173174void ScriptedThreadPlan::GetDescription(Stream *s,175lldb::DescriptionLevel level) {176Log *log = GetLog(LLDBLog::Thread);177LLDB_LOGF(log, "%s called on Scripted Thread Plan: %s )",178LLVM_PRETTY_FUNCTION, m_class_name.c_str());179if (m_implementation_sp) {180ScriptInterpreter *script_interp = GetScriptInterpreter();181if (script_interp) {182lldb::StreamSP stream = std::make_shared<lldb_private::StreamString>();183llvm::Error err = m_interface->GetStopDescription(stream);184if (err) {185LLDB_LOG_ERROR(186GetLog(LLDBLog::Thread), std::move(err),187"Can't call ScriptedThreadPlan::GetStopDescription: {0}");188s->Printf("Scripted thread plan implemented by class %s.",189m_class_name.c_str());190} else191s->PutCString(192reinterpret_cast<StreamString *>(stream.get())->GetData());193}194return;195}196// It's an error not to have a description, so if we get here, we should197// add something.198if (m_stop_description.Empty())199s->Printf("Scripted thread plan implemented by class %s.",200m_class_name.c_str());201s->PutCString(m_stop_description.GetData());202}203204// The ones below are not currently exported to Python.205bool ScriptedThreadPlan::WillStop() {206Log *log = GetLog(LLDBLog::Thread);207LLDB_LOGF(log, "%s called on Scripted Thread Plan: %s )",208LLVM_PRETTY_FUNCTION, m_class_name.c_str());209return true;210}211212bool ScriptedThreadPlan::DoWillResume(lldb::StateType resume_state,213bool current_plan) {214m_stop_description.Clear();215return true;216}217218219