1039cfe81SMed Ismail Bennani //===-- ScriptedThreadPlan.cpp --------------------------------------------===// 2039cfe81SMed Ismail Bennani // 3039cfe81SMed Ismail Bennani // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4039cfe81SMed Ismail Bennani // See https://llvm.org/LICENSE.txt for license information. 5039cfe81SMed Ismail Bennani // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6039cfe81SMed Ismail Bennani // 7039cfe81SMed Ismail Bennani //===----------------------------------------------------------------------===// 8039cfe81SMed Ismail Bennani 9039cfe81SMed Ismail Bennani #include "lldb/Target/ThreadPlan.h" 10039cfe81SMed Ismail Bennani 11039cfe81SMed Ismail Bennani #include "lldb/Core/Debugger.h" 12039cfe81SMed Ismail Bennani #include "lldb/Interpreter/CommandInterpreter.h" 13039cfe81SMed Ismail Bennani #include "lldb/Interpreter/Interfaces/ScriptedThreadPlanInterface.h" 14039cfe81SMed Ismail Bennani #include "lldb/Interpreter/ScriptInterpreter.h" 15039cfe81SMed Ismail Bennani #include "lldb/Target/Process.h" 16039cfe81SMed Ismail Bennani #include "lldb/Target/RegisterContext.h" 17039cfe81SMed Ismail Bennani #include "lldb/Target/ScriptedThreadPlan.h" 18039cfe81SMed Ismail Bennani #include "lldb/Target/Target.h" 19039cfe81SMed Ismail Bennani #include "lldb/Target/Thread.h" 20039cfe81SMed Ismail Bennani #include "lldb/Target/ThreadPlan.h" 21039cfe81SMed Ismail Bennani #include "lldb/Utility/LLDBLog.h" 22039cfe81SMed Ismail Bennani #include "lldb/Utility/Log.h" 23039cfe81SMed Ismail Bennani #include "lldb/Utility/State.h" 24039cfe81SMed Ismail Bennani 25039cfe81SMed Ismail Bennani using namespace lldb; 26039cfe81SMed Ismail Bennani using namespace lldb_private; 27039cfe81SMed Ismail Bennani 28039cfe81SMed Ismail Bennani ScriptedThreadPlan::ScriptedThreadPlan(Thread &thread, const char *class_name, 29039cfe81SMed Ismail Bennani const StructuredDataImpl &args_data) 30039cfe81SMed Ismail Bennani : ThreadPlan(ThreadPlan::eKindPython, "Script based Thread Plan", thread, 31039cfe81SMed Ismail Bennani eVoteNoOpinion, eVoteNoOpinion), 32039cfe81SMed Ismail Bennani m_class_name(class_name), m_args_data(args_data), m_did_push(false), 33039cfe81SMed Ismail Bennani m_stop_others(false) { 34039cfe81SMed Ismail Bennani ScriptInterpreter *interpreter = GetScriptInterpreter(); 35039cfe81SMed Ismail Bennani if (!interpreter) { 36039cfe81SMed Ismail Bennani SetPlanComplete(false); 37039cfe81SMed Ismail Bennani // FIXME: error handling 380642cd76SAdrian Prantl // error = Status::FromErrorStringWithFormat( 39039cfe81SMed Ismail Bennani // "ScriptedThreadPlan::%s () - ERROR: %s", __FUNCTION__, 40039cfe81SMed Ismail Bennani // "Couldn't get script interpreter"); 41039cfe81SMed Ismail Bennani return; 42039cfe81SMed Ismail Bennani } 43039cfe81SMed Ismail Bennani 44039cfe81SMed Ismail Bennani m_interface = interpreter->CreateScriptedThreadPlanInterface(); 45039cfe81SMed Ismail Bennani if (!m_interface) { 46039cfe81SMed Ismail Bennani SetPlanComplete(false); 47039cfe81SMed Ismail Bennani // FIXME: error handling 480642cd76SAdrian Prantl // error = Status::FromErrorStringWithFormat( 49039cfe81SMed Ismail Bennani // "ScriptedThreadPlan::%s () - ERROR: %s", __FUNCTION__, 50039cfe81SMed Ismail Bennani // "Script interpreter couldn't create Scripted Thread Plan Interface"); 51039cfe81SMed Ismail Bennani return; 52039cfe81SMed Ismail Bennani } 53039cfe81SMed Ismail Bennani 54039cfe81SMed Ismail Bennani SetIsControllingPlan(true); 55039cfe81SMed Ismail Bennani SetOkayToDiscard(true); 56039cfe81SMed Ismail Bennani SetPrivate(false); 57039cfe81SMed Ismail Bennani } 58039cfe81SMed Ismail Bennani 59039cfe81SMed Ismail Bennani bool ScriptedThreadPlan::ValidatePlan(Stream *error) { 60039cfe81SMed Ismail Bennani if (!m_did_push) 61039cfe81SMed Ismail Bennani return true; 62039cfe81SMed Ismail Bennani 63039cfe81SMed Ismail Bennani if (!m_implementation_sp) { 64039cfe81SMed Ismail Bennani if (error) 65039cfe81SMed Ismail Bennani error->Printf("Error constructing Python ThreadPlan: %s", 66039cfe81SMed Ismail Bennani m_error_str.empty() ? "<unknown error>" 67039cfe81SMed Ismail Bennani : m_error_str.c_str()); 68039cfe81SMed Ismail Bennani return false; 69039cfe81SMed Ismail Bennani } 70039cfe81SMed Ismail Bennani 71039cfe81SMed Ismail Bennani return true; 72039cfe81SMed Ismail Bennani } 73039cfe81SMed Ismail Bennani 74039cfe81SMed Ismail Bennani ScriptInterpreter *ScriptedThreadPlan::GetScriptInterpreter() { 75039cfe81SMed Ismail Bennani return m_process.GetTarget().GetDebugger().GetScriptInterpreter(); 76039cfe81SMed Ismail Bennani } 77039cfe81SMed Ismail Bennani 78039cfe81SMed Ismail Bennani void ScriptedThreadPlan::DidPush() { 79039cfe81SMed Ismail Bennani // We set up the script side in DidPush, so that it can push other plans in 80039cfe81SMed Ismail Bennani // the constructor, and doesn't have to care about the details of DidPush. 81039cfe81SMed Ismail Bennani m_did_push = true; 82039cfe81SMed Ismail Bennani if (m_interface) { 83039cfe81SMed Ismail Bennani auto obj_or_err = m_interface->CreatePluginObject( 84039cfe81SMed Ismail Bennani m_class_name, this->shared_from_this(), m_args_data); 85039cfe81SMed Ismail Bennani if (!obj_or_err) { 86039cfe81SMed Ismail Bennani m_error_str = llvm::toString(obj_or_err.takeError()); 87039cfe81SMed Ismail Bennani SetPlanComplete(false); 88039cfe81SMed Ismail Bennani } else 89039cfe81SMed Ismail Bennani m_implementation_sp = *obj_or_err; 90039cfe81SMed Ismail Bennani } 91039cfe81SMed Ismail Bennani } 92039cfe81SMed Ismail Bennani 93039cfe81SMed Ismail Bennani bool ScriptedThreadPlan::ShouldStop(Event *event_ptr) { 94039cfe81SMed Ismail Bennani Log *log = GetLog(LLDBLog::Thread); 95039cfe81SMed Ismail Bennani LLDB_LOGF(log, "%s called on Scripted Thread Plan: %s )", 96039cfe81SMed Ismail Bennani LLVM_PRETTY_FUNCTION, m_class_name.c_str()); 97039cfe81SMed Ismail Bennani 98039cfe81SMed Ismail Bennani bool should_stop = true; 99039cfe81SMed Ismail Bennani if (m_implementation_sp) { 100039cfe81SMed Ismail Bennani auto should_stop_or_err = m_interface->ShouldStop(event_ptr); 101039cfe81SMed Ismail Bennani if (!should_stop_or_err) { 102039cfe81SMed Ismail Bennani LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), should_stop_or_err.takeError(), 103039cfe81SMed Ismail Bennani "Can't call ScriptedThreadPlan::ShouldStop."); 104039cfe81SMed Ismail Bennani SetPlanComplete(false); 105039cfe81SMed Ismail Bennani } else 106039cfe81SMed Ismail Bennani should_stop = *should_stop_or_err; 107039cfe81SMed Ismail Bennani } 108039cfe81SMed Ismail Bennani return should_stop; 109039cfe81SMed Ismail Bennani } 110039cfe81SMed Ismail Bennani 111039cfe81SMed Ismail Bennani bool ScriptedThreadPlan::IsPlanStale() { 112039cfe81SMed Ismail Bennani Log *log = GetLog(LLDBLog::Thread); 113039cfe81SMed Ismail Bennani LLDB_LOGF(log, "%s called on Scripted Thread Plan: %s )", 114039cfe81SMed Ismail Bennani LLVM_PRETTY_FUNCTION, m_class_name.c_str()); 115039cfe81SMed Ismail Bennani 116039cfe81SMed Ismail Bennani bool is_stale = true; 117039cfe81SMed Ismail Bennani if (m_implementation_sp) { 118039cfe81SMed Ismail Bennani auto is_stale_or_err = m_interface->IsStale(); 119039cfe81SMed Ismail Bennani if (!is_stale_or_err) { 120039cfe81SMed Ismail Bennani LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), is_stale_or_err.takeError(), 121039cfe81SMed Ismail Bennani "Can't call ScriptedThreadPlan::IsStale."); 122039cfe81SMed Ismail Bennani SetPlanComplete(false); 123039cfe81SMed Ismail Bennani } else 124039cfe81SMed Ismail Bennani is_stale = *is_stale_or_err; 125039cfe81SMed Ismail Bennani } 126039cfe81SMed Ismail Bennani return is_stale; 127039cfe81SMed Ismail Bennani } 128039cfe81SMed Ismail Bennani 129039cfe81SMed Ismail Bennani bool ScriptedThreadPlan::DoPlanExplainsStop(Event *event_ptr) { 130039cfe81SMed Ismail Bennani Log *log = GetLog(LLDBLog::Thread); 131039cfe81SMed Ismail Bennani LLDB_LOGF(log, "%s called on Scripted Thread Plan: %s )", 132039cfe81SMed Ismail Bennani LLVM_PRETTY_FUNCTION, m_class_name.c_str()); 133039cfe81SMed Ismail Bennani 134039cfe81SMed Ismail Bennani bool explains_stop = true; 135039cfe81SMed Ismail Bennani if (m_implementation_sp) { 136039cfe81SMed Ismail Bennani auto explains_stop_or_error = m_interface->ExplainsStop(event_ptr); 137039cfe81SMed Ismail Bennani if (!explains_stop_or_error) { 138039cfe81SMed Ismail Bennani LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), 139039cfe81SMed Ismail Bennani explains_stop_or_error.takeError(), 140039cfe81SMed Ismail Bennani "Can't call ScriptedThreadPlan::ExplainsStop."); 141039cfe81SMed Ismail Bennani SetPlanComplete(false); 142039cfe81SMed Ismail Bennani } else 143039cfe81SMed Ismail Bennani explains_stop = *explains_stop_or_error; 144039cfe81SMed Ismail Bennani } 145039cfe81SMed Ismail Bennani return explains_stop; 146039cfe81SMed Ismail Bennani } 147039cfe81SMed Ismail Bennani 148039cfe81SMed Ismail Bennani bool ScriptedThreadPlan::MischiefManaged() { 149039cfe81SMed Ismail Bennani Log *log = GetLog(LLDBLog::Thread); 150039cfe81SMed Ismail Bennani LLDB_LOGF(log, "%s called on Scripted Thread Plan: %s )", 151039cfe81SMed Ismail Bennani LLVM_PRETTY_FUNCTION, m_class_name.c_str()); 152039cfe81SMed Ismail Bennani bool mischief_managed = true; 153039cfe81SMed Ismail Bennani if (m_implementation_sp) { 154039cfe81SMed Ismail Bennani // I don't really need mischief_managed, since it's simpler to just call 155039cfe81SMed Ismail Bennani // SetPlanComplete in should_stop. 156039cfe81SMed Ismail Bennani mischief_managed = IsPlanComplete(); 157039cfe81SMed Ismail Bennani if (mischief_managed) { 158039cfe81SMed Ismail Bennani // We need to cache the stop reason here we'll need it in GetDescription. 159039cfe81SMed Ismail Bennani GetDescription(&m_stop_description, eDescriptionLevelBrief); 160039cfe81SMed Ismail Bennani m_implementation_sp.reset(); 161039cfe81SMed Ismail Bennani } 162039cfe81SMed Ismail Bennani } 163039cfe81SMed Ismail Bennani return mischief_managed; 164039cfe81SMed Ismail Bennani } 165039cfe81SMed Ismail Bennani 166039cfe81SMed Ismail Bennani lldb::StateType ScriptedThreadPlan::GetPlanRunState() { 167039cfe81SMed Ismail Bennani Log *log = GetLog(LLDBLog::Thread); 168039cfe81SMed Ismail Bennani LLDB_LOGF(log, "%s called on Scripted Thread Plan: %s )", 169039cfe81SMed Ismail Bennani LLVM_PRETTY_FUNCTION, m_class_name.c_str()); 170039cfe81SMed Ismail Bennani lldb::StateType run_state = eStateRunning; 171039cfe81SMed Ismail Bennani if (m_implementation_sp) 172039cfe81SMed Ismail Bennani run_state = m_interface->GetRunState(); 173039cfe81SMed Ismail Bennani return run_state; 174039cfe81SMed Ismail Bennani } 175039cfe81SMed Ismail Bennani 176039cfe81SMed Ismail Bennani void ScriptedThreadPlan::GetDescription(Stream *s, 177039cfe81SMed Ismail Bennani lldb::DescriptionLevel level) { 178039cfe81SMed Ismail Bennani Log *log = GetLog(LLDBLog::Thread); 179039cfe81SMed Ismail Bennani LLDB_LOGF(log, "%s called on Scripted Thread Plan: %s )", 180039cfe81SMed Ismail Bennani LLVM_PRETTY_FUNCTION, m_class_name.c_str()); 181039cfe81SMed Ismail Bennani if (m_implementation_sp) { 182039cfe81SMed Ismail Bennani ScriptInterpreter *script_interp = GetScriptInterpreter(); 183039cfe81SMed Ismail Bennani if (script_interp) { 184039cfe81SMed Ismail Bennani lldb::StreamSP stream = std::make_shared<lldb_private::StreamString>(); 185039cfe81SMed Ismail Bennani llvm::Error err = m_interface->GetStopDescription(stream); 186039cfe81SMed Ismail Bennani if (err) { 187*f2c5aa92SJonas Devlieghere LLDB_LOG_ERROR( 188*f2c5aa92SJonas Devlieghere GetLog(LLDBLog::Thread), std::move(err), 189*f2c5aa92SJonas Devlieghere "Can't call ScriptedThreadPlan::GetStopDescription: {0}"); 190039cfe81SMed Ismail Bennani s->Printf("Scripted thread plan implemented by class %s.", 191039cfe81SMed Ismail Bennani m_class_name.c_str()); 192039cfe81SMed Ismail Bennani } else 193039cfe81SMed Ismail Bennani s->PutCString( 194039cfe81SMed Ismail Bennani reinterpret_cast<StreamString *>(stream.get())->GetData()); 195039cfe81SMed Ismail Bennani } 196039cfe81SMed Ismail Bennani return; 197039cfe81SMed Ismail Bennani } 198039cfe81SMed Ismail Bennani // It's an error not to have a description, so if we get here, we should 199039cfe81SMed Ismail Bennani // add something. 200039cfe81SMed Ismail Bennani if (m_stop_description.Empty()) 201039cfe81SMed Ismail Bennani s->Printf("Scripted thread plan implemented by class %s.", 202039cfe81SMed Ismail Bennani m_class_name.c_str()); 203039cfe81SMed Ismail Bennani s->PutCString(m_stop_description.GetData()); 204039cfe81SMed Ismail Bennani } 205039cfe81SMed Ismail Bennani 206039cfe81SMed Ismail Bennani // The ones below are not currently exported to Python. 207039cfe81SMed Ismail Bennani bool ScriptedThreadPlan::WillStop() { 208039cfe81SMed Ismail Bennani Log *log = GetLog(LLDBLog::Thread); 209039cfe81SMed Ismail Bennani LLDB_LOGF(log, "%s called on Scripted Thread Plan: %s )", 210039cfe81SMed Ismail Bennani LLVM_PRETTY_FUNCTION, m_class_name.c_str()); 211039cfe81SMed Ismail Bennani return true; 212039cfe81SMed Ismail Bennani } 213039cfe81SMed Ismail Bennani 214039cfe81SMed Ismail Bennani bool ScriptedThreadPlan::DoWillResume(lldb::StateType resume_state, 215039cfe81SMed Ismail Bennani bool current_plan) { 216039cfe81SMed Ismail Bennani m_stop_description.Clear(); 217039cfe81SMed Ismail Bennani return true; 218039cfe81SMed Ismail Bennani } 219