This patch removes all of the Set.* methods from Status. This cleanup is part of a series of patches that make it harder use the anti-pattern of keeping a long-lives Status object around and updating it while dropping any errors it contains on the floor. This patch is largely NFC, the more interesting next steps this enables is to: 1. remove Status.Clear() 2. assert that Status::operator=() never overwrites an error 3. remove Status::operator=() Note that step (2) will bring 90% of the benefits for users, and step (3) will dramatically clean up the error handling code in various places. In the end my goal is to convert all APIs that are of the form ` ResultTy DoFoo(Status& error) ` to ` llvm::Expected<ResultTy> DoFoo() ` How to read this patch? The interesting changes are in Status.h and Status.cpp, all other changes are mostly ` perl -pi -e 's/\.SetErrorString/ = Status::FromErrorString/g' $(git grep -l SetErrorString lldb/source) ` plus the occasional manual cleanup.
218 lines
7.5 KiB
C++
218 lines
7.5 KiB
C++
//===-- ScriptedThreadPlan.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/Target/ThreadPlan.h"
|
|
|
|
#include "lldb/Core/Debugger.h"
|
|
#include "lldb/Interpreter/CommandInterpreter.h"
|
|
#include "lldb/Interpreter/Interfaces/ScriptedThreadPlanInterface.h"
|
|
#include "lldb/Interpreter/ScriptInterpreter.h"
|
|
#include "lldb/Target/Process.h"
|
|
#include "lldb/Target/RegisterContext.h"
|
|
#include "lldb/Target/ScriptedThreadPlan.h"
|
|
#include "lldb/Target/Target.h"
|
|
#include "lldb/Target/Thread.h"
|
|
#include "lldb/Target/ThreadPlan.h"
|
|
#include "lldb/Utility/LLDBLog.h"
|
|
#include "lldb/Utility/Log.h"
|
|
#include "lldb/Utility/State.h"
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
ScriptedThreadPlan::ScriptedThreadPlan(Thread &thread, const char *class_name,
|
|
const StructuredDataImpl &args_data)
|
|
: ThreadPlan(ThreadPlan::eKindPython, "Script based Thread Plan", thread,
|
|
eVoteNoOpinion, eVoteNoOpinion),
|
|
m_class_name(class_name), m_args_data(args_data), m_did_push(false),
|
|
m_stop_others(false) {
|
|
ScriptInterpreter *interpreter = GetScriptInterpreter();
|
|
if (!interpreter) {
|
|
SetPlanComplete(false);
|
|
// FIXME: error handling
|
|
// error = Status::FromErrorStringWithFormat(
|
|
// "ScriptedThreadPlan::%s () - ERROR: %s", __FUNCTION__,
|
|
// "Couldn't get script interpreter");
|
|
return;
|
|
}
|
|
|
|
m_interface = interpreter->CreateScriptedThreadPlanInterface();
|
|
if (!m_interface) {
|
|
SetPlanComplete(false);
|
|
// FIXME: error handling
|
|
// error = Status::FromErrorStringWithFormat(
|
|
// "ScriptedThreadPlan::%s () - ERROR: %s", __FUNCTION__,
|
|
// "Script interpreter couldn't create Scripted Thread Plan Interface");
|
|
return;
|
|
}
|
|
|
|
SetIsControllingPlan(true);
|
|
SetOkayToDiscard(true);
|
|
SetPrivate(false);
|
|
}
|
|
|
|
bool ScriptedThreadPlan::ValidatePlan(Stream *error) {
|
|
if (!m_did_push)
|
|
return true;
|
|
|
|
if (!m_implementation_sp) {
|
|
if (error)
|
|
error->Printf("Error constructing Python ThreadPlan: %s",
|
|
m_error_str.empty() ? "<unknown error>"
|
|
: m_error_str.c_str());
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
ScriptInterpreter *ScriptedThreadPlan::GetScriptInterpreter() {
|
|
return m_process.GetTarget().GetDebugger().GetScriptInterpreter();
|
|
}
|
|
|
|
void ScriptedThreadPlan::DidPush() {
|
|
// We set up the script side in DidPush, so that it can push other plans in
|
|
// the constructor, and doesn't have to care about the details of DidPush.
|
|
m_did_push = true;
|
|
if (m_interface) {
|
|
auto obj_or_err = m_interface->CreatePluginObject(
|
|
m_class_name, this->shared_from_this(), m_args_data);
|
|
if (!obj_or_err) {
|
|
m_error_str = llvm::toString(obj_or_err.takeError());
|
|
SetPlanComplete(false);
|
|
} else
|
|
m_implementation_sp = *obj_or_err;
|
|
}
|
|
}
|
|
|
|
bool ScriptedThreadPlan::ShouldStop(Event *event_ptr) {
|
|
Log *log = GetLog(LLDBLog::Thread);
|
|
LLDB_LOGF(log, "%s called on Scripted Thread Plan: %s )",
|
|
LLVM_PRETTY_FUNCTION, m_class_name.c_str());
|
|
|
|
bool should_stop = true;
|
|
if (m_implementation_sp) {
|
|
auto should_stop_or_err = m_interface->ShouldStop(event_ptr);
|
|
if (!should_stop_or_err) {
|
|
LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), should_stop_or_err.takeError(),
|
|
"Can't call ScriptedThreadPlan::ShouldStop.");
|
|
SetPlanComplete(false);
|
|
} else
|
|
should_stop = *should_stop_or_err;
|
|
}
|
|
return should_stop;
|
|
}
|
|
|
|
bool ScriptedThreadPlan::IsPlanStale() {
|
|
Log *log = GetLog(LLDBLog::Thread);
|
|
LLDB_LOGF(log, "%s called on Scripted Thread Plan: %s )",
|
|
LLVM_PRETTY_FUNCTION, m_class_name.c_str());
|
|
|
|
bool is_stale = true;
|
|
if (m_implementation_sp) {
|
|
auto is_stale_or_err = m_interface->IsStale();
|
|
if (!is_stale_or_err) {
|
|
LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), is_stale_or_err.takeError(),
|
|
"Can't call ScriptedThreadPlan::IsStale.");
|
|
SetPlanComplete(false);
|
|
} else
|
|
is_stale = *is_stale_or_err;
|
|
}
|
|
return is_stale;
|
|
}
|
|
|
|
bool ScriptedThreadPlan::DoPlanExplainsStop(Event *event_ptr) {
|
|
Log *log = GetLog(LLDBLog::Thread);
|
|
LLDB_LOGF(log, "%s called on Scripted Thread Plan: %s )",
|
|
LLVM_PRETTY_FUNCTION, m_class_name.c_str());
|
|
|
|
bool explains_stop = true;
|
|
if (m_implementation_sp) {
|
|
auto explains_stop_or_error = m_interface->ExplainsStop(event_ptr);
|
|
if (!explains_stop_or_error) {
|
|
LLDB_LOG_ERROR(GetLog(LLDBLog::Thread),
|
|
explains_stop_or_error.takeError(),
|
|
"Can't call ScriptedThreadPlan::ExplainsStop.");
|
|
SetPlanComplete(false);
|
|
} else
|
|
explains_stop = *explains_stop_or_error;
|
|
}
|
|
return explains_stop;
|
|
}
|
|
|
|
bool ScriptedThreadPlan::MischiefManaged() {
|
|
Log *log = GetLog(LLDBLog::Thread);
|
|
LLDB_LOGF(log, "%s called on Scripted Thread Plan: %s )",
|
|
LLVM_PRETTY_FUNCTION, m_class_name.c_str());
|
|
bool mischief_managed = true;
|
|
if (m_implementation_sp) {
|
|
// I don't really need mischief_managed, since it's simpler to just call
|
|
// SetPlanComplete in should_stop.
|
|
mischief_managed = IsPlanComplete();
|
|
if (mischief_managed) {
|
|
// We need to cache the stop reason here we'll need it in GetDescription.
|
|
GetDescription(&m_stop_description, eDescriptionLevelBrief);
|
|
m_implementation_sp.reset();
|
|
}
|
|
}
|
|
return mischief_managed;
|
|
}
|
|
|
|
lldb::StateType ScriptedThreadPlan::GetPlanRunState() {
|
|
Log *log = GetLog(LLDBLog::Thread);
|
|
LLDB_LOGF(log, "%s called on Scripted Thread Plan: %s )",
|
|
LLVM_PRETTY_FUNCTION, m_class_name.c_str());
|
|
lldb::StateType run_state = eStateRunning;
|
|
if (m_implementation_sp)
|
|
run_state = m_interface->GetRunState();
|
|
return run_state;
|
|
}
|
|
|
|
void ScriptedThreadPlan::GetDescription(Stream *s,
|
|
lldb::DescriptionLevel level) {
|
|
Log *log = GetLog(LLDBLog::Thread);
|
|
LLDB_LOGF(log, "%s called on Scripted Thread Plan: %s )",
|
|
LLVM_PRETTY_FUNCTION, m_class_name.c_str());
|
|
if (m_implementation_sp) {
|
|
ScriptInterpreter *script_interp = GetScriptInterpreter();
|
|
if (script_interp) {
|
|
lldb::StreamSP stream = std::make_shared<lldb_private::StreamString>();
|
|
llvm::Error err = m_interface->GetStopDescription(stream);
|
|
if (err) {
|
|
LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), std::move(err),
|
|
"Can't call ScriptedThreadPlan::GetStopDescription.");
|
|
s->Printf("Scripted thread plan implemented by class %s.",
|
|
m_class_name.c_str());
|
|
} else
|
|
s->PutCString(
|
|
reinterpret_cast<StreamString *>(stream.get())->GetData());
|
|
}
|
|
return;
|
|
}
|
|
// It's an error not to have a description, so if we get here, we should
|
|
// add something.
|
|
if (m_stop_description.Empty())
|
|
s->Printf("Scripted thread plan implemented by class %s.",
|
|
m_class_name.c_str());
|
|
s->PutCString(m_stop_description.GetData());
|
|
}
|
|
|
|
// The ones below are not currently exported to Python.
|
|
bool ScriptedThreadPlan::WillStop() {
|
|
Log *log = GetLog(LLDBLog::Thread);
|
|
LLDB_LOGF(log, "%s called on Scripted Thread Plan: %s )",
|
|
LLVM_PRETTY_FUNCTION, m_class_name.c_str());
|
|
return true;
|
|
}
|
|
|
|
bool ScriptedThreadPlan::DoWillResume(lldb::StateType resume_state,
|
|
bool current_plan) {
|
|
m_stop_description.Clear();
|
|
return true;
|
|
}
|