1 //===-- ThreadPlanPython.cpp ------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "lldb/Target/ThreadPlan.h" 10 11 #include "lldb/Core/Debugger.h" 12 #include "lldb/Interpreter/CommandInterpreter.h" 13 #include "lldb/Interpreter/ScriptInterpreter.h" 14 #include "lldb/Target/Process.h" 15 #include "lldb/Target/RegisterContext.h" 16 #include "lldb/Target/Target.h" 17 #include "lldb/Target/Thread.h" 18 #include "lldb/Target/ThreadPlan.h" 19 #include "lldb/Target/ThreadPlanPython.h" 20 #include "lldb/Utility/Log.h" 21 #include "lldb/Utility/State.h" 22 23 using namespace lldb; 24 using namespace lldb_private; 25 26 // ThreadPlanPython 27 28 ThreadPlanPython::ThreadPlanPython(Thread &thread, const char *class_name) 29 : ThreadPlan(ThreadPlan::eKindPython, "Python based Thread Plan", thread, 30 eVoteNoOpinion, eVoteNoOpinion), 31 m_class_name(class_name), m_did_push(false) { 32 SetIsMasterPlan(true); 33 SetOkayToDiscard(true); 34 SetPrivate(false); 35 } 36 37 ThreadPlanPython::~ThreadPlanPython() { 38 // FIXME, do I need to decrement the ref count on this implementation object 39 // to make it go away? 40 } 41 42 bool ThreadPlanPython::ValidatePlan(Stream *error) { 43 if (!m_did_push) 44 return true; 45 46 if (!m_implementation_sp) { 47 if (error) 48 error->Printf("Python thread plan does not have an implementation"); 49 return false; 50 } 51 52 return true; 53 } 54 55 void ThreadPlanPython::DidPush() { 56 // We set up the script side in DidPush, so that it can push other plans in 57 // the constructor, and doesn't have to care about the details of DidPush. 58 m_did_push = true; 59 if (!m_class_name.empty()) { 60 ScriptInterpreter *script_interp = m_thread.GetProcess() 61 ->GetTarget() 62 .GetDebugger() 63 .GetCommandInterpreter() 64 .GetScriptInterpreter(); 65 if (script_interp) { 66 m_implementation_sp = script_interp->CreateScriptedThreadPlan( 67 m_class_name.c_str(), this->shared_from_this()); 68 } 69 } 70 } 71 72 bool ThreadPlanPython::ShouldStop(Event *event_ptr) { 73 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 74 if (log) 75 log->Printf("%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, 76 m_class_name.c_str()); 77 78 bool should_stop = true; 79 if (m_implementation_sp) { 80 ScriptInterpreter *script_interp = m_thread.GetProcess() 81 ->GetTarget() 82 .GetDebugger() 83 .GetCommandInterpreter() 84 .GetScriptInterpreter(); 85 if (script_interp) { 86 bool script_error; 87 should_stop = script_interp->ScriptedThreadPlanShouldStop( 88 m_implementation_sp, event_ptr, script_error); 89 if (script_error) 90 SetPlanComplete(false); 91 } 92 } 93 return should_stop; 94 } 95 96 bool ThreadPlanPython::IsPlanStale() { 97 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 98 if (log) 99 log->Printf("%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, 100 m_class_name.c_str()); 101 102 bool is_stale = true; 103 if (m_implementation_sp) { 104 ScriptInterpreter *script_interp = m_thread.GetProcess() 105 ->GetTarget() 106 .GetDebugger() 107 .GetCommandInterpreter() 108 .GetScriptInterpreter(); 109 if (script_interp) { 110 bool script_error; 111 is_stale = script_interp->ScriptedThreadPlanIsStale(m_implementation_sp, 112 script_error); 113 if (script_error) 114 SetPlanComplete(false); 115 } 116 } 117 return is_stale; 118 } 119 120 bool ThreadPlanPython::DoPlanExplainsStop(Event *event_ptr) { 121 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 122 if (log) 123 log->Printf("%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, 124 m_class_name.c_str()); 125 126 bool explains_stop = true; 127 if (m_implementation_sp) { 128 ScriptInterpreter *script_interp = m_thread.GetProcess() 129 ->GetTarget() 130 .GetDebugger() 131 .GetCommandInterpreter() 132 .GetScriptInterpreter(); 133 if (script_interp) { 134 bool script_error; 135 explains_stop = script_interp->ScriptedThreadPlanExplainsStop( 136 m_implementation_sp, event_ptr, script_error); 137 if (script_error) 138 SetPlanComplete(false); 139 } 140 } 141 return explains_stop; 142 } 143 144 bool ThreadPlanPython::MischiefManaged() { 145 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 146 if (log) 147 log->Printf("%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, 148 m_class_name.c_str()); 149 bool mischief_managed = true; 150 if (m_implementation_sp) { 151 // I don't really need mischief_managed, since it's simpler to just call 152 // SetPlanComplete in should_stop. 153 mischief_managed = IsPlanComplete(); 154 if (mischief_managed) 155 m_implementation_sp.reset(); 156 } 157 return mischief_managed; 158 } 159 160 lldb::StateType ThreadPlanPython::GetPlanRunState() { 161 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 162 if (log) 163 log->Printf("%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, 164 m_class_name.c_str()); 165 lldb::StateType run_state = eStateRunning; 166 if (m_implementation_sp) { 167 ScriptInterpreter *script_interp = m_thread.GetProcess() 168 ->GetTarget() 169 .GetDebugger() 170 .GetCommandInterpreter() 171 .GetScriptInterpreter(); 172 if (script_interp) { 173 bool script_error; 174 run_state = script_interp->ScriptedThreadPlanGetRunState( 175 m_implementation_sp, script_error); 176 } 177 } 178 return run_state; 179 } 180 181 // The ones below are not currently exported to Python. 182 183 bool ThreadPlanPython::StopOthers() { 184 // For now Python plans run all threads, but we should add some controls for 185 // this. 186 return false; 187 } 188 189 void ThreadPlanPython::GetDescription(Stream *s, lldb::DescriptionLevel level) { 190 s->Printf("Python thread plan implemented by class %s.", 191 m_class_name.c_str()); 192 } 193 194 bool ThreadPlanPython::WillStop() { 195 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 196 if (log) 197 log->Printf("%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, 198 m_class_name.c_str()); 199 return true; 200 } 201