1 //===-- ThreadPlanPython.cpp ----------------------------------------------===// 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 StructuredDataImpl *args_data) 30 : ThreadPlan(ThreadPlan::eKindPython, "Python based Thread Plan", thread, 31 eVoteNoOpinion, eVoteNoOpinion), 32 m_class_name(class_name), m_args_data(args_data), m_did_push(false), 33 m_stop_others(false) { 34 SetIsMasterPlan(true); 35 SetOkayToDiscard(true); 36 SetPrivate(false); 37 } 38 39 ThreadPlanPython::~ThreadPlanPython() { 40 // FIXME, do I need to decrement the ref count on this implementation object 41 // to make it go away? 42 } 43 44 bool ThreadPlanPython::ValidatePlan(Stream *error) { 45 if (!m_did_push) 46 return true; 47 48 if (!m_implementation_sp) { 49 if (error) 50 error->Printf("Error constructing Python ThreadPlan: %s", 51 m_error_str.empty() ? "<unknown error>" 52 : m_error_str.c_str()); 53 return false; 54 } 55 56 return true; 57 } 58 59 ScriptInterpreter *ThreadPlanPython::GetScriptInterpreter() { 60 return m_process.GetTarget().GetDebugger().GetScriptInterpreter(); 61 } 62 63 void ThreadPlanPython::DidPush() { 64 // We set up the script side in DidPush, so that it can push other plans in 65 // the constructor, and doesn't have to care about the details of DidPush. 66 m_did_push = true; 67 if (!m_class_name.empty()) { 68 ScriptInterpreter *script_interp = GetScriptInterpreter(); 69 if (script_interp) { 70 m_implementation_sp = script_interp->CreateScriptedThreadPlan( 71 m_class_name.c_str(), m_args_data, m_error_str, 72 this->shared_from_this()); 73 } 74 } 75 } 76 77 bool ThreadPlanPython::ShouldStop(Event *event_ptr) { 78 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 79 LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, 80 m_class_name.c_str()); 81 82 bool should_stop = true; 83 if (m_implementation_sp) { 84 ScriptInterpreter *script_interp = 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 LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, 99 m_class_name.c_str()); 100 101 bool is_stale = true; 102 if (m_implementation_sp) { 103 ScriptInterpreter *script_interp = GetScriptInterpreter(); 104 if (script_interp) { 105 bool script_error; 106 is_stale = script_interp->ScriptedThreadPlanIsStale(m_implementation_sp, 107 script_error); 108 if (script_error) 109 SetPlanComplete(false); 110 } 111 } 112 return is_stale; 113 } 114 115 bool ThreadPlanPython::DoPlanExplainsStop(Event *event_ptr) { 116 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 117 LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, 118 m_class_name.c_str()); 119 120 bool explains_stop = true; 121 if (m_implementation_sp) { 122 ScriptInterpreter *script_interp = GetScriptInterpreter(); 123 if (script_interp) { 124 bool script_error; 125 explains_stop = script_interp->ScriptedThreadPlanExplainsStop( 126 m_implementation_sp, event_ptr, script_error); 127 if (script_error) 128 SetPlanComplete(false); 129 } 130 } 131 return explains_stop; 132 } 133 134 bool ThreadPlanPython::MischiefManaged() { 135 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 136 LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, 137 m_class_name.c_str()); 138 bool mischief_managed = true; 139 if (m_implementation_sp) { 140 // I don't really need mischief_managed, since it's simpler to just call 141 // SetPlanComplete in should_stop. 142 mischief_managed = IsPlanComplete(); 143 if (mischief_managed) 144 m_implementation_sp.reset(); 145 } 146 return mischief_managed; 147 } 148 149 lldb::StateType ThreadPlanPython::GetPlanRunState() { 150 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 151 LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, 152 m_class_name.c_str()); 153 lldb::StateType run_state = eStateRunning; 154 if (m_implementation_sp) { 155 ScriptInterpreter *script_interp = GetScriptInterpreter(); 156 if (script_interp) { 157 bool script_error; 158 run_state = script_interp->ScriptedThreadPlanGetRunState( 159 m_implementation_sp, script_error); 160 } 161 } 162 return run_state; 163 } 164 165 // The ones below are not currently exported to Python. 166 void ThreadPlanPython::GetDescription(Stream *s, lldb::DescriptionLevel level) { 167 s->Printf("Python thread plan implemented by class %s.", 168 m_class_name.c_str()); 169 } 170 171 bool ThreadPlanPython::WillStop() { 172 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 173 LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, 174 m_class_name.c_str()); 175 return true; 176 } 177