1696bd635SAlexander Shaposhnikov //===-- ThreadPlanPython.cpp ------------------------------------*- C++ -*-===// 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 28b9c1b51eSKate Stone ThreadPlanPython::ThreadPlanPython(Thread &thread, const char *class_name) 29b9c1b51eSKate Stone : ThreadPlan(ThreadPlan::eKindPython, "Python based Thread Plan", thread, 30b9c1b51eSKate Stone eVoteNoOpinion, eVoteNoOpinion), 31e103ae92SJonas Devlieghere m_class_name(class_name), m_did_push(false) { 322bdbfd50SJim Ingham SetIsMasterPlan(true); 332bdbfd50SJim Ingham SetOkayToDiscard(true); 342bdbfd50SJim Ingham SetPrivate(false); 352bdbfd50SJim Ingham } 362bdbfd50SJim Ingham 37b9c1b51eSKate Stone ThreadPlanPython::~ThreadPlanPython() { 38b9c1b51eSKate Stone // FIXME, do I need to decrement the ref count on this implementation object 39b9c1b51eSKate Stone // to make it go away? 402bdbfd50SJim Ingham } 412bdbfd50SJim Ingham 42b9c1b51eSKate Stone bool ThreadPlanPython::ValidatePlan(Stream *error) { 43e103ae92SJonas Devlieghere if (!m_did_push) 442bdbfd50SJim Ingham return true; 45e103ae92SJonas Devlieghere 46e103ae92SJonas Devlieghere if (!m_implementation_sp) { 47e103ae92SJonas Devlieghere if (error) 48e103ae92SJonas Devlieghere error->Printf("Python thread plan does not have an implementation"); 492bdbfd50SJim Ingham return false; 502bdbfd50SJim Ingham } 512bdbfd50SJim Ingham 52e103ae92SJonas Devlieghere return true; 53e103ae92SJonas Devlieghere } 54e103ae92SJonas Devlieghere 55b9c1b51eSKate Stone void ThreadPlanPython::DidPush() { 56b9c1b51eSKate Stone // We set up the script side in DidPush, so that it can push other plans in 5705097246SAdrian Prantl // the constructor, and doesn't have to care about the details of DidPush. 58e103ae92SJonas Devlieghere m_did_push = true; 59b9c1b51eSKate Stone if (!m_class_name.empty()) { 60b9c1b51eSKate Stone ScriptInterpreter *script_interp = m_thread.GetProcess() 61b9c1b51eSKate Stone ->GetTarget() 62b9c1b51eSKate Stone .GetDebugger() 63b9c1b51eSKate Stone .GetScriptInterpreter(); 64b9c1b51eSKate Stone if (script_interp) { 65b9c1b51eSKate Stone m_implementation_sp = script_interp->CreateScriptedThreadPlan( 66b9c1b51eSKate Stone m_class_name.c_str(), this->shared_from_this()); 672bdbfd50SJim Ingham } 682bdbfd50SJim Ingham } 692bdbfd50SJim Ingham } 702bdbfd50SJim Ingham 71b9c1b51eSKate Stone bool ThreadPlanPython::ShouldStop(Event *event_ptr) { 722bdbfd50SJim Ingham Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 73*63e5fb76SJonas Devlieghere LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, 74b9c1b51eSKate Stone m_class_name.c_str()); 752bdbfd50SJim Ingham 762bdbfd50SJim Ingham bool should_stop = true; 77b9c1b51eSKate Stone if (m_implementation_sp) { 78b9c1b51eSKate Stone ScriptInterpreter *script_interp = m_thread.GetProcess() 79b9c1b51eSKate Stone ->GetTarget() 80b9c1b51eSKate Stone .GetDebugger() 81b9c1b51eSKate Stone .GetScriptInterpreter(); 82b9c1b51eSKate Stone if (script_interp) { 832bdbfd50SJim Ingham bool script_error; 84b9c1b51eSKate Stone should_stop = script_interp->ScriptedThreadPlanShouldStop( 85b9c1b51eSKate Stone m_implementation_sp, event_ptr, script_error); 862bdbfd50SJim Ingham if (script_error) 872bdbfd50SJim Ingham SetPlanComplete(false); 882bdbfd50SJim Ingham } 892bdbfd50SJim Ingham } 902bdbfd50SJim Ingham return should_stop; 912bdbfd50SJim Ingham } 922bdbfd50SJim Ingham 93b9c1b51eSKate Stone bool ThreadPlanPython::IsPlanStale() { 94c915a7d2SJim Ingham Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 95*63e5fb76SJonas Devlieghere LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, 96b9c1b51eSKate Stone m_class_name.c_str()); 97c915a7d2SJim Ingham 98c915a7d2SJim Ingham bool is_stale = true; 99b9c1b51eSKate Stone if (m_implementation_sp) { 100b9c1b51eSKate Stone ScriptInterpreter *script_interp = m_thread.GetProcess() 101b9c1b51eSKate Stone ->GetTarget() 102b9c1b51eSKate Stone .GetDebugger() 103b9c1b51eSKate Stone .GetScriptInterpreter(); 104b9c1b51eSKate Stone if (script_interp) { 105c915a7d2SJim Ingham bool script_error; 106b9c1b51eSKate Stone is_stale = script_interp->ScriptedThreadPlanIsStale(m_implementation_sp, 107b9c1b51eSKate Stone script_error); 108c915a7d2SJim Ingham if (script_error) 109c915a7d2SJim Ingham SetPlanComplete(false); 110c915a7d2SJim Ingham } 111c915a7d2SJim Ingham } 112c915a7d2SJim Ingham return is_stale; 113c915a7d2SJim Ingham } 114c915a7d2SJim Ingham 115b9c1b51eSKate Stone bool ThreadPlanPython::DoPlanExplainsStop(Event *event_ptr) { 1162bdbfd50SJim Ingham Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 117*63e5fb76SJonas Devlieghere LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, 118b9c1b51eSKate Stone m_class_name.c_str()); 1192bdbfd50SJim Ingham 1202bdbfd50SJim Ingham bool explains_stop = true; 121b9c1b51eSKate Stone if (m_implementation_sp) { 122b9c1b51eSKate Stone ScriptInterpreter *script_interp = m_thread.GetProcess() 123b9c1b51eSKate Stone ->GetTarget() 124b9c1b51eSKate Stone .GetDebugger() 125b9c1b51eSKate Stone .GetScriptInterpreter(); 126b9c1b51eSKate Stone if (script_interp) { 1272bdbfd50SJim Ingham bool script_error; 128b9c1b51eSKate Stone explains_stop = script_interp->ScriptedThreadPlanExplainsStop( 129b9c1b51eSKate Stone m_implementation_sp, event_ptr, script_error); 1302bdbfd50SJim Ingham if (script_error) 1312bdbfd50SJim Ingham SetPlanComplete(false); 1322bdbfd50SJim Ingham } 1332bdbfd50SJim Ingham } 1342bdbfd50SJim Ingham return explains_stop; 1352bdbfd50SJim Ingham } 1362bdbfd50SJim Ingham 137b9c1b51eSKate Stone bool ThreadPlanPython::MischiefManaged() { 1382bdbfd50SJim Ingham Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 139*63e5fb76SJonas Devlieghere LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, 140b9c1b51eSKate Stone m_class_name.c_str()); 1412bdbfd50SJim Ingham bool mischief_managed = true; 142b9c1b51eSKate Stone if (m_implementation_sp) { 143b9c1b51eSKate Stone // I don't really need mischief_managed, since it's simpler to just call 144b9c1b51eSKate Stone // SetPlanComplete in should_stop. 1452bdbfd50SJim Ingham mischief_managed = IsPlanComplete(); 1462bdbfd50SJim Ingham if (mischief_managed) 1472bdbfd50SJim Ingham m_implementation_sp.reset(); 1482bdbfd50SJim Ingham } 1492bdbfd50SJim Ingham return mischief_managed; 1502bdbfd50SJim Ingham } 1512bdbfd50SJim Ingham 152b9c1b51eSKate Stone lldb::StateType ThreadPlanPython::GetPlanRunState() { 1532bdbfd50SJim Ingham Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 154*63e5fb76SJonas Devlieghere LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, 1552bdbfd50SJim Ingham m_class_name.c_str()); 1562bdbfd50SJim Ingham lldb::StateType run_state = eStateRunning; 157b9c1b51eSKate Stone if (m_implementation_sp) { 158b9c1b51eSKate Stone ScriptInterpreter *script_interp = m_thread.GetProcess() 159b9c1b51eSKate Stone ->GetTarget() 160b9c1b51eSKate Stone .GetDebugger() 161b9c1b51eSKate Stone .GetScriptInterpreter(); 162b9c1b51eSKate Stone if (script_interp) { 1632bdbfd50SJim Ingham bool script_error; 164b9c1b51eSKate Stone run_state = script_interp->ScriptedThreadPlanGetRunState( 165b9c1b51eSKate Stone m_implementation_sp, script_error); 1662bdbfd50SJim Ingham } 1672bdbfd50SJim Ingham } 1682bdbfd50SJim Ingham return run_state; 1692bdbfd50SJim Ingham } 1702bdbfd50SJim Ingham 1712bdbfd50SJim Ingham // The ones below are not currently exported to Python. 1722bdbfd50SJim Ingham 173b9c1b51eSKate Stone bool ThreadPlanPython::StopOthers() { 174b9c1b51eSKate Stone // For now Python plans run all threads, but we should add some controls for 175b9c1b51eSKate Stone // this. 1762bdbfd50SJim Ingham return false; 1772bdbfd50SJim Ingham } 1782bdbfd50SJim Ingham 179b9c1b51eSKate Stone void ThreadPlanPython::GetDescription(Stream *s, lldb::DescriptionLevel level) { 180b9c1b51eSKate Stone s->Printf("Python thread plan implemented by class %s.", 181b9c1b51eSKate Stone m_class_name.c_str()); 1822bdbfd50SJim Ingham } 1832bdbfd50SJim Ingham 184b9c1b51eSKate Stone bool ThreadPlanPython::WillStop() { 1852bdbfd50SJim Ingham Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 186*63e5fb76SJonas Devlieghere LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, 187b9c1b51eSKate Stone m_class_name.c_str()); 1882bdbfd50SJim Ingham return true; 1892bdbfd50SJim Ingham } 190