180814287SRaphael Isemann //===-- ThreadPlanPython.cpp ----------------------------------------------===// 22bdbfd50SJim Ingham // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 62bdbfd50SJim Ingham // 72bdbfd50SJim Ingham //===----------------------------------------------------------------------===// 82bdbfd50SJim Ingham 92bdbfd50SJim Ingham #include "lldb/Target/ThreadPlan.h" 102bdbfd50SJim Ingham 112bdbfd50SJim Ingham #include "lldb/Core/Debugger.h" 122bdbfd50SJim Ingham #include "lldb/Interpreter/CommandInterpreter.h" 132bdbfd50SJim Ingham #include "lldb/Interpreter/ScriptInterpreter.h" 14b9c1b51eSKate Stone #include "lldb/Target/Process.h" 152bdbfd50SJim Ingham #include "lldb/Target/RegisterContext.h" 16b9c1b51eSKate Stone #include "lldb/Target/Target.h" 172bdbfd50SJim Ingham #include "lldb/Target/Thread.h" 182bdbfd50SJim Ingham #include "lldb/Target/ThreadPlan.h" 192bdbfd50SJim Ingham #include "lldb/Target/ThreadPlanPython.h" 206f9e6901SZachary Turner #include "lldb/Utility/Log.h" 21d821c997SPavel Labath #include "lldb/Utility/State.h" 222bdbfd50SJim Ingham 232bdbfd50SJim Ingham using namespace lldb; 242bdbfd50SJim Ingham using namespace lldb_private; 252bdbfd50SJim Ingham 262bdbfd50SJim Ingham // ThreadPlanPython 272bdbfd50SJim Ingham 2827a14f19SJim Ingham ThreadPlanPython::ThreadPlanPython(Thread &thread, const char *class_name, 2982de8df2SPavel Labath const StructuredDataImpl &args_data) 30b9c1b51eSKate Stone : ThreadPlan(ThreadPlan::eKindPython, "Python based Thread Plan", thread, 31b9c1b51eSKate Stone eVoteNoOpinion, eVoteNoOpinion), 32d3dfd8ceSJim Ingham m_class_name(class_name), m_args_data(args_data), m_did_push(false), 33d3dfd8ceSJim Ingham m_stop_others(false) { 3404cbfa95SQuinn Pham SetIsControllingPlan(true); 352bdbfd50SJim Ingham SetOkayToDiscard(true); 362bdbfd50SJim Ingham SetPrivate(false); 372bdbfd50SJim Ingham } 382bdbfd50SJim Ingham 39b9c1b51eSKate Stone bool ThreadPlanPython::ValidatePlan(Stream *error) { 40e103ae92SJonas Devlieghere if (!m_did_push) 412bdbfd50SJim Ingham return true; 42e103ae92SJonas Devlieghere 43e103ae92SJonas Devlieghere if (!m_implementation_sp) { 44e103ae92SJonas Devlieghere if (error) 4593c98346SJim Ingham error->Printf("Error constructing Python ThreadPlan: %s", 4693c98346SJim Ingham m_error_str.empty() ? "<unknown error>" 4793c98346SJim Ingham : m_error_str.c_str()); 482bdbfd50SJim Ingham return false; 492bdbfd50SJim Ingham } 502bdbfd50SJim Ingham 51e103ae92SJonas Devlieghere return true; 52e103ae92SJonas Devlieghere } 53e103ae92SJonas Devlieghere 54e4598dc0SJim Ingham ScriptInterpreter *ThreadPlanPython::GetScriptInterpreter() { 55e4598dc0SJim Ingham return m_process.GetTarget().GetDebugger().GetScriptInterpreter(); 56e4598dc0SJim Ingham } 57e4598dc0SJim Ingham 58b9c1b51eSKate Stone void ThreadPlanPython::DidPush() { 59b9c1b51eSKate Stone // We set up the script side in DidPush, so that it can push other plans in 6005097246SAdrian Prantl // the constructor, and doesn't have to care about the details of DidPush. 61e103ae92SJonas Devlieghere m_did_push = true; 62b9c1b51eSKate Stone if (!m_class_name.empty()) { 63e4598dc0SJim Ingham ScriptInterpreter *script_interp = GetScriptInterpreter(); 64b9c1b51eSKate Stone if (script_interp) { 65b9c1b51eSKate Stone m_implementation_sp = script_interp->CreateScriptedThreadPlan( 6627a14f19SJim Ingham m_class_name.c_str(), m_args_data, m_error_str, 6727a14f19SJim Ingham this->shared_from_this()); 682bdbfd50SJim Ingham } 692bdbfd50SJim Ingham } 702bdbfd50SJim Ingham } 712bdbfd50SJim Ingham 72b9c1b51eSKate Stone bool ThreadPlanPython::ShouldStop(Event *event_ptr) { 73*a007a6d8SPavel Labath Log *log = GetLog(LLDBLog::Thread); 7463e5fb76SJonas Devlieghere LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, 75b9c1b51eSKate Stone m_class_name.c_str()); 762bdbfd50SJim Ingham 772bdbfd50SJim Ingham bool should_stop = true; 78b9c1b51eSKate Stone if (m_implementation_sp) { 79e4598dc0SJim Ingham ScriptInterpreter *script_interp = GetScriptInterpreter(); 80b9c1b51eSKate Stone if (script_interp) { 812bdbfd50SJim Ingham bool script_error; 82b9c1b51eSKate Stone should_stop = script_interp->ScriptedThreadPlanShouldStop( 83b9c1b51eSKate Stone m_implementation_sp, event_ptr, script_error); 842bdbfd50SJim Ingham if (script_error) 852bdbfd50SJim Ingham SetPlanComplete(false); 862bdbfd50SJim Ingham } 872bdbfd50SJim Ingham } 882bdbfd50SJim Ingham return should_stop; 892bdbfd50SJim Ingham } 902bdbfd50SJim Ingham 91b9c1b51eSKate Stone bool ThreadPlanPython::IsPlanStale() { 92*a007a6d8SPavel Labath Log *log = GetLog(LLDBLog::Thread); 9363e5fb76SJonas Devlieghere LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, 94b9c1b51eSKate Stone m_class_name.c_str()); 95c915a7d2SJim Ingham 96c915a7d2SJim Ingham bool is_stale = true; 97b9c1b51eSKate Stone if (m_implementation_sp) { 98e4598dc0SJim Ingham ScriptInterpreter *script_interp = GetScriptInterpreter(); 99b9c1b51eSKate Stone if (script_interp) { 100c915a7d2SJim Ingham bool script_error; 101b9c1b51eSKate Stone is_stale = script_interp->ScriptedThreadPlanIsStale(m_implementation_sp, 102b9c1b51eSKate Stone script_error); 103c915a7d2SJim Ingham if (script_error) 104c915a7d2SJim Ingham SetPlanComplete(false); 105c915a7d2SJim Ingham } 106c915a7d2SJim Ingham } 107c915a7d2SJim Ingham return is_stale; 108c915a7d2SJim Ingham } 109c915a7d2SJim Ingham 110b9c1b51eSKate Stone bool ThreadPlanPython::DoPlanExplainsStop(Event *event_ptr) { 111*a007a6d8SPavel Labath Log *log = GetLog(LLDBLog::Thread); 11263e5fb76SJonas Devlieghere LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, 113b9c1b51eSKate Stone m_class_name.c_str()); 1142bdbfd50SJim Ingham 1152bdbfd50SJim Ingham bool explains_stop = true; 116b9c1b51eSKate Stone if (m_implementation_sp) { 117e4598dc0SJim Ingham ScriptInterpreter *script_interp = GetScriptInterpreter(); 118b9c1b51eSKate Stone if (script_interp) { 1192bdbfd50SJim Ingham bool script_error; 120b9c1b51eSKate Stone explains_stop = script_interp->ScriptedThreadPlanExplainsStop( 121b9c1b51eSKate Stone m_implementation_sp, event_ptr, script_error); 1222bdbfd50SJim Ingham if (script_error) 1232bdbfd50SJim Ingham SetPlanComplete(false); 1242bdbfd50SJim Ingham } 1252bdbfd50SJim Ingham } 1262bdbfd50SJim Ingham return explains_stop; 1272bdbfd50SJim Ingham } 1282bdbfd50SJim Ingham 129b9c1b51eSKate Stone bool ThreadPlanPython::MischiefManaged() { 130*a007a6d8SPavel Labath Log *log = GetLog(LLDBLog::Thread); 13163e5fb76SJonas Devlieghere LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, 132b9c1b51eSKate Stone m_class_name.c_str()); 1332bdbfd50SJim Ingham bool mischief_managed = true; 134b9c1b51eSKate Stone if (m_implementation_sp) { 135b9c1b51eSKate Stone // I don't really need mischief_managed, since it's simpler to just call 136b9c1b51eSKate Stone // SetPlanComplete in should_stop. 1372bdbfd50SJim Ingham mischief_managed = IsPlanComplete(); 1382bdbfd50SJim Ingham if (mischief_managed) 1392bdbfd50SJim Ingham m_implementation_sp.reset(); 1402bdbfd50SJim Ingham } 1412bdbfd50SJim Ingham return mischief_managed; 1422bdbfd50SJim Ingham } 1432bdbfd50SJim Ingham 144b9c1b51eSKate Stone lldb::StateType ThreadPlanPython::GetPlanRunState() { 145*a007a6d8SPavel Labath Log *log = GetLog(LLDBLog::Thread); 14663e5fb76SJonas Devlieghere LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, 1472bdbfd50SJim Ingham m_class_name.c_str()); 1482bdbfd50SJim Ingham lldb::StateType run_state = eStateRunning; 149b9c1b51eSKate Stone if (m_implementation_sp) { 150e4598dc0SJim Ingham ScriptInterpreter *script_interp = GetScriptInterpreter(); 151b9c1b51eSKate Stone if (script_interp) { 1522bdbfd50SJim Ingham bool script_error; 153b9c1b51eSKate Stone run_state = script_interp->ScriptedThreadPlanGetRunState( 154b9c1b51eSKate Stone m_implementation_sp, script_error); 1552bdbfd50SJim Ingham } 1562bdbfd50SJim Ingham } 1572bdbfd50SJim Ingham return run_state; 1582bdbfd50SJim Ingham } 1592bdbfd50SJim Ingham 1602bdbfd50SJim Ingham // The ones below are not currently exported to Python. 161b9c1b51eSKate Stone void ThreadPlanPython::GetDescription(Stream *s, lldb::DescriptionLevel level) { 162b9c1b51eSKate Stone s->Printf("Python thread plan implemented by class %s.", 163b9c1b51eSKate Stone m_class_name.c_str()); 1642bdbfd50SJim Ingham } 1652bdbfd50SJim Ingham 166b9c1b51eSKate Stone bool ThreadPlanPython::WillStop() { 167*a007a6d8SPavel Labath Log *log = GetLog(LLDBLog::Thread); 16863e5fb76SJonas Devlieghere LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, 169b9c1b51eSKate Stone m_class_name.c_str()); 1702bdbfd50SJim Ingham return true; 1712bdbfd50SJim Ingham } 172