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